Esri Karma Tutorial
NOTE: I now consider the techniques shown in this tutorial as an anti-pattern. Specifically, I think that you should avoid using the ArcGIS API or Dojo to load your application code and especially your test code. Instead, try using something like esri-loader to lazy-load the ArcGIS API only when you need it. Then you can test your application code the way you normally would with Karma or whatever framework you like by mocking esri-laoder's
loadModules()
or your own modules that wrap it. If you are unable to use esri-loader, or you are maintainging a legacy Dojo 1 application, then you should probably just use Intern.
If you're building web mapping apps using the ArcGIS API for JavaScript, and need a way to automate running your unit tests, this tutorial will show you how using the Karma test runner and Jasmine BDD-style testing framework.
If you (don't already know and) want to know why Karma is so awesome, I suggest watching this video, starting at the point where the first tests are run:
http://youtu.be/MVw8N3hTfCI?t=3m44s
In a nut shell, Karma:
- is easy to intall and configure w/ NPM
- serves up your app and test files in a local web server, which includes a reverse-proxy to prevent cross-origin requests
- launches one or more browsers pointing to above web server and runs your tests
- watches for changes in your source and test files and re-runs all your tests as soon as you save a file
- works with most popular testing frameworks (Jasmine, Mocha, Qunit)
- works with AMD (Require.js and Dojo) code
- can generage code coverage reports and much more via plugins
This tutorial demonstrates the configuration settings to get Karma running Jasmine BDD-style tests on code that relies on the ArcGIS API for JavaScript.
Jasmine is a popular and simple BDD-style JavaScript testing framework. Details on using Jasmine can be found at the Jasmine Wiki.
NOTE: The current release of this tutorial runs on Jasmine 2.0 and uses done()
style async testing. If you want to use this tutorial with existing specs written for Jasmine 1.x (i.e. using the deprecated runs()
and waitsFor()
async syntax), you can check out the v0.1.0 release of this tutorial.
Running the Tests
- Clone the repo:
git clone https://github.com/tomwayson/esri-karma-tutorial
- Go to local copy of repo:
cd esri-karma-tutorial
- Install Node (if not already installed) from http://nodejs.org/
- Install Karma (if not already installed)
npm install karma-cli -g
- Install development dependencies (Karma plugins for Jasmine, Dojo, browsers, etc):
npm install
- Run my tests:
karma start karma.conf.js
or justkarma start
- Add your own specs and code under
/spec
and/src
and let karma run your tests for you!
Tutorial
This tutorial walks you through configuring Karma to use additional plugins to run tests in additional browsers, use spies and fakes, generate code coverage reports, and integrate with generic task runners like Grunt.
To view the completed tutorial, run the following at the command line:
git checkout completed-tutorial
npm install
Testing in Additional Browsers
Testing in additional browsers with Karma is a breeze. For each browser you want to test in you simply:
- Install the browser launcher*
- Add the browser name in the
browsers
section
For example, to run tests in FireFox as well as Chrome:
npm install karma-firefox-launcher --save-dev
After insalling the plugin, update the browsers
section of karma.conf.js
:
browsers: ['Chrome', 'Firefox'],
Re-run Karma and you should see your tests run in both Chrome and Firefox.
*Note that you may need to first set the path to the browser's executable in an environment vairable.
set FIREFOX_BIN="c:\Program Files (x86)\Mozilla Firefox\firefox.exe"
See the Browsers page of the Karma documentation for more information.
Testing in Internet Explorer and Emulating Older Versions
If you are unlucky enough to have to support Internet Explorer, especially older versions, then you will want to run you tests in those environments as well.
To run tests in Internet Explorer:
npm install karma-ie-launcher --save-dev
After insalling the plugin, update the browsers
section of karma.conf.js
:
browsers: ['Chrome', 'IE'],
Re-run Karma and you should see your tests run in both Chrome and Internet Explorer.
Karma can also launch Internet Explorer in emulation mode to simulate running tests in older versions of Internet Explorer. To do that, add the following section to karma.conf.js
:
// custom browser configurations
// to emulate older versions of IE
customLaunchers: {
// emulate IE8
IE8: {
base: 'IE',
'x-ua-compatible': 'IE=EmulateIE8'
},
// emulate IE9
IE9: {
base: 'IE',
'x-ua-compatible': 'IE=EmulateIE9'
},
// emulate IE10
IE10: {
base: 'IE',
'x-ua-compatible': 'IE=EmulateIE10'
}
},
Then update the browsers
section of karma.conf.js
with the versions you want to test in:
browsers: ['Chrome', 'IE', 'IE10', 'IE9', 'IE8'],
Re-run Karma and you should see your tests run in both Chrome and all the versions of Internet Explorer that you specified.
See the Karma IE launcher documentation for more information.
Going Headless with PhantomJS
If you prefer to not have Karma spawn several browser windows while you are coding you can have Karma run your tests in a "headless" browser such as PhantomJS.
npm install karma-phantomjs-launcher --save-dev
After insalling the plugin, update the browsers
and plugins
sections of karma.conf.js
:
browsers: ['PhantomJS'],
Re-run Karma and you should see your tests run in PhantomJS.
See the Browsers page of the Karma documentation for more information.
Spies, Fakes, and Mocks
You can use spies, fakes, and mocks from Sinon.js in your tests by installing the karma-sinon plugin:
npm install karma-sinon --save-dev
After insalling the plugin, add 'sinon'
to the list of frameworks
in karma.conf.js
as follows:
frameworks: ['jasmine', 'dojo', 'sinon'],
For an example of how to use Sinon.js's fake server to test code that generates an XHR request without actually makeing the XHR request, add the following test suite to specs/imageServiceUtilsSpec.js
:
describe('item info tests', function() {
var server;
beforeEach(function() {
server = sinon.fakeServer.create();
});
afterEach(function() {
server.restore();
});
it('should request item info', function(done) {
var imageServiceUrl = '/not/a/real/url/ImageServer';
// var imageServiceUrl = 'http://imagery.arcgisonline.com/arcgis/rest/services/LandsatGLS/GLS2010_Enhanced/ImageServer';
var dummyResponse = {
result: 'success'
};
// hijack any HTTP requests to item info end point
server.respondWith('GET',
imageServiceUrl + '/info/iteminfo?f=json',
[200, { 'Content-Type': 'application/json' }, JSON.stringify(dummyResponse) ]);
// call get item info and have fake server respond
imageServiceUtils.getItemInfo(imageServiceUrl).then(function(response) {
// success
expect(response).toEqual(dummyResponse);
done();
}, function(err) {
expect(err).toBeNull(null);
done();
});
// respond to any matching request
server.respond();
});
});
See the Sinon.js documentation for more ways to use Sinon to help you spy on or fake your modules' dependencies.
Code Coverage
You can get Istanbul code coverage reports for your tests by installing the karma-coverage plugin:
npm install karma-coverage --save-dev
After insalling the plugin, uncomment the coverage related lines in the preprocessors
, reporters
, and coverageReporter
, sections of karma.conf.js
and run karma.
See the karma-coverage plugin README for more information.
Calling Karma from Grunt
Often you'll want to run your tests as part of some workflow (like a build). Futhermore, in that workflow, you may want to override your default test configuration settings, such as which browsers to use, or to only run the tests once. The steps below show how to use Grunt to run tests using Karma's default configuration from above with the exception that the tests will only run one time.
If you don't already have the Grunt CLI installed globally, run this:
npm install -g grunt-cli
Then install a local grunt and the karma plugin for grunt in this repo:
npm install grunt --save-dev
npm install grunt-karma --save-dev
Then add gruntfile.js
at the repo's root folder with the following configuration:
module.exports = function(grunt) {
grunt.initConfig({
karma: {
// common options for all targets
options: {
// use Karma's defaults
configFile: 'karma.conf.js'
},
// options for the build target
build: {
// test in real browsers once beofre build
browsers: ['Chrome', 'Firefox'],
singleRun: true
}
}
});
grunt.loadNpmTasks('grunt-karma');
grunt.registerTask('default', ['karma']);
};
Finally run Karma from Grunt with:
grunt karma
Another common scenario is when you want to use Grunt's watch task to listen for file changes and then run the tests in Karma as a step (i.e. after jshint). In this case you'd add another target (i.e. dev
) above and configure it to run karma in background mode and have a watch target run the tests.
See the Grunt and grunt-karma documentaion for more information.
Other Test Frameworks
This repo shows you how to use Karma to run unit tests using the Jasmine test framework, but Karma can be used with other test frameworks. For an example of how to use Karma to run Mocha tests with the ArcGIS API for JavaScript, see:
https://github.com/Esri/landscape-modeler-js
How It Works
This tutorial relies on the karma-dojo plugin which enables testing of AMD style Dojo code.
After insalling and configuring the plug in, the trick is to set the dojoConfig
in main.js to use the ArcGIS API for JavaScript for the Dojo and Esri packages as follows:
window.dojoConfig = {
packages: [
// local pacakges to test
{
name:"esri-utils",
location:"/base/src/esri-utils"
},
// esri/dojo packages
{
name: 'dgrid',
location: 'http://js.arcgis.com/3.20/dgrid'
}, {
name: 'dijit',
location: 'http://js.arcgis.com/3.20/dijit'
}, {
name: 'esri',
location: 'http://js.arcgis.com/3.20/esri'
}, {
name: 'dojo',
location: 'http://js.arcgis.com/3.20/dojo'
}, {
name: 'dojox',
location: 'http://js.arcgis.com/3.20/dojox'
}, {
name: 'put-selector',
location: 'http://js.arcgis.com/3.20/put-selector'
}, {
name: 'util',
location: 'http://js.arcgis.com/3.20/util'
}, {
name: 'xstyle',
location: 'http://js.arcgis.com/3.20/xstyle'
}, {
name: 'moment',
location: 'http://js.arcgis.com/3.20/moment',
}
],
async: true
};
Requirements
Dependencies
- ArcGIS API for JavaScript: built/tested on v3.20 and updated to latest; may work w/ earlier versions.
And the latest versions of:
Resources
- ArcGIS for JavaScript API
- Karma
- Configuring karma-dojo
- Jasmine
- [Jasmine Wiki] (https://github.com/jasmine/jasmine/wiki)
- Node
- ArcGIS for Developers
- ArcGIS REST Services
- @esri
- Sinon.js
Issues
Find a bug or want to request a new feature? Please let us know by submitting an issue.
Contributing
Please do! See CONTRIBUTING.md
Credit
Largely inspired by:
- The blog post by Dave Bouwman on Automated Headless Unit Tests with Esri JS API using Jasmine, Grunt, and PhantomJS
- The tutorial by David Spriggs on using the intern with the ArcGIS API for JavaScript repo
- Scott Davis and Rene Rubalcava who graciously share their outstanding ideas and code
Licensing
Copyright 2013 Tom Wayson
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
A copy of the license is available in the repository's license.txt file.
[](Esri Tags: ArcGIS Unit Testing Jasmine Karma) [](Esri Language: JavaScript)