Testing Modules with ModuleTest
ModuleTest can setup a testing environment for modules, enabling them to be tested with a minimal standalone server.
Testing is based on Express and Mocha.
Testing is still run via the standard Mocha command. In a folder run by Mocha, use your standard setup. Our example uses Chai and should.
Once the testing environment is ready, include the ModuleTest class to setup a testing environment.
var chai = require("chai");
var should = chai.should();
var ModuleTest = require("@codelenny/module-server");
// ModuleTest.DEBUG = yes
Various methods inside ModuleTest configure the test definition. All methods mentioned in this document chain (like jQuery).
The idea is that we will create a test description section in the constructor, then load a module in a virtual browser. Once client-side, we will initialize the module and collect data that we can test back on the server, to collect all data in a single Mocha run.
The constructor takes in a name to pass to
Mocha's describe
function.
var test = new ModuleTest("My Module");
test.load() loads modules via
ModuleServer.load(). You must load your own module,
which will also include modules listed in package.json
.
test.load("MyModule", "../");
A generic webpage will be created, including the RequireJS script to load your test. To specify additional contents to include in the body before the script tag, you can include raw HTML via test.html(), or preprocessed code. Blade code can be added via test.blade().
test.html('<div id="module-target"></div>');
test.blade("#module-target");
You can load RequireJS-based code to run on the webpage to fetch
data that should be tested. Paths loaded via test.load()
will already be initialized.
Code can be provided as raw JavaScript via test.js()
or as CoffeeScript via test.coffee().
To take advantage of test response features, require the TestResponse
module, which is
available by default.
Your test can be written in JavaScript, but this example uses CoffeeScript to take advantage of multi-line strings.
test.js("""
require(["MyModule", "TestResponse"], function(MyModule, TestResponse){
// ...
});
""");
test.coffee """
require ["MyModule", "TestResponse"], (MyModule, TestResponse) ->
# ...
"""
Inside the client-side code, the TestResponse class provides methods to send data to tests (discussed next).
Use the class method TestResponse.emit() to send
data to the tests. emit
takes a handler (discussed below), followed by one or more data
parameters to send to the client.
TestResponse.emit("divCount", $("#module-target").length);
TestResponse.emit("module", typeof MyModule, typeof MyModule.INIT);
Two syntaxes for test definitions are available: test.onit() and test.on().it().
Both test data that is generated from the client side and sent via a TestResponse.emit
.
Provide a name to call the it
block by, a URL segment (handler) to identify client side
data by, an optional timeout, and a callback to run testing with.
Each onit
definition needs one and only one emit
from the client side.
After the first value to emit
, all subsequent values emit
ed to the same handler are ignored.
test.onit("has one target div", "divCount", function(count) {
count.should.equal(1);
});
Example using timeouts, written in CoffeeScript.
test.onit "loads MyModule", "module", 50000, (MyModule, INIT) ->
should.exist MyModule
MyModule.should.equal "function"
should.exist INIT
INIT.should.equal "function"
Provide a handler to listen to via test.on(), then
define the test to run after receiving data to that handler, giving it the name to call
a Mocha it
block, an optional timeout, and a callback function.
test
.on("divCount")
.it("has one target div", function(count) {
count.should.equal(1);
})
.on("module")
.it("loads MyModule", 50000, function(MyModule, INIT) {
should.exist(MyModule);
should.exist(INIT);
MyModule.should.equal("function");
INIT.should.equal("function");
})
Once all test definitions and responses have been written, call test.run() to run the test.
Run takes an optional integer to define the number of times the test should be executed, to ensure that all tests are stable.
If only run once, a describe
block is created with the name given to the constructor.
Otherwise, a describe block is created for each run, with (run x/y)
appended to the name.
test.run(5);
You can optionally use an environment variable to determine if a larger number of runs should be triggered, to shorten testing incremental changes, but occasionally fully testing components.
CoffeeScript included for compactness.
test.run (if process.env.FULLTEST then 20 else 2)
If tests are failing, test.chrome() will start a
copy of the testing server in parellel to the tests being run, and open a new chrome-browser
tab with the same HTML and JavaScript content defined as specified the test.
At the same time as running a chrome test, the normal execution of tests can still occur.
Comment out test.run
or set the value to 0 to prevent the tests from running
in the background.
test.run(0);
test.chrome();
By default, test.chrome()
will run for 10 seconds. Pass an alternative timeout (in ms)
to test.chrome()
. Alternatively, passing 0
will keep the server alive until the page
is closed (but will remain online for page reload).