Skip to content

Commit

Permalink
Build: Rewrite test-on-node task to use QUnit.on()
Browse files Browse the repository at this point in the history
Ref #1511.
  • Loading branch information
Krinkle authored Nov 22, 2020
1 parent 2bf39f7 commit 6b50747
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 126 deletions.
62 changes: 37 additions & 25 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,31 +155,43 @@ module.exports = function( grunt ) {
},
"test-on-node": {
files: [
"test/logs",
"test/main/test",
"test/main/assert",
"test/main/assert/step",
"test/main/assert/timeout",
"test/main/async",
"test/main/promise",
"test/main/modules",
"test/main/deepEqual",
"test/main/stack",
"test/main/utilities",
"test/events",
"test/events-in-test",
"test/onerror/inside-test",
"test/onerror/outside-test",
"test/only",
"test/setTimeout",
"test/main/dump",
"test/node/storage-1",
"test/node/storage-2",
"test/module-only",
"test/module-skip",
"test/module-todo",
"test/es2017/async-functions",
"test/es2017/throws"
"test/logs.js",
"test/main/test.js",
"test/main/assert.js",
"test/main/assert/step.js",
"test/main/assert/timeout.js",
"test/main/async.js",
"test/main/promise.js",
"test/main/modules.js",
"test/main/deepEqual.js",
"test/main/stack.js",
"test/main/utilities.js",
"test/events.js",
"test/events-in-test.js",
"test/onerror/inside-test.js",
"test/onerror/outside-test.js",
"test/only.js",
"test/setTimeout.js",
"test/main/dump.js",
"test/node/storage-1.js",
"test/node/storage-2.js",

// FIXME: These tests use an ugly hack that re-opens
// an already finished test run. This only works reliably
// via the HTML Reporter thanks to some delays in the bridge.
// These tests are about reporting, not about functional
// behaviour. They would be best run either as reflection on the
// DOM in an HTML Reporter test, or from the CLI by asserting
// TAP output. I suggest we do the latter, and then remove them
// from here.
//
// Ref https://github.com/qunitjs/qunit/issues/1511
//
// "test/module-only.js",
// "test/module-skip.js",
// "test/module-todo.js",
"test/es2017/async-functions.js",
"test/es2017/throws.js"
]
},
"watch-repeatable": {
Expand Down
150 changes: 49 additions & 101 deletions build/tasks/test-on-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,24 @@ module.exports = function( grunt ) {
grunt.registerMultiTask( "test-on-node", async function() {
var done = this.async();

const stats = [];
const totals = { files: 0, failed: 0 };
for ( const file of this.data ) {
const stat = await new Promise( resolve => runQUnit( file, resolve ) );
stats.push( stat );
totals.failed += await new Promise( resolve => runQUnit( file, resolve ) );
totals.files++;
}

var totals = stats.reduce( function( totals, stats ) {
totals.passed += stats.passed;
totals.failed += stats.failed;
totals.skipped += stats.skipped;
totals.todo += stats.todo;
totals.passedAssertions += stats.passedAssertions;
totals.failedAssertions += stats.failedAssertions;
totals.runtime += stats.runtime;
return totals;
}, {
passed: 0,
failed: 0,
skipped: 0,
todo: 0,
runtime: 0,
passedAssertions: 0,
failedAssertions: 0
} );

grunt.log.writeln( "-----" );
grunt.log.ok( constructMessage( totals ) );
if ( totals.failed ) {
grunt.log.error( `Ran ${totals.files} files, ${totals.failed} failed tests` );
} else {
grunt.log.ok( `Ran ${totals.files} files` );
}

// Refresh the QUnit global to be used in other tests
global.QUnit = requireFresh( "../../dist/qunit" );

done( !totals.failed );
} );

function constructMessage( stats ) {
var totalTests = stats.passed + stats.failed + stats.skipped + stats.todo,
totalAssertions = stats.passedAssertions + stats.failedAssertions;

return [
totalTests,
" tests completed with ",
stats.failed,
" failed, " +
stats.skipped,
" skipped, and ",
stats.todo,
" todo. \n" +
totalAssertions,
" assertions (in ",
stats.runtime,
"ms), passed: " +
stats.passedAssertions,
", failed: ",
stats.failedAssertions
].join( "" );
}

function requireFresh( path ) {
var resolvedPath = require.resolve( path );
delete require.cache[ resolvedPath ];
Expand All @@ -78,76 +39,63 @@ module.exports = function( grunt ) {
global.QUnit = QUnit;

QUnit.config.autostart = false;

requireFresh( "../../" + file );

registerEvents( QUnit, file, runEnd );

QUnit.start();
}

function registerEvents( QUnit, file, runEnd ) {
var runDone = false;
var testActive = false;
var stats = {
passed: 0,
failed: 0,
skipped: 0,
todo: 0
};

QUnit.begin( function() {
grunt.log.ok( "Testing " + file + " ..." );
} );

QUnit.testStart( function() {
testActive = true;
} );
function registerEvents( QUnit, fileName, callback ) {

QUnit.log( function( details ) {
if ( !testActive || details.result || details.todo ) {
return;
}
var message = "name: " + details.name + " module: " + details.module +
" message: " + details.message;
grunt.log.error( message );
} );

QUnit.testDone( function( details ) {
testActive = false;
// Silence deprecation warnings
const warn = process.stderr.write;
process.stderr.write = function() {};
function restore() {
process.stderr.write = warn;
}

var testPassed = details.failed > 0 ? details.todo : !details.todo;
// These tests are relatively short. Buffer the output so that we
// only have to restore once, and can craft more condensed output.
let out = "";

if ( details.skipped ) {
stats.skipped++;
} else if ( !testPassed ) {
stats.failed++;
} else if ( details.todo ) {
stats.todo++;
} else {
stats.passed++;
}
QUnit.on( "runStart", () => {
out += "Testing " + fileName;
} );

QUnit.done( function( details ) {
if ( runDone ) {
QUnit.on( "testEnd", ( testEnd ) => {
if ( testEnd.status === "todo" ) {
return;
}
testEnd.errors.forEach( ( assertion ) => {
out += `\n\ntest: ${testEnd.name}\n` +
`module: ${testEnd.suiteName}\n` +
`message: ${assertion.message}\n${assertion.stack || ""}`;
} );
} );

stats.runtime = details.runtime;
stats.passedAssertions = details.passed;
stats.failedAssertions = details.failed;

var message = constructMessage( stats );

if ( stats.failed ) {
grunt.log.error( message );
QUnit.on( "runEnd", ( suiteEnd ) => {
restore();
const stats = suiteEnd.testCounts;

if ( suiteEnd.status === "failed" ) {
out += "\n" + `${stats.total} tests in ${suiteEnd.runtime}ms`;
out += `, ${stats.passed} passed`;
if ( stats.failed ) {
out += `, ${stats.failed} failed`;
}
if ( stats.skipped ) {
out += `, ${stats.skipped} skipped`;
}
if ( stats.todo ) {
out += `, ${stats.todo} todo`;
}
out += ".";
grunt.log.error( out );
} else {
grunt.log.ok( message );
out += ` (${stats.total} tests in ${suiteEnd.runtime}ms)`;
grunt.log.writeln( out );
}

runDone = true;
runEnd( stats );
callback( stats.failed );
} );
}
};

0 comments on commit 6b50747

Please sign in to comment.