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 RequireJSKarma 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
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 :
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.
Run
npm init
from the root folder of the web app, follow the sample below...
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)
Alternatively manually create package.json as follows...
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.
We need to set up our RequireJS bootstrap...
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!");
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
.
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 fortest-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.
Create a subfolder
test/app
and create spec filestartup.spec.js
.
Karma's watcher will pick this spec up automatically and execute it
Two errors you can get pretty easily through misconfiguration are :
There is no timestamp for /base/src/someScript.js
Mismatched anonymous define() module: ...
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!'
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'
]
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: jasmine, karma, requirejs, test driver, testing, web app