From b7db0fb911810441bd898706f868278e81c67c2e Mon Sep 17 00:00:00 2001 From: Trent Willis Date: Fri, 2 Mar 2018 10:59:42 -0800 Subject: [PATCH] CLI: Implement --require option --- bin/qunit | 8 +++ bin/require-from-cwd.js | 6 +++ bin/run.js | 52 ++++++++++--------- test/cli/fixtures/expected/tap-outputs.js | 13 ++++- .../node_modules/require-dep/index.js | 1 + .../node_modules/require-dep/module.js | 1 + .../node_modules/require-dep/package.json | 4 ++ test/cli/main.js | 22 ++++++++ 8 files changed, 82 insertions(+), 25 deletions(-) create mode 100644 bin/require-from-cwd.js create mode 100644 test/cli/fixtures/node_modules/require-dep/index.js create mode 100644 test/cli/fixtures/node_modules/require-dep/module.js create mode 100644 test/cli/fixtures/node_modules/require-dep/package.json diff --git a/bin/qunit b/bin/qunit index 847527d82..61946a62c 100755 --- a/bin/qunit +++ b/bin/qunit @@ -17,6 +17,11 @@ const description = `Runs tests using the QUnit framework. For more info on working with QUnit, check out http://qunitjs.com.`; +function collect( val, collection ) { + collection.push( val ); + return collection; +} + program._name = "qunit"; program .version( pkg.version ) @@ -26,6 +31,8 @@ program .option( "-r, --reporter [name]", "specify the reporter to use; " + "if no match is found or no name is provided, a list of available " + "reporters will be displayed" ) + .option( "--require ", "specify a module to require prior to running " + + "any tests.", collect, [] ) .option( "--seed [value]", "specify a seed to order your tests; " + "if option is specified without a value, one will be generated" ) .option( "-w, --watch", "Watch files for changes and re-run the test suite" ) @@ -39,6 +46,7 @@ const args = program.args; const options = { filter: program.filter, reporter: findReporter( program.reporter ), + requires: program.require, seed: program.seed }; diff --git a/bin/require-from-cwd.js b/bin/require-from-cwd.js new file mode 100644 index 000000000..007d11905 --- /dev/null +++ b/bin/require-from-cwd.js @@ -0,0 +1,6 @@ +const resolve = require( "resolve" ); + +module.exports = function requireFromCWD( mod ) { + const resolvedPath = resolve.sync( mod, { basedir: process.cwd() } ); + return require( resolvedPath ); +}; diff --git a/bin/run.js b/bin/run.js index 1eeeef9ef..52a1b3129 100644 --- a/bin/run.js +++ b/bin/run.js @@ -3,6 +3,7 @@ const path = require( "path" ); const walkSync = require( "walk-sync" ); +const requireFromCWD = require( "./require-from-cwd" ); const requireQUnit = require( "./require-qunit" ); const utils = require( "./utils" ); @@ -14,34 +15,10 @@ const RESTART_DEBOUNCE_LENGTH = 200; let QUnit; function run( args, options ) { - let running = true; // Default to non-zero exit code to avoid false positives process.exitCode = 1; - 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." ); - } - } - } ); - - // Listen for unhandled rejections, and call QUnit.onUnhandledRejection - process.on( "unhandledRejection", function( reason ) { - QUnit.onUnhandledRejection( reason ); - } ); - - process.on( "uncaughtException", function( error ) { - QUnit.onError( error ); - } ); - const files = utils.getFilesFromArgs( args ); QUnit = requireQUnit(); @@ -65,6 +42,8 @@ function run( args, options ) { // still done automatically. global.QUnit = QUnit; + options.requires.forEach( requireFromCWD ); + options.reporter.init( QUnit ); for ( let i = 0; i < files.length; i++ ) { @@ -85,6 +64,31 @@ function run( args, options ) { } } + 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 ) { diff --git a/test/cli/fixtures/expected/tap-outputs.js b/test/cli/fixtures/expected/tap-outputs.js index da89335d4..1a66624bb 100644 --- a/test/cli/fixtures/expected/tap-outputs.js +++ b/test/cli/fixtures/expected/tap-outputs.js @@ -158,5 +158,16 @@ not ok 1 global failure # skip 0 # todo 0 # fail 1 -` +`, + + "qunit single.js --require require-dep --require './node_modules/require-dep/module.js'": +`required require-dep/index.js +required require-dep/module.js +TAP version 13 +ok 1 Single > has a test +1..1 +# pass 1 +# skip 0 +# todo 0 +# fail 0` }; diff --git a/test/cli/fixtures/node_modules/require-dep/index.js b/test/cli/fixtures/node_modules/require-dep/index.js new file mode 100644 index 000000000..8fd7bf873 --- /dev/null +++ b/test/cli/fixtures/node_modules/require-dep/index.js @@ -0,0 +1 @@ +console.log( "required require-dep/index.js" ); diff --git a/test/cli/fixtures/node_modules/require-dep/module.js b/test/cli/fixtures/node_modules/require-dep/module.js new file mode 100644 index 000000000..21055bea7 --- /dev/null +++ b/test/cli/fixtures/node_modules/require-dep/module.js @@ -0,0 +1 @@ +console.log( "required require-dep/module.js" ); diff --git a/test/cli/fixtures/node_modules/require-dep/package.json b/test/cli/fixtures/node_modules/require-dep/package.json new file mode 100644 index 000000000..ab3a66a4f --- /dev/null +++ b/test/cli/fixtures/node_modules/require-dep/package.json @@ -0,0 +1,4 @@ +{ + "version": "1.0.0", + "name": "require-dep" +} diff --git a/test/cli/main.js b/test/cli/main.js index 0c6bd8c9c..9407ea021 100644 --- a/test/cli/main.js +++ b/test/cli/main.js @@ -146,6 +146,28 @@ QUnit.module( "CLI Main", function() { } ) ); } ); + QUnit.module( "require", function() { + QUnit.test( "can properly require dependencies and modules", co.wrap( function* ( assert ) { + const command = "qunit single.js --require require-dep --require './node_modules/require-dep/module.js'"; + const execution = yield execute( command ); + + assert.equal( execution.code, 0 ); + assert.equal( execution.stderr, "" ); + assert.equal( execution.stdout, expectedOutput[ command ] ); + } ) ); + + QUnit.test( "displays helpful error when failing to require a file", co.wrap( function* ( assert ) { + const command = "qunit single.js --require 'does-not-exist-at-all'"; + try { + yield execute( command ); + } catch ( e ) { + assert.equal( e.code, 1 ); + assert.ok( e.stderr.includes( "Error: Cannot find module 'does-not-exist-at-all'" ) ); + assert.equal( e.stdout, "" ); + } + } ) ); + } ); + QUnit.module( "seed", function() { QUnit.test( "can properly seed tests", co.wrap( function* ( assert ) { const command = "qunit --seed 's33d' test single.js 'glob/**/*-test.js'";