Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

small enhancements

  • Loading branch information...
commit 2cb3f45ae9c580aa30d8027ed29ae629f1100dc4 1 parent 07e3df8
@kof authored
View
73 bin/cli.js
@@ -1,11 +1,32 @@
#!/usr/bin/env node
+var util = require('util'),
+ argsparser = require('argsparser'),
+ fs = require('fs');
+
var root = __dirname + '/..',
- args = require('argsparser').parse(),
- testrunner = require( root ),
- util = require( 'util' ),
+ args = argsparser.parse(),
+ testrunner = require(root),
o = testrunner.options,
- code, tests;
+ code, tests,
+ help;
+
+help = ''
+ + '\nUsage: cli [options] value (boolean value can be used)'
+ + '\n'
+ + '\nOptions:'
+ + '\n -c, --code path to code you want to test'
+ + '\n -t, --tests path to tests (space separated)'
+ + '\n -d, --deps dependency paths - files required before code (space separated)'
+ + '\n -o, --errors-only report only errors'
+ + '\n -e, --error-stack display error stack'
+ + '\n -s, --summary display summary report'
+ + '\n --cov create tests coverage report'
+ + '\n -p, --paths, add paths to require.paths array'
+ + '\n --tmp change temp dir, which is used for jscoverage tool'
+ + '\n -h, --help show this help'
+ + '\n -v, --version show module version'
+ + '\n';
/**
* Parses a code or dependency argument, returning an object defining the
@@ -18,13 +39,13 @@ var root = __dirname + '/..',
* @param {string} path to file or module name to require.
* @return {Object} resource
*/
-function parsePath( path ) {
- var parts = path.split( ':' ),
+function parsePath(path) {
+ var parts = path.split(':'),
resource = {
path: path
};
- if ( parts.length === 2 ) {
+ if (parts.length === 2) {
resource.namespace = parts[0];
resource.path = parts[1];
}
@@ -32,24 +53,8 @@ function parsePath( path ) {
return resource;
}
-var help = ''
- + '\nUsage: cli [options] value (boolean value can be used)'
- + '\n'
- + '\nOptions:'
- + '\n -c, --code path to code you want to test'
- + '\n -t, --tests path to tests (space separated)'
- + '\n -d, --deps dependency paths - files required before code (space separated)'
- + '\n -o, --errors-only report only errors'
- + '\n -e, --error-stack display error stack'
- + '\n -s, --summary display summary report'
- + '\n --cov create tests coverage report'
- + '\n -p, --paths, add paths to require.paths array'
- + '\n --tmp change temp dir, which is used for jscoverage tool'
- + '\n -h, --help show this help'
- + '\n';
-
-for ( var key in args ) {
- switch( key ) {
+for (var key in args) {
+ switch(key) {
case 'node':
// Skip the 'node' argument
break;
@@ -67,7 +72,7 @@ for ( var key in args ) {
case '-d':
case '--deps':
o.deps = args[key];
- if ( !Array.isArray ( o.deps ) ) {
+ if (!Array.isArray (o.deps)) {
o.deps = [o.deps];
}
o.deps = o.deps.map(parsePath);
@@ -94,16 +99,24 @@ for ( var key in args ) {
case '--tmp':
o.coverageTmpDir = args[key];
break;
+ case '-v':
+ case '--version':
+ util.print(
+ JSON.parse(
+ fs.readFileSync(__dirname + '/../package.json')
+ ).version + '\n'
+ );
+ return;
case '-h':
case '-?':
case '--help':
- util.print( help );
+ util.print(help);
return;
}
}
-if( !code || !tests ) {
- util.print( help );
- util.print( '\nBoth --code and --tests arguments are required\n' );
+if(!code || !tests) {
+ util.print(help);
+ util.print('\nBoth --code and --tests arguments are required\n');
return;
}
View
79 lib/child.js
@@ -1,22 +1,25 @@
var path = require('path'),
fs = require('fs'),
- vm = require('vm'),
+ vm = require('vm'),
_ = require('underscore'),
- trace = require('tracejs').trace,
- options = JSON.parse(process.argv[2]);
-
-var currentModule = path.basename(options.code.path, '.js'),
- currentTest;
+ trace = require('tracejs').trace;
-var qunitPath = __dirname + '/../deps/qunit/qunit/qunit.js',
+var options = JSON.parse(process.argv[2]),
+ currentModule = path.basename(options.code.path, '.js'),
+ currentTest,
+ doneTimeout,
+ qunitPath = __dirname + '/../deps/qunit/qunit/qunit.js',
qunitCode,
- sandbox = {
- require: require,
- exports: {},
- window: {setTimeout: setTimeout},
- console: console,
- clearTimeout: clearTimeout
- };
+ sandbox;
+
+// globals needed by qunit
+sandbox = {
+ require: require,
+ exports: {},
+ window: {setTimeout: setTimeout},
+ console: console,
+ clearTimeout: clearTimeout
+};
try {
qunitCode = fs.readFileSync(qunitPath, 'utf-8');
@@ -29,10 +32,9 @@ try {
vm.runInNewContext('(function(){'+ qunitCode +'}.call(window))', sandbox, qunitPath);
-_.extend(global, sandbox.exports);
// make qunit api global, like it is in the browser
-//_.extend(global, require('../deps/qunit/qunit/qunit'));
+_.extend(global, sandbox.exports);
/**
* Require a resource.
@@ -53,7 +55,7 @@ function load(res) {
* Calculate coverage stats using bunker
*/
function calcCoverage() {
-
+
}
/**
@@ -74,7 +76,7 @@ QUnit.testStart(function(test) {
QUnit.log(function(data) {
data.test = currentTest;
data.module = currentModule;
-
+
process.send({
event: 'assertionDone',
data: data
@@ -88,7 +90,7 @@ QUnit.log(function(data) {
QUnit.testDone(function(test) {
// use last module name if no module name defined
test.module = test.module || currentModule;
-
+
process.send({
event: 'testDone',
data: test
@@ -99,27 +101,16 @@ QUnit.testDone(function(test) {
* Callback for all done tests in the file.
* @param {Object} res
*/
-QUnit.done(function done(res) {
- clearTimeout(done.timeout);
- done.timeout = setTimeout(function() {
- if (options.coverage) {
- res.coverage = calcCoverage();
- }
-
- process.send({
- event: 'done',
- data: res
- });
- }, 3000);
-});
-
+QUnit.done(_.debounce(function done(res) {
+ if (options.coverage) {
+ res.coverage = calcCoverage();
+ }
-// require deps
-options.deps.forEach(load);
-// require code
-load(options.code);
-// require tests
-options.tests.forEach(load);
+ process.send({
+ event: 'done',
+ data: res
+ });
+}, 1000));
/**
* Provide better stack traces
@@ -133,4 +124,14 @@ console.error = function(obj) {
return error.apply(this, arguments);
};
+
+// require deps
+options.deps.forEach(load);
+
+// require code
+load(options.code);
+
+// require tests
+options.tests.forEach(load);
+
QUnit.begin();
View
6 lib/coverage.js
@@ -4,7 +4,7 @@ var bunker = require('bunker'),
exports.instrument = function(path) {
var src = fs.readFileSync(path, 'utf-8'),
newSrc = bunker(src).compile();
-
+
fs.renameSync(src, '__' + src);
fs.writeFileSync(path, newSrc, 'utf-8');
};
@@ -14,7 +14,7 @@ exports.restore = function(path) {
// do it only if the original file exist
if (fs.statSync('__' + path).isFile()) {
fs.unlinkSync(path);
- fs.renameSync('__' + path, path);
+ fs.renameSync('__' + path, path);
}
-
+
};
View
66 lib/log.js
@@ -1,17 +1,19 @@
var util = require('util'),
Table = require('cli-table');
-var data = {
- assertions: [],
- tests: [],
- summaries: []
- };
+var data;
+
+data = {
+ assertions: [],
+ tests: [],
+ summaries: []
+};
exports.assertion = function(d) {
if (d) {
data.assertions.push(d);
}
-
+
return data.assertions;
};
@@ -19,7 +21,7 @@ exports.test = function(d) {
if (d) {
data.tests.push(d);
}
-
+
return data.tests;
};
@@ -27,22 +29,22 @@ exports.summary = function(d) {
if (d) {
data.summaries.push(d);
}
-
+
return data.summaries;
};
var print = {};
print.assertions = function() {
- var table,
+ var table,
currentModule, module,
currentTest, test;
-
+
table = new Table({
head: ['Module', 'Test', 'Assertion', 'Result'],
colWidths: [40, 40, 40, 8]
});
-
+
data.assertions.forEach(function(data) {
// just easier to read the table
if (data.module === currentModule) {
@@ -50,29 +52,29 @@ print.assertions = function() {
} else {
module = currentModule = data.module;
}
-
+
// just easier to read the table
if (data.test === currentTest) {
test = '';
} else {
test = currentTest = data.test;
- }
+ }
table.push([module, test, data.message, data.result ? 'ok' : 'fail']);
});
-
+
util.print('\nAssertions:\n' + table.toString() + '\n');
}
print.tests = function() {
- var table,
+ var table,
currentModule, module;
-
+
table = new Table({
head: ['Module', 'Test', 'Failed', 'Passed', 'Total'],
colWidths: [40, 40, 8, 8, 8]
});
-
+
data.tests.forEach(function(data) {
// just easier to read the table
if (data.module === currentModule) {
@@ -83,43 +85,43 @@ print.tests = function() {
table.push([module, data.name, data.failed, data.passed, data.total]);
});
-
+
util.print('\Tests:\n' + table.toString() + '\n');
}
print.summary = function() {
var table, fileColWidth = 50;
-
+
table = new Table({
head: ['File', 'Failed', 'Passed', 'Total', 'Runtime'],
colWidths: [fileColWidth + 2, 10, 10, 10, 10]
});
-
+
data.summaries.forEach(function(data) {
var code = data.code;
-
- // truncate file name
+
+ // truncate file name
if (code.length > fileColWidth) {
code = '...' + code.slice(code.length - fileColWidth + 3);
}
-
+
table.push([code, data.failed, data.passed, data.total, data.runtime]);
});
-
+
util.print('\Summary:\n' + table.toString() + '\n');
}
print.globalSummary = function() {
var table,
data = exports.stats();
-
+
table = new Table({
head: ['Files', 'Tests', 'Assertions', 'Failed', 'Passed'],
colWidths: [12, 12, 12, 12, 12]
});
table.push([data.files, data.tests, data.assertions, data.failed, data.passed]);
-
+
util.print('\Global summary:\n' + table.toString() + '\n');
};
@@ -133,17 +135,17 @@ exports.stats = function() {
failed: 0,
passed: 0
};
-
+
data.summaries.forEach(function(file) {
stats.files++;
stats.assertions += file.total;
stats.failed += file.failed;
stats.passed += file.passed;
});
-
+
stats.tests = data.tests.length;
-
- return stats;
+
+ return stats;
};
/**
@@ -153,8 +155,8 @@ exports.reset = function() {
data = {
assertions: [],
tests: [],
- summaries: []
- };
+ summaries: []
+ };
};
/**
View
68 lib/testrunner.js
@@ -2,16 +2,20 @@ var fs = require('fs'),
path = require('path'),
coverage = require('./coverage'),
cp = require('child_process'),
+ _ = require('underscore'),
log = require('./log');
-var options = exports.options = {
- assertions: true,
- tests: true,
- summary: true,
- globalSummary: true,
- coverage: true,
- deps: null
- };
+var options;
+
+options = exports.options = {
+ assertions: true,
+ tests: true,
+ summary: true,
+ globalSummary: true,
+ coverage: false,
+ deps: null,
+ namespace: null
+};
/**
* Run one spawned instance with tests
@@ -20,26 +24,25 @@ var options = exports.options = {
*/
function runOne(opts, callback) {
var child;
+
child = cp.fork(
__dirname + '/child.js',
[JSON.stringify(opts)],
- { env: process.env }
+ {env: process.env}
);
child.on('message', function(msg) {
if (msg.event === 'assertionDone') {
- log.assertion(msg.data);
+ log.assertion(msg.data);
} else if (msg.event === 'testDone') {
- log.test(msg.data);
+ log.test(msg.data);
} else if (msg.event === 'done') {
msg.data.code = opts.code.path;
log.summary(msg.data);
+ callback(msg.data);
+
child.kill();
-
- if (typeof callback === 'function') {
- callback(msg.data);
- }
}
});
}
@@ -53,8 +56,8 @@ function absPath(file) {
if (typeof file === 'string') {
file = {path: file};
}
-
- if(file.path.charAt(0) === '.') {
+
+ if (file.path.charAt(0) === '.') {
file.path = path.join(process.cwd(), file.path);
}
@@ -66,7 +69,7 @@ function absPath(file) {
* @param {Array|string} files
* @return {Array}
*/
-function toArray(files) {
+function absPaths(files) {
var ret = [];
if (Array.isArray(files)) {
@@ -86,34 +89,27 @@ function toArray(files) {
* @param {Function} callback optional
*/
exports.run = function(files, callback) {
+ var filesCount = 0;
+
if (!Array.isArray(files)) {
files = [files];
}
- var filesCount = 0;
-
files.forEach(function(file) {
- var opts = {
- deps: toArray(file.deps || options.deps),
- code: absPath(file.code),
- tests: toArray(file.tests),
- paths: file.paths || options.paths,
- coverage: file.coverage,
- namespace: null
- };
-
- if (typeof opts.coverage === 'undefined') {
- opts.coverage = options.coverage;
- }
+ var opts = _.extend({}, options, file);
+
+ opts.deps = absPaths(opts.deps);
+ opts.code = absPath(opts.code);
+ opts.tests = absPaths(opts.tests);
function finished(stat) {
filesCount++;
-
+
if (filesCount >= files.length) {
if (options.assertions) {
log.print('assertions');
}
-
+
if (options.tests) {
log.print('tests');
}
@@ -125,15 +121,15 @@ exports.run = function(files, callback) {
if (options.globalSummary) {
log.print('globalSummary');
}
-
+
if (typeof callback === 'function') {
callback(log.stats());
}
}
-
}
if (opts.coverage) {
+ converage.instrument(opts.code);
} else {
runOne(opts, finished);
}
View
6 package.json
@@ -1,7 +1,7 @@
{
"name": "qunit",
"description": "A port of QUnit unit testing framework to nodejs",
- "version": "0.2.6",
+ "version": "0.2.8",
"author": "Oleg Slobodskoi <oleg008@gmail.com>",
"contributors": [
{"name": "Jonathan Buchanan"},
@@ -15,7 +15,7 @@
"bin": {"qunit": "./bin/cli.js"},
"engines": {"node": "0.6.x"},
"scripts": {
- "test": "make test"
+ "test": "make test"
},
"dependencies": {
"underscore": ">= 1.1.7",
@@ -28,7 +28,7 @@
"chainer": ">= 0.0.5"
},
"licenses": [
- {
+ {
"type": "MIT",
"url": "http: //www.opensource.org/licenses/mit-license.php"
}
View
18 test/fixtures/async-test.js
@@ -1,19 +1,19 @@
test('a', 2, function(){
stop();
-
+
setTimeout(function() {
- ok(true, 'test a1');
- ok(true, 'test a2');
- start();
- }, 10);
+ ok(true, 'test a1');
+ ok(true, 'test a2');
+ start();
+ }, 10000);
})
test('b', 2, function(){
stop();
-
+
setTimeout(function() {
- ok(true, 'test b1');
- ok(true, 'test b2');
- start();
+ ok(true, 'test b1');
+ ok(true, 'test b2');
+ start();
}, 10);
})
View
36 test/testrunner.js
@@ -1,6 +1,6 @@
var a = require('assert'),
chainer = require('chainer');
-
+
var tr = require('../lib/testrunner'),
log = require('../lib/log');
@@ -15,21 +15,20 @@ tr.options.globalSummary = false;
// reset log stats every time .next is called
chain.next = function() {
log.reset();
- return chainer.prototype.next.apply(this, arguments);
+ return chainer.prototype.next.apply(this, arguments);
};
chain.add('base testrunner', function() {
tr.run({
code: fixtures + '/testrunner-code.js',
tests: fixtures + '/testrunner-tests.js',
- coverage: false
}, function(res) {
- var stat = {
+ var stat = {
files: 1,
tests: 2,
assertions: 5,
failed: 2,
- passed: 3
+ passed: 3
};
a.deepEqual(stat, res, 'base testrunner test');
@@ -41,20 +40,19 @@ chain.add('attach code to global', function() {
tr.run({
code: fixtures + '/child-code-global.js',
tests: fixtures + '/child-tests-global.js',
- coverage: false
}, function(res) {
- var stat = {
+ var stat = {
files: 1,
tests: 1,
assertions: 2,
failed: 0,
- passed: 2
+ passed: 2
};
-
+
a.deepEqual(stat, res, 'attaching code to global works');
chain.next();
});
-});
+});
chain.add('attach code to a namespace', function() {
tr.run({
@@ -63,16 +61,15 @@ chain.add('attach code to a namespace', function() {
namespace: 'testns'
},
tests: fixtures + '/child-tests-namespace.js',
- coverage: false
}, function(res) {
- var stat = {
+ var stat = {
files: 1,
tests: 1,
assertions: 3,
failed: 0,
- passed: 3
+ passed: 3
};
-
+
a.deepEqual(stat, res, 'attaching code to specified namespace works');
chain.next();
});
@@ -82,25 +79,22 @@ chain.add('async testing logs', function() {
tr.run({
code: fixtures + '/async-code.js',
tests: fixtures + '/async-test.js',
- coverage: false
}, function(res) {
- var stat = {
+ var stat = {
files: 1,
tests: 2,
assertions: 4,
failed: 0,
- passed: 4
+ passed: 4
};
-
+
a.deepEqual(stat, res, 'async code testing works');
chain.next();
});
});
-
-
chain.add(function() {
- console.log('All tests done');
+ console.log('All tests done');
});
chain.start();
Please sign in to comment.
Something went wrong with that request. Please try again.