I first want to say that I am new to RequireJS and even newer to Jasmine.
I am having some issues with the SpecRunner and require JS. I have been following the tut
Another option for Jasmine 2.0 standalone is creating a boot.js file and setting it up to run your tests after all of your AMD modules have been loaded.
The ideal end user case for writing tests in our case was to not have to list out all of our spec files or dependencies in once explicit list, and only have the requirement of declaring your *spec files as AMD modules with dependencies.
Example ideal spec: spec/javascript/sampleController_spec.js
require(['app/controllers/SampleController'], function(SampleController) {
describe('SampleController', function() {
it('should construct an instance of a SampleController', function() {
expect(new SampleController() instanceof SampleController).toBeTruthy();
});
});
});
Ideally the background behaviour of loading the dependency in and running the specs would be totally opaque to anyone coming on to the project wanting to write tests, and they won't need to do anything other than create a *spec.js file with AMD dependencies.
To get this all working, we created a boot file and configured Jasmine to use it (http://jasmine.github.io/2.0/boot.html), and added some magic to wrap around require to temporarily delay running tests until after we have our deps loaded:
Our boot.js' "Execution" section:
/**
* ## Execution
*
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
*/
var currentWindowOnload = window.onload;
// Stack of AMD spec definitions
var specDefinitions = [];
// Store a ref to the current require function
window.oldRequire = require;
// Shim in our Jasmine spec require helper, which will queue up all of the definitions to be loaded in later.
require = function(deps, specCallback){
//push any module defined using require([deps], callback) onto the specDefinitions stack.
specDefinitions.push({ 'deps' : deps, 'specCallback' : specCallback });
};
//
window.onload = function() {
// Restore original require functionality
window.require = oldRequire;
// Keep a ref to Jasmine context for when we execute later
var context = this,
requireCalls = 0, // counter of (successful) require callbacks
specCount = specDefinitions.length; // # of AMD specs we're expecting to load
// func to execute the AMD callbacks for our test specs once requireJS has finished loading our deps
function execSpecDefinitions() {
//exec the callback of our AMD defined test spec, passing in the returned modules.
this.specCallback.apply(context, arguments);
requireCalls++; // inc our counter for successful AMD callbacks.
if(requireCalls === specCount){
//do the normal Jamsine HTML reporter initialization
htmlReporter.initialize.call(context);
//execute our Jasmine Env, now that all of our dependencies are loaded and our specs are defined.
env.execute.call(context);
}
}
var specDefinition;
// iterate through all of our AMD specs and call require with our spec execution callback
for (var i = specDefinitions.length - 1; i >= 0; i--) {
require(specDefinitions[i].deps, execSpecDefinitions.bind(specDefinitions[i]));
}
//keep original onload in case we set one in the HTML
if (currentWindowOnload) {
currentWindowOnload();
}
};
We basically keep our AMD syntax specs in a stack, pop them off, require the modules, execute the callback with our assertions in it, then run Jasmine once everything is done loading in.
This set up allows us to wait until all of the AMD modules required by our individual tests are loaded, and doesn't break AMD patterns by creating globals. There's a little hackery in the fact that we temporarily override require, and only load our app code using require (our `src_dir: in jasmine.yml is empty), but the overall goal here is to reduce the overhead of writing a spec.