Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9d0f841
closes #98 implemented child block detection
kof Oct 2, 2014
f57e0db
inc maxBlockDuration
kof Oct 4, 2014
7065bb8
#105 forward argv to the child
kof Oct 7, 2014
95ccdc7
Update package.json
olegabr Dec 23, 2014
1f21d7f
Update readme.md
olegabr Dec 23, 2014
57754a6
Update readme.md
olegabr Dec 23, 2014
6f12107
Update package.json
olegabr Dec 23, 2014
7307e8e
Update package.json
olegabr Dec 23, 2014
bc39c6e
Update package.json
olegabr Dec 23, 2014
e09abae
Merge pull request #111 from olegabr/master
kof Dec 23, 2014
c926ea0
Default reporters lcov, json with a way to specify it from runner
hakubo Dec 30, 2014
d16a2c2
Update readme.md
hakubo Jan 6, 2015
020b464
Merge pull request #115 from hakubo/Accept-coverage.reporters
kof Jan 8, 2015
4fb32b6
Test on nodejs 0.12
nikolas Apr 9, 2015
775b4e6
Merge pull request #122 from nikolas/patch-1
kof Apr 9, 2015
49c1ca8
add node < 0.13 support, bump the version
kof Apr 13, 2015
8d85583
Add node v4 support
edi9999 Sep 26, 2015
ec60b79
Merge pull request #124 from edi9999/master
kof Sep 26, 2015
f6981b3
bump version, add latest node to travis
kof Sep 26, 2015
60c869f
allow coverage instrumentation of multiple files
bjouhier Feb 1, 2016
b53a7ee
use options.coverage.files + allow array of strings or regexps
bjouhier Feb 2, 2016
b0d6832
Merge pull request #125 from Sage/directory-coverage
kof Feb 2, 2016
1910235
bump the version
kof Feb 2, 2016
164a617
removed buggy regexp option from instrument filter
bjouhier Feb 2, 2016
afc4bec
unit test for instrumentation of multiple files
bjouhier Feb 2, 2016
34720f4
Merge pull request #126 from Sage/directory-coverage
kof Feb 3, 2016
6ba2337
bump the version
kof Feb 3, 2016
2655953
Added parsing of the maxBlockDuration config from the command line.
bramp Mar 26, 2016
5ee4f75
Merge pull request #130 from bramp/max-blocking-duration
kof Mar 30, 2016
f199b96
release 0.9.1
kof Mar 30, 2016
5f34c2b
Bumped `qunitjs` version to `1.23.1`
yomexzo Jun 2, 2016
114f473
rewrote all tests to accept the `assert` variable in callback and use…
yomexzo Jun 2, 2016
ec18f72
Changed `test()` invocations to `QUnit.test()`
yomexzo Jun 2, 2016
2d8ce66
Fixed bugs due to upgrade in `child.js`
yomexzo Jun 2, 2016
841531a
reverted back to using `test()` already in global instead of `QUnit.t…
yomexzo Jun 3, 2016
276f6c5
Merge pull request #1 from yomexzo/upgrade-qunit-1.23.1
yomexzo Aug 30, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ language: node_js
node_js:
- '0.10'
- '0.11'
- '0.12'
- '4.1.1'
4 changes: 4 additions & 0 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ help = ''
+ '\n -d, --deps dependency paths - files required before code (space separated)'
+ '\n -l, --log logging options, json have to be used'
+ '\n --cov create tests coverage report'
+ '\n --timeout max block duration (in ms)'
+ '\n -h, --help show this help'
+ '\n -v, --version show module version'
+ '\n';
Expand Down Expand Up @@ -84,6 +85,9 @@ for (var key in args) {
case '--paths':
o.paths = args[key];
break;
case '--timeout':
o.maxBlockDuration = args[key];
break;
case '-v':
case '--version':
util.print(
Expand Down
20 changes: 12 additions & 8 deletions lib/child.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,21 @@ var QUnit = require('qunitjs'),
// http://GOESSNER.net/articles/JsonPath/
require('../support/json/cycle');

var options = JSON.parse(process.argv[2]),
var options = JSON.parse(process.argv.pop()),
currentModule = path.basename(options.code.path, '.js'),
currentTest;

// send ping messages to when child is blocked.
// after I sent the first ping, testrunner will start to except the next ping
// within maxBlockDuration, otherwise this process will be killed
process.send({event: 'ping'});
setInterval(function() {
process.send({event: 'ping'});
}, Math.floor(options.maxBlockDuration / 2));

process.on('uncaughtException', function(err) {
if (QUnit.config.current) {
QUnit.ok(false, 'Test threw unexpected exception: ' + err.message);
QUnit.start();
}
process.send({
event: 'uncaughtException',
Expand All @@ -30,9 +37,6 @@ process.on('uncaughtException', function(err) {
});
});

QUnit.config.autorun = false;
QUnit.config.autostart = false;

// make qunit api global, like it is in the browser
_.extend(global, QUnit);

Expand All @@ -54,8 +58,6 @@ function _require(res, addToGlobal) {
_.extend(global, exports);
}
}

QUnit.start();
}

/**
Expand All @@ -75,7 +77,7 @@ QUnit.testStart(function(test) {
* @param {Object} data
*/
QUnit.log(function(data) {
data.test = this.config.current.testName;
data.test = QUnit.config.current.testName;
data.module = currentModule;
process.send({
event: 'assertionDone',
Expand Down Expand Up @@ -168,3 +170,5 @@ _require(options.code, true);
options.tests.forEach(function(test) {
_require(test, false);
});

QUnit.load();
20 changes: 17 additions & 3 deletions lib/coverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ var path = require('path'),
var istanbul,
collector,
options = {
dir: 'coverage'
dir: 'coverage',
reporters: ['lcov', 'json']
};

try {
Expand Down Expand Up @@ -38,7 +39,11 @@ exports.report = function() {

if (collector) {
Report = istanbul.Report;
reports = [Report.create('lcov', options), Report.create('json', options)];

reports = options.reporters.map(function (report) {
return Report.create(report, options);
});

reports.forEach(function(rep) {
rep.writeReport(collector, true);
});
Expand All @@ -49,7 +54,16 @@ exports.instrument = function(options) {
var matcher, instrumenter;

matcher = function (file) {
return file === options.code.path;
var files = options.coverage.files;
if (files) {
files = Array.isArray(files) ? files : [files];
return files.some(function(f) {
if (typeof f === 'string') return file.indexOf(f) === 0;
else throw new Error("invalid entry in options.coverage.files: " + typeof f);
});
} else {
return file === options.code.path;
}
}
instrumenter = new istanbul.Instrumenter();
istanbul.hook.hookRequire(matcher, instrumenter.instrumentSync.bind(instrumenter));
Expand Down
72 changes: 45 additions & 27 deletions lib/testrunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ options = exports.options = {
deps: null,

// define namespace your code will be attached to on global['your namespace']
namespace: null
namespace: null,

// max amount of ms child can be blocked, after that we assume running an infinite loop
maxBlockDuration: 2000
};

/**
Expand All @@ -55,40 +58,55 @@ options = exports.options = {
*/
function runOne(opts, callback) {
var child;
var pingCheckTimeoutId;
var argv = process.argv.slice();

child = cp.fork(
__dirname + '/child.js',
[JSON.stringify(opts)],
{env: process.env}
);
argv.push(JSON.stringify(opts));
child = cp.fork(__dirname + '/child.js', argv, {env: process.env});

function kill() {
process.removeListener('exit', kill);
child.kill();
}

function complete(err, data) {
kill();
clearTimeout(pingCheckTimeoutId);
callback(err, data)
}

child.on('message', function(msg) {
if (msg.event === 'assertionDone') {
log.add('assertions', msg.data);
} else if (msg.event === 'testDone') {
log.add('tests', msg.data);
} else if (msg.event === 'done') {
msg.data.code = opts.code.path;
log.add('summaries', msg.data);
if (opts.coverage) {
coverage.add(msg.data.coverage);
msg.data.coverage = coverage.get();
msg.data.coverage.code = msg.data.code;
log.add('coverages', msg.data.coverage);
}
if (opts.log.testing) {
console.log('done');
}
callback(null, msg.data);
kill();
} else if (msg.event === 'uncaughtException') {
callback(_.extend(new Error(), msg.data));
kill();
switch (msg.event) {
case 'ping':
clearTimeout(pingCheckTimeoutId);
pingCheckTimeoutId = setTimeout(function() {
complete(new Error('Process blocked for too long'));
}, opts.maxBlockDuration);
break;
case 'assertionDone':
log.add('assertions', msg.data);
break;
case 'testDone':
log.add('tests', msg.data);
break;
case 'done':
clearTimeout(pingCheckTimeoutId);
msg.data.code = opts.code.path;
log.add('summaries', msg.data);
if (opts.coverage) {
coverage.add(msg.data.coverage);
msg.data.coverage = coverage.get();
msg.data.coverage.code = msg.data.code;
log.add('coverages', msg.data.coverage);
}
if (opts.log.testing) {
console.log('done');
}
complete(null, msg.data);
break;
case 'uncaughtException':
complete(_.extend(new Error(), msg.data));
break;
}
});

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "qunit",
"description": "QUnit testing framework for nodejs",
"version": "0.7.2",
"version": "0.9.1",
"author": "Oleg Slobodskoi <oleg008@gmail.com>",
"contributors": [
{
Expand Down Expand Up @@ -30,7 +30,7 @@
"qunit": "./bin/cli.js"
},
"engines": {
"node": ">=0.6.0 < 0.12.0"
"node": ">=0.6.0 < 5.0"
},
"scripts": {
"test": "node --harmony ./test/testrunner.js"
Expand All @@ -39,7 +39,7 @@
"argsparser": "^0.0.6",
"cli-table": "^0.3.0",
"co": "^3.0.6",
"qunitjs": "1.10.0",
"qunitjs": "1.23.1",
"tracejs": "^0.1.8",
"underscore": "^1.6.0"
},
Expand Down
15 changes: 13 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## QUnit testing framework for nodejs.

[![Build Status](https://travis-ci.org/kof/node-qunit.png?branch=master)](https://travis-ci.org/kof/node-qunit)

http://qunitjs.com

http://github.com/jquery/qunit
Expand Down Expand Up @@ -97,7 +99,10 @@ var testrunner = require("qunit");
deps: null,

// define namespace your code will be attached to on global['your namespace']
namespace: null
namespace: null,

// max amount of ms child can be blocked, after that we assume running an infinite loop
maxBlockDuration: 2000
}
```

Expand Down Expand Up @@ -259,4 +264,10 @@ $ npm test

### Coverage

Code coverage via Istanbul. To utilize, install `istanbul` and set option `coverage: true` or give a path where to store report `coverage: {dir: "coverage/path"}` or pass `--cov` parameter in the shell. Coverage calculations based on code and tests passed to `node-qunit`.
Code coverage via Istanbul.

To utilize, install `istanbul` and set option `coverage: true` or give a path where to store report `coverage: {dir: "coverage/path"}` or pass `--cov` parameter in the shell.

To specify the format of coverage report pass reporters array to the coverage options: `coverage: {reporters: ['lcov', 'json']}` (default)

Coverage calculations based on code and tests passed to `node-qunit`.
26 changes: 13 additions & 13 deletions test/fixtures/async-test.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
test('1', 1, function (){
ok(true, "tests intermixing sync and async tests #1");
test('1', 1, function (assert){
assert.ok(true, "tests intermixing sync and async tests #1");
});

test('a', 2, function(){
stop();
test('a', 2, function(assert){
var done = assert.async();

setTimeout(function() {
ok(true, 'test a1');
ok(true, 'test a2');
start();
assert.ok(true, 'test a1');
assert.ok(true, 'test a2');
done();
}, 10000);
});

test('2', 1, function (){
ok(true, "tests intermixing sync and async tests #2");
assert.ok(true, "tests intermixing sync and async tests #2");
});

test('b', 2, function(){
stop();
test('b', 2, function(assert){
var done = assert.async();

setTimeout(function() {
ok(true, 'test b1');
ok(true, 'test b2');
start();
assert.ok(true, 'test b1');
assert.ok(true, 'test b2');
done();
}, 10);
});
6 changes: 3 additions & 3 deletions test/fixtures/child-tests-global.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
test("Dependency file required as global", function() {
equal(typeof whereFrom, "function");
equal(whereFrom(), "I was required as global");
test("Dependency file required as global", function(assert) {
assert.equal(typeof whereFrom, "function");
assert.equal(whereFrom(), "I was required as global");
});
8 changes: 4 additions & 4 deletions test/fixtures/child-tests-namespace.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
test("Dependency file required as a namespace object", function() {
strictEqual(typeof testns != "undefined", true);
equal(typeof testns.whereFrom, "function", "right method attached to right object");
equal(testns.whereFrom(), "I was required as a namespace object");
test("Dependency file required as a namespace object", function(assert) {
assert.strictEqual(typeof testns != "undefined", true);
assert.equal(typeof testns.whereFrom, "function", "right method attached to right object");
assert.equal(testns.whereFrom(), "I was required as a namespace object");
});
1 change: 1 addition & 0 deletions test/fixtures/coverage-multiple-code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./coverage-code')
16 changes: 8 additions & 8 deletions test/fixtures/coverage-test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
test('myMethod test', function() {
equal(myMethod(), 123, 'myMethod returns right result');
test('myMethod test', function(assert) {
assert.equal(myMethod(), 123, 'myMethod returns right result');
});

test('myAsyncMethod test', function() {
ok(true, 'myAsyncMethod started');
test('myAsyncMethod test', function(assert) {
assert.ok(true, 'myAsyncMethod started');

stop();
expect(2);
var done = assert.async();
assert.expect(2);

myAsyncMethod(function(data) {
equal(data, 123, 'myAsyncMethod returns right result');
start();
assert.equal(data, 123, 'myAsyncMethod returns right result');
done();
});
});
4 changes: 2 additions & 2 deletions test/fixtures/generators-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
test('generators', function* () {
test('generators', function* (assert) {
var data = yield thunk();
deepEqual(data, {a: 1}, 'woks');
assert.deepEqual(data, {a: 1}, 'woks');
});
1 change: 1 addition & 0 deletions test/fixtures/infinite-loop-code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
while(1) {}
3 changes: 3 additions & 0 deletions test/fixtures/infinite-loop-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
test('infinite loop', function(assert) {
assert.ok(true)
})
Loading