This blog post has moved to blog.stvjam.es

You should be redirected shortly, alternatively please click the following link

Lab: A beginners guide to starting a new web app with Karma, Jasmine and RequireJS

Karma test runner is a really simple and relatively easy way to run JavaScript across multiple browsers, automatically test code changes (using watchers) and it also integrates neatly into task runners like Grunt, so it can be chained nicely into a Lint>Build>Test>Distribute type of process. Coupled with this, it really plays well with RequireJS...

The only problem is, when things go wrong with misconfiguration you can run into errors like :

There is no timestamp for /base/src/someScript.js

or

Mismatched anonymous define() module: ...

So the first time you're setting it up, it helps to understand those errors and how to patch them up and also to know the sequence of configs and package installations to get off the ground. If you're just interested in those errors see Troubleshooting.

In this lab I'll walk through (in fairly painful detail!) setting up a web app and all the scaffolding required. Each step has been committed to a git repository for reference, so after initial setup you can advance through the lab manually (recommended!) or use git to checkout each step. view steps on github

Step 0 - Prerequisites and Initial Setup

This lab assumes you have the following installed

To get started with the lab, clone the repository and checkout step 0 - basic structure...

In your dev folder, run the following

git clone https://github.com/stephen-james/lab-karma-require-jasmine.git

Change directory to the cloned repo

cd lab-karma-require-jasmine

And checkout the starting point of this lab, step 0...

git checkout step0

While everyone has their own preferred folder structure for web apps, for the purposes of this lab we'll be using the following basic structure :

Step 1 - Initialising the Web Application as an npm package

Its typical in a web app that we'll have quite a few dependencies, but we don't want to commit these to our repository. Its way cleaner to use a package manager that stores a list of dependencies and to exclude them explicitly using a .gitignore file.

For this lab, we'll be using npm as the package manager. So we should create a .gitignore file to ignore any dependencies it loads in node_modules

Create .gitignore

Next up we'll create the package.json file for this project using npm. While we'd never want to actually publish this sample app on npm, this will help us describe the project and in future steps will also list dependencies. more information on package.json

You can follow along through the npm init wizard, or alternatively just create the package.json manually.

Using npm init

Run npm init from the root folder of the web app, follow the sample below...

Sample : using npm init from comand line

C:\dev\lab-karma-require-jasmine

>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (lab-karma-require-jasmine)
version: (0.0.0)
description: A step-by-step lab for setting up a simple JavaScript centric web a
pp using RequireJS, Karma and Jasmine
entry point: (index.js) index.html
test command:
git repository: (https://github.com/stephen-james/lab-karma-require-jasmine.git)

keywords: lab, jasmine, require, requirejs, karma
author: Stephen James
license: (ISC) MIT
About to write to C:\dev\lab-karma-require-jasmine\package.json 

...

Is this ok? (yes)

package.json

Alternatively manually create package.json as follows...

Step 2 - Setting up RequireJS and the browser default page

To keep our JavaScript nice and modular and manageable we're going to use RequireJS.

Install RequireJS as a dependency of the web app and save the dependency meta info in the package.json file.

npm install requirejs --save

Now in the root folder of the web app, we're going to edit index.html to include a script reference to RequireJS.

Add the following script tag at the bottom of the <body>

<script src="node_modules/requirejs/require.js" data-main="src/main.js"></script>

Our index.html now looks like this

We're referencing RequireJS in the location that npm has installed it for us and telling Require that it should bootstrap the app by running src/main.js

If we were to run the web app now, we'd get a 404 because src/main.js doesn't exist yet and RequireJS would throw a Script error.

 photo lab-karma-console_error_zpsc27bb087.jpg

We need to set up our RequireJS bootstrap...

Step 3 - Setting up the RequireJS bootstrap and App entry point

In the /src folder we're going to create two files, main.js and app.js. main.js will contain the JavaScript module configuration for RequireJS and app.js will be the real entry point to the web app, which will be fired up once RequireJS has performed it's magic.

Install jQuery, it'll serve as an example dependency for our app

npm install jquery --save

Create src/app.js and src/main.js

In main.js, we're configuring RequireJS, telling it where to find jQuery and that once it's configured the modules it should launch our app, by calling app.start()

If we point a browser to index.html we should now see the simple message that the app has started up, coming from app.js

this.target.html("App Started!");

 photo lab-karma-app-started_zps8eada00b.jpg

Step 4 - Getting some Karma!

Now that the initial strawman is there for our web app, lets get that test runner going and start putting in some test specs!

We need to install karma as a development dependency of the application

npm install karma --save-dev

To run the karma client from the command line, we must install it globally

npm install karma-cli -g

Karma requires a karma.conf.js configuration file, which we can write to a file manually or create using the console 'wizard' by running karma init.

Using the Karma init console wizard

Run the following from the command line

karma init

selecting the following values :

C:\dev\lab-karma-require-jasmine

>karma init

Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> jasmine

Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> yes

Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next quest
ion.
> PhantomJS
> Chrome
>

What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> node_modules/jquery/dist/jquery.js
> src/*.js
> test/**/*.spec.js
WARN [init]: There is no file matching this pattern.

>

Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
> src/main.js
>

Do you wanna generate a bootstrap file for RequireJS?
This will generate test-main.js/coffee that configures RequireJS and starts the
tests.
> yes

Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> yes


RequireJS bootstrap file generated at "C:\dev\lab-karma-require-jasmine\test-mai
n.js".

Config file generated at "C:\dev\lab-karma-require-jasmine\karma.conf.js".


C:\dev\lab-karma-require-jasmine

>

Ignore the warnings about non-matching files, provided you got the paths right that just means that those paths don't contain any test specs yet.

Karma has now created a config file which describes how we want to Karma to perform karma.conf.js and an entry point for RequireJS (for Karma, not our app) test-main.js. To keep things clean, move the RequireJS entry point/bootstrap file to the test folder so that our structure now looks like this :

/node_modules
    /jquery
    /karma
    /karma-...
    /...
    /requirejs

/src
    app.js
    main.js

/test
    test-main.js

karma.conf.js
package.json    

Edit karma.conf.js to look for test-main.js in the test folder.

files: [
  'test/test-main.js',
  ...
]

Edit test/test-main.js to look like the following

We're changing a couple of values from the boilerplate template, setting the baseUrl to be /base/src so that dependency definitions are consistent between main.js and test-main.js and adding paths for jQuery and ensuring that the test folder has a relative mapping.

Start Karma up from the command line

karma start

Because we chose to have Chrome and PhantomJS as browsers for testing, the testrunner will show feedback in both the command line and a launched Chrome instance.

 photo lab-karma-chrome-test-runner_zps6a30c1f9.jpg

 photo lab-karma-console-no-specs_zps1446bd8b.jpg

Step 5 - Creating a Spec

Create a subfolder test/app and create spec file startup.spec.js.

Karma's watcher will pick this spec up automatically and execute it

 photo lab-karma-console-with-specs_zpscbd4be51.jpg

Troubleshooting

Two errors you can get pretty easily through misconfiguration are :

No Timestamp Errors

This indicates that Karma doesn't have that file in it's file list. All files need to be included in this list, the app files, library files / dependencies and test specs too. If a file is missing from this list, Karma will put up a warning for that particular file.

So in our sample app, if we modified our filelist in karma.conf.js from :

files: [
  'test/test-main.js',
  { pattern: 'node_modules/jquery/dist/jquery.js', included: false },
  { pattern: 'src/*.js', included: false },
  { pattern: 'test/**/*.spec.js', included: false }
]

to this (removing the jquery reference):

files: [
  'test/test-main.js',
  { pattern: 'src/*.js', included: false },
  { pattern: 'test/**/*.spec.js', included: false }
]

Karma's web server won't serve the file and we'll get error output similar to :

WARN [web-server]: 404: /base/node_modules/jquery/dist/jquery.js
PhantomJS 1.9.7 (Windows 7) ERROR: 'There is no timestamp for /base/node_modules
/jquery/dist/jquery.js!'

Mismatched anonymous define() module

Again this is an issue with karma.confg.js, when we're using RequireJS with Karma we must make sure that any files that will be required as dependencies from the test specs are included in the file list with the included: false option. This will make sure that the script is not loaded twice (which causes the mismatch).

// list of files / patterns to load in the browser
files: [
  'test/test-main.js',
  { pattern: 'node_modules/jquery/dist/jquery.js', included: false },
  { pattern: 'src/*.js', included: false },
  { pattern: 'test/**/*.spec.js', included: false }
]

If you want to see this in action, we can simulate this problem by switching included:true on src/*.js using the lab files for an example.

Another thing to ensure is that the Application's RequireJS bootstrap main.js is in the exclude setting.

// list of files to exclude
exclude: [
  'src/main.js'
]

Using Jasmine 2.0 with Karma

At the time of writing this, Karma installed Jasmine 1.3.1 by default, if you want to use version 2.0 of Jasmine, make sure you specify the Karma version to be 0.2.0 or higher... more info on Karma with Jasmine 2.0 here

Labels: , , , , ,