Skip to content

Instantly share code, notes, and snippets.

@acthp
Created August 31, 2012 19:14
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save acthp/3557646 to your computer and use it in GitHub Desktop.
Save acthp/3557646 to your computer and use it in GitHub Desktop.
requirejs (AMD) loader plugin for jstestdriver
(function() {
var loadSource = function(file, onSourceLoad) {
if (!file.fileSrc.match(/js-test/)) {
return false;
}
require([file.fileSrc], function() {
onSourceLoad({file: file, success: true, message: ''});
}, function(err) {
var msg = err.requireType;
if (err.requireModules) {
msg += ": " + err.requireModules.join(', ');
}
onSourceLoad({file: file, success: false, message: msg});
});
return true;
};
jstestdriver.pluginRegistrar.register({
name: 'AMDLoaderPlugin',
loadSource: loadSource
});
}());
@acthp
Copy link
Author

acthp commented Sep 1, 2012

This will allow jstestdriver to load anonymous AMD modules, such as those supported by requirejs. It does not require you to run the optimizer, give the modules names, monkey-patch define(), or preload the modules. The plugin works by delegating loading of test modules to requirejs.

Include this file in the 'load' section of the jstd config file (along with require.js and a config file for require.js).

load:
 - AMDLoaderPlugin.js
 - require.js
 - requirejs-config.js

test:
 - js-test/*.js

Change the pattern in the file.fileSrc.match() as necessary so it only matches test files that are requirejs modules. It would be nice if we could keep this pattern in the jstd config file, but I haven't found an easy way to pass config to the plugin.

Test modules should be declared with define(), not require().

define(['jquery', 'mymodule'], function($, mymodule) {
   TestCase('test something', /* blah blah */ );
});

Theory of operation

AMD is a problem in jstd because it starts running the test suite before the test dependencies are loaded. Jstd will make an async call to load a test script. When the script is loaded, the onSourceLoad callback fires, starting the tests. If the script makes a require() or define() call, those calls will not have completed when the testing starts.

At first glance preloading modules looks like a workable solution, because then the require() call will return immediately, instead of causing an asynchronous fetch. However it merely introduces a race condition, because jstd has no way of waiting for the preloading to finish. I you add deps: ['main'] to your requirejs config, requirejs will start loading your modules at the same time that jstd starts loading your test scripts. Whether it works depends on which loads first.

The solution is to not invoke the onSourceLoad for a test module until all of its dependencies are also loaded. This is very easy to do with requirejs.

@acthp
Copy link
Author

acthp commented Sep 6, 2012

Important safety tip: the first time jstd loads source, it does not use the loadSource plugin. I'm not sure how to coerce it to load and activate the plugin before loading other source. To activate it, always use the '--reset' flag when running tests.

@osmestad
Copy link

Great work! Finally a solution for testing AMD modules with dependancies! One comment, shouldn´t this plugin be loaded after require.js (in the jstd config file)? I had to move it after to get it working.

@blittle
Copy link

blittle commented Oct 16, 2012

acthp, I am trying to get this working and am running into problems where it doesn't seem as though the plugin gets loaded. What do you mean by, the first time jstd loads source, it doesn't use the loadSource plugin? Does the reset flag need to be on the server and client instance of jstd?

@quannguyen81
Copy link

Hi acthp,

Do you have a working example that you could share? It seems like I am missing some key configurations here and there. It would be very helpful if you could help.

Thanks a lot in advance!

@mattnworb
Copy link

The easiest workaround I've found for this is to just put explicit module names inside each of my define() calls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment