I would like to use mocha (the node.js test framework, not the ruby mocking library) as a library, rather than using the mocha executable to run my test.
Is it possible to run a mocha test this way? The examples all just call mocha libraries assuming they are already "require'd", and the mocha executable does all the "require-ing" ahead of time, but I would really prefer to do them explicitly in my script so that I can simply set +x on my script and call it directly.
Can I do something like this?
#!/usr/bin/env coffee
mocha = require 'mocha'
test = mocha.Test
suite = mocha.Suite
assert = require("chai").assert
thing = null
suite "Logging", () ->
setup (done) ->
thing = new Thing()
done()
test "the thing does a thing.", (done) ->
thing.doThing () ->
assert.equal thing.numThingsDone, 1
done()
teardown (done) ->
thing = null
done()
It's possible, but certainly not recommended.
Look at the mocha binary's source (specifically bin/_mocha
) to get an idea of what it does. In particular, look at the run
function. Everything it's using—Runner
, Reporter
, etc.—is exported by the mocha library, so there's nothing stopping you from reverse-engineering it.
This feature has since been added. I include an example below.
I got information from here:
You will need 2 files. One test, and one to run the test. You can mark runTest as executable, and set its output in the mocha options.
runTest.js
#!/usr/bin/env node
var Mocha = require('mocha'),
fs = require('fs'),
path = require('path');
var mocha = new Mocha(
{
ui: 'tdd'
});
mocha.addFile(
path.join(__dirname, 'test.js')
);
mocha.run(function(failures){
process.on('exit', function () {
process.exit(failures);
});
});
test.js
var assert = require('chai').assert
suite('Array', function(){
setup(function(){});
suite('#indexOf()', function(){
test('should return -1 when not present', function(){
assert.equal(-1, [1,2,3].indexOf(4));
});
});
});
The following snippet allows you to control programmatically Mocha main features outside of Node, like adding suites and run suites in different steps. The crucial point was finding out how to make mocha interfaces globally accessible (the code is also available as a gist)
var Mocha = require("mocha");
var mocha = new Mocha();
var _suites = [];
var _done = false;
/**
* default mocha options
* for other configurations, check out bin/_mocha
*/
mocha.reporter("nyan");
mocha.useColors(true);
mocha.growl();
module.exports = {
/**
* set interface (bdd is default) and make it global to node
* @param {string} interface bdd|tdd|exports|qunit
*/
init: function(interface) {
interface && mocha.ui(interface);
mocha.suite.emit('pre-require', global, undefined, mocha);
},
/**
* add suite
* @param {function} suite to be executed later
*/
add: function(suite) {
mocha.suite && _suites.push(suite) && suite();
},
/**
* run added suites
*/
run: function(cb) {
console.info('run mocha');
var done = function () {
_done = true;
cb && cb();
process.on('exit', function() {
console.info("exit mocha");
process.exit(1);
});
};
mocha.run(done);
},
/**
* end mocha test
*/
exit: function() {
if (_done) {
process.exit();
} else {
var start = new Date().getTime(),
interval = setInterval(function() {
if (_done) {
console.log("test suites finished");
clearInterval(interval);
process.exit();
} else if (new Date().getTime() - start > 5000) {
console.log("wait for nothing!");
clearInterval(interval);
process.exit();
}
}, 250);
}
},
/**
* change mocha options at runtime, e.g., "reporter", "nyan"
*/
_set: function(key, val){
mocha[property](val);
}
};