180 lines
4.1 KiB
JavaScript
180 lines
4.1 KiB
JavaScript
"use strict";
|
|
|
|
const path = require( "path" );
|
|
|
|
const requireFromCWD = require( "./require-from-cwd" );
|
|
const requireQUnit = require( "./require-qunit" );
|
|
const utils = require( "./utils" );
|
|
|
|
const IGNORED_GLOBS = [
|
|
"**/node_modules/**"
|
|
];
|
|
const RESTART_DEBOUNCE_LENGTH = 200;
|
|
|
|
let QUnit;
|
|
|
|
function run( args, options ) {
|
|
|
|
// Default to non-zero exit code to avoid false positives
|
|
process.exitCode = 1;
|
|
|
|
const files = utils.getFilesFromArgs( args );
|
|
|
|
QUnit = requireQUnit();
|
|
|
|
if ( options.filter ) {
|
|
QUnit.config.filter = options.filter;
|
|
}
|
|
|
|
const seed = options.seed;
|
|
if ( seed ) {
|
|
if ( seed === true ) {
|
|
QUnit.config.seed = Math.random().toString( 36 ).slice( 2 );
|
|
} else {
|
|
QUnit.config.seed = seed;
|
|
}
|
|
|
|
console.log( `Running tests with seed: ${QUnit.config.seed}` );
|
|
}
|
|
|
|
// TODO: Enable mode where QUnit is not auto-injected, but other setup is
|
|
// still done automatically.
|
|
global.QUnit = QUnit;
|
|
|
|
options.requires.forEach( requireFromCWD );
|
|
|
|
options.reporter.init( QUnit );
|
|
|
|
for ( let i = 0; i < files.length; i++ ) {
|
|
const filePath = path.resolve( process.cwd(), files[ i ] );
|
|
delete require.cache[ filePath ];
|
|
|
|
try {
|
|
require( filePath );
|
|
} catch ( e ) {
|
|
|
|
// eslint-disable-next-line no-loop-func
|
|
QUnit.module( files[ i ], function() {
|
|
const loadFailureMessage = `Failed to load the test file with error:\n${e.stack}`;
|
|
QUnit.test( loadFailureMessage, function( assert ) {
|
|
assert.ok( false, "should be able to load file" );
|
|
} );
|
|
} );
|
|
}
|
|
}
|
|
|
|
let running = true;
|
|
|
|
// Listen for unhandled rejections, and call QUnit.onUnhandledRejection
|
|
process.on( "unhandledRejection", function( reason ) {
|
|
QUnit.onUnhandledRejection( reason );
|
|
} );
|
|
|
|
process.on( "uncaughtException", function( error ) {
|
|
QUnit.onError( error );
|
|
} );
|
|
|
|
process.on( "exit", function() {
|
|
if ( running ) {
|
|
console.error( "Error: Process exited before tests finished running" );
|
|
|
|
const currentTest = QUnit.config.current;
|
|
if ( currentTest && currentTest.semaphore ) {
|
|
const name = currentTest.testName;
|
|
console.error( "Last test to run (" + name + ") has an async hold. " +
|
|
"Ensure all assert.async() callbacks are invoked and Promises resolve. " +
|
|
"You should also set a standard timeout via QUnit.config.testTimeout." );
|
|
}
|
|
}
|
|
} );
|
|
|
|
QUnit.start();
|
|
|
|
QUnit.on( "runEnd", function setExitCode( data ) {
|
|
running = false;
|
|
|
|
if ( data.testCounts.failed ) {
|
|
process.exitCode = 1;
|
|
} else {
|
|
process.exitCode = 0;
|
|
}
|
|
} );
|
|
}
|
|
|
|
run.restart = function( args ) {
|
|
clearTimeout( this._restartDebounceTimer );
|
|
|
|
this._restartDebounceTimer = setTimeout( () => {
|
|
|
|
const watchedFiles = utils.findFiles( process.cwd(), {
|
|
match: [ "**/*.js" ],
|
|
ignore: IGNORED_GLOBS
|
|
} );
|
|
|
|
watchedFiles.forEach( file => delete require.cache[ path.resolve( file ) ] );
|
|
|
|
if ( QUnit.config.queue.length ) {
|
|
console.log( "Finishing current test and restarting..." );
|
|
} else {
|
|
console.log( "Restarting..." );
|
|
}
|
|
|
|
run.abort( () => run.apply( null, args ) );
|
|
}, RESTART_DEBOUNCE_LENGTH );
|
|
};
|
|
|
|
run.abort = function( callback ) {
|
|
function clearQUnit() {
|
|
delete global.QUnit;
|
|
QUnit = null;
|
|
if ( callback ) {
|
|
callback();
|
|
}
|
|
}
|
|
|
|
if ( QUnit.config.queue.length ) {
|
|
const nextTestIndex = QUnit.config.queue.findIndex( fn => fn.name === "runTest" );
|
|
QUnit.config.queue.splice( nextTestIndex );
|
|
QUnit.on( "runEnd", clearQUnit );
|
|
} else {
|
|
clearQUnit();
|
|
}
|
|
};
|
|
|
|
run.watch = function watch() {
|
|
const watch = require( "node-watch" );
|
|
const args = Array.prototype.slice.call( arguments );
|
|
const baseDir = process.cwd();
|
|
|
|
const watcher = watch( baseDir, {
|
|
persistent: true,
|
|
recursive: true,
|
|
delay: 0,
|
|
filter: ( fullpath ) => {
|
|
return !/\/node_modules\//.test( fullpath ) &&
|
|
/\.js$/.test( fullpath );
|
|
}
|
|
}, ( event, fullpath ) => {
|
|
console.log( `File ${event}: ${path.relative( baseDir, fullpath )}` );
|
|
run.restart( args );
|
|
} );
|
|
|
|
watcher.on( "ready", () => {
|
|
run.apply( null, args );
|
|
} );
|
|
|
|
function stop() {
|
|
console.log( "Stopping QUnit..." );
|
|
|
|
watcher.close();
|
|
run.abort( () => {
|
|
process.exit();
|
|
} );
|
|
}
|
|
|
|
process.on( "SIGTERM", stop );
|
|
process.on( "SIGINT", stop );
|
|
};
|
|
|
|
module.exports = run;
|