Skip to content

Add test debugging support #109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
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
12 changes: 10 additions & 2 deletions bin/cli.js
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ var root = __dirname + '/..',
args = argsparser.parse(),
testrunner = require(root),
o = testrunner.options,
code, tests,
code, tests, debug,
help;

help = ''
@@ -17,6 +17,7 @@ help = ''
+ '\nOptions:'
+ '\n -c, --code path to code you want to test'
+ '\n -t, --tests path to tests (space separated)'
+ '\n --debug debugging port'
+ '\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'
@@ -65,6 +66,9 @@ for (var key in args) {
// of QUnit in browsers.
tests = args[key];
break;
case '--debug':
debug = args[key];
break;
case '-d':
case '--deps':
o.deps = args[key];
@@ -105,7 +109,11 @@ if(!code || !tests) {
return;
}

testrunner.run({ code: code, tests: tests, deps: o.deps, log: o.log }, function(err, stats) {
debug = debug || process.execArgv.reduce(function (prevArg, curArg) {
return prevArg || curArg.indexOf('--debug') === 0;
}, false);

testrunner.run({ code: code, tests: tests, deps: o.deps, log: o.log, debug: debug }, function(err, stats) {
if (err) {
console.error(err);
process.exit(1);
14 changes: 8 additions & 6 deletions lib/child.js
Original file line number Diff line number Diff line change
@@ -16,13 +16,15 @@ 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() {
if(!options.debug) {
// 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'});
}, Math.floor(options.maxBlockDuration / 2));
setInterval(function () {
process.send({event: 'ping'});
}, Math.floor(options.maxBlockDuration / 2));
}

process.on('uncaughtException', function(err) {
if (QUnit.config.current) {
93 changes: 57 additions & 36 deletions lib/testrunner.js
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ var fs = require('fs'),
coverage = require('./coverage'),
cp = require('child_process'),
_ = require('underscore'),
freeport = require('freeport'),
log = exports.log = require('./log');

var options,
@@ -48,7 +49,10 @@ options = exports.options = {
namespace: null,

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

// port that should be used for debugging
debug: null
};

/**
@@ -60,9 +64,23 @@ function runOne(opts, callback) {
var child;
var pingCheckTimeoutId;
var argv = process.argv.slice();
var debug = opts.debug;

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

if (debug) {
if (typeof debug === 'boolean') {
freeport(function (er, port) {
process.execArgv.push('--debug-brk=' + port);
fork();
});
} else {
process.execArgv.push('--debug-brk=' + debug);
fork();
}
} else {
fork();
}

function kill() {
process.removeListener('exit', kill);
@@ -75,40 +93,43 @@ function runOne(opts, callback) {
callback(err, data)
}

child.on('message', function(msg) {
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;
}
});
function fork() {
child = cp.fork(__dirname + '/child.js', argv, {env: process.env});
child.on('message', function (msg) {
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;
}
});
}

process.on('exit', kill);

3 changes: 2 additions & 1 deletion 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.5",
"version": "0.7.6",
"author": "Oleg Slobodskoi <oleg008@gmail.com>",
"contributors": [
{
@@ -39,6 +39,7 @@
"argsparser": "^0.0.6",
"cli-table": "^0.3.0",
"co": "^3.0.6",
"freeport": "^1.0.3",
"qunitjs": "1.10.0",
"tracejs": "^0.1.8",
"underscore": "^1.6.0"