A method for mocking AMD dependencies when testing JavaScript modules that are loaded with the Dojo AMD loader.
Inspired by this stackoverflow question and testr.
Open tests/spec/SpecHello.js for a demo.
When testing AMD modules it is sometimes necessary to verify how it interacts with it's dependencies. For example, you might be writing a module that makes XHR requests using dojo/request
and you want to make sure that it's passing the correct parameters. How would you test this? Creating a wrapper around the request
method in your module and then spying on that method would work. You could also store the request
method as a property of your module and spy on that in your tests. However, both of these solutions lead to messy code and there's something that feels wrong to me when adding code to production modules just for testing purposes.
You might think that it would be as easy as adding a map
config to the Dojo loader and pointing dojo/request
to a mocked module. While this is a possible solution it means that you have to create a separate file for each mock that you use and it gets very messy if you want to mock the same module multiple times within a single test page (since modules are cached by the loader).
StubModule.js provides a cleaner way to solve this problem. It allows you to stub modules with no dependencies on external files and no side effects to pollute your other tests. It does this by using the map config mentioned above as well as require.undef
which is a Dojo-specific method that removes a module from the cache.
Using this tool is fairly straight forward. stub-module.js
returns a single method that accepts two parameters. The first is the module identifier (MID) of the module that you want to test. The second is an object with keys that are MID's of the dependencies that you want to mock and values that are the mocked returned values. The method returns a promise that resolves with the stubbed module. For example (using Jasmine):
it('this is a demo', function (done) {
var stub = jasmine.createSpy('request');
stubModule('test/Module', {'dojo/request': stub}).then(function (StubbedModule) {
var testObject = new StubbedModule();
testObject.makeRequest();
expect(stub).toHaveBeenCalledWith('some/url');
done();
});
});
Run bower install
and npm install
before running the tests. Run the tests by running grunt travis
.
This code uses require.undef which is not turned on by default in the Dojo loader. You can enable it by adding this has property to your dojo config:
window.dojoConfig = {
has: {
'dojo-undef-api': true
}
};
This will not work for the ESRI JSAPI prior to version 3.4. However, at 3.4 they turned on the dojo-undef-api
has tag and it works great!