diff --git a/index.js b/index.js index 131cbd031..f987caf2f 100644 --- a/index.js +++ b/index.js @@ -1,88 +1,8 @@ 'use strict'; -var process = require('./lib/process-adapter'); -var serializeError = require('./lib/serialize-error'); -var globals = require('./lib/globals'); -var Runner = require('./lib/runner'); -var send = process.send; -var opts = globals.options; -var runner = new Runner({ - serial: opts.serial, - bail: opts.failFast, - match: opts.match -}); - -// note that test files have require('ava') -require('./lib/test-worker').avaRequired = true; - -// if fail-fast is enabled, use this variable to detect -// that no more tests should be logged -var isFailed = false; - -Error.stackTraceLimit = Infinity; - -function test(props) { - if (isFailed) { - return; - } - - var hasError = typeof props.error !== 'undefined'; - - // don't display anything if it's a passed hook - if (!hasError && props.type !== 'test') { - return; - } - - if (hasError) { - props.error = serializeError(props.error); - } else { - props.error = null; - } - - send('test', props); - - if (hasError && opts.failFast) { - isFailed = true; - exit(); - } -} - -function exit() { - var stats = runner._buildStats(); - - send('results', { - stats: stats - }); +// Ensure the same AVA install is loaded by the test file as by the test worker. +if (process.env.AVA_PATH && process.env.AVA_PATH !== __dirname) { + module.exports = require(process.env.AVA_PATH); // eslint-disable-line import/no-dynamic-require +} else { + module.exports = require('./lib/main'); } - -globals.setImmediate(function () { - var hasExclusive = runner.tests.hasExclusive; - var numberOfTests = runner.tests.tests.concurrent.length + runner.tests.tests.serial.length; - - if (numberOfTests === 0) { - send('no-tests', {avaRequired: true}); - return; - } - - send('stats', { - testCount: numberOfTests, - hasExclusive: hasExclusive - }); - - runner.on('test', test); - - process.on('ava-run', function (options) { - runner.run(options).then(exit); - }); - - process.on('ava-init-exit', function () { - exit(); - }); -}); - -module.exports = runner.test; - -// TypeScript imports the `default` property for -// an ES2015 default import (`import test from 'ava'`) -// See: https://github.com/Microsoft/TypeScript/issues/2242#issuecomment-83694181 -module.exports.default = runner.test; diff --git a/lib/fork.js b/lib/fork.js index 495f8d8c7..c7ceac4e2 100644 --- a/lib/fork.js +++ b/lib/fork.js @@ -30,6 +30,10 @@ if (env.NODE_PATH) { .join(path.delimiter); } +// In case the test file imports a different AVA install, the presence of this variable allows it to require this one +// instead. +env.AVA_PATH = path.resolve(__dirname, '..'); + module.exports = function (file, opts, execArgv) { opts = objectAssign({ file: file, diff --git a/lib/main.js b/lib/main.js new file mode 100644 index 000000000..9e50dae14 --- /dev/null +++ b/lib/main.js @@ -0,0 +1,89 @@ +'use strict'; + +var process = require('./process-adapter'); +var serializeError = require('./serialize-error'); +var globals = require('./globals'); +var Runner = require('./runner'); +var send = process.send; + +var opts = globals.options; +var runner = new Runner({ + serial: opts.serial, + bail: opts.failFast, + match: opts.match +}); + +// note that test files have require('ava') +require('./test-worker').avaRequired = true; + +// if fail-fast is enabled, use this variable to detect +// that no more tests should be logged +var isFailed = false; + +Error.stackTraceLimit = Infinity; + +function test(props) { + if (isFailed) { + return; + } + + var hasError = typeof props.error !== 'undefined'; + + // don't display anything if it's a passed hook + if (!hasError && props.type !== 'test') { + return; + } + + if (hasError) { + props.error = serializeError(props.error); + } else { + props.error = null; + } + + send('test', props); + + if (hasError && opts.failFast) { + isFailed = true; + exit(); + } +} + +function exit() { + var stats = runner._buildStats(); + + send('results', { + stats: stats + }); +} + +globals.setImmediate(function () { + var hasExclusive = runner.tests.hasExclusive; + var numberOfTests = runner.tests.tests.concurrent.length + runner.tests.tests.serial.length; + + if (numberOfTests === 0) { + send('no-tests', {avaRequired: true}); + return; + } + + send('stats', { + testCount: numberOfTests, + hasExclusive: hasExclusive + }); + + runner.on('test', test); + + process.on('ava-run', function (options) { + runner.run(options).then(exit); + }); + + process.on('ava-init-exit', function () { + exit(); + }); +}); + +module.exports = runner.test; + +// TypeScript imports the `default` property for +// an ES2015 default import (`import test from 'ava'`) +// See: https://github.com/Microsoft/TypeScript/issues/2242#issuecomment-83694181 +module.exports.default = runner.test; diff --git a/test/cli.js b/test/cli.js index 3982a5ea9..2c60b62ce 100644 --- a/test/cli.js +++ b/test/cli.js @@ -1,4 +1,5 @@ 'use strict'; +var fs = require('fs'); var path = require('path'); var childProcess = require('child_process'); var test = require('tap').test; @@ -7,6 +8,7 @@ var getStream = require('get-stream'); var figures = require('figures'); var arrify = require('arrify'); var chalk = require('chalk'); +var mkdirp = require('mkdirp'); var touch = require('touch'); var proxyquire = require('proxyquire'); var sinon = require('sinon'); @@ -368,3 +370,21 @@ test('prefers local version of ava', function (t) { t.ok(debugSpy.calledWith('Using local install of AVA')); t.end(); }); + +test('workers ensure test files load the same version of ava', function (t) { + var target = path.join(__dirname, 'fixture', 'ava-paths', 'target'); + + // Copy the index.js so the testFile imports it. It should then load the correct AVA install. + var targetInstall = path.join(target, 'node_modules', 'ava'); + mkdirp.sync(targetInstall); + fs.writeFileSync( + path.join(targetInstall, 'index.js'), + fs.readFileSync(path.join(__dirname, '..', 'index.js')) + ); + + var testFile = path.join(target, 'test.js'); + execCli([testFile], {dirname: path.join('fixture', 'ava-paths', 'cwd')}, function (err) { + t.ifError(err); + t.end(); + }); +}); diff --git a/test/fixture/ava-paths/cwd/.gitkeep b/test/fixture/ava-paths/cwd/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixture/ava-paths/target/test.js b/test/fixture/ava-paths/target/test.js new file mode 100644 index 000000000..3d195b6f6 --- /dev/null +++ b/test/fixture/ava-paths/target/test.js @@ -0,0 +1,5 @@ +/* eslint-disable import/no-extraneous-dependencies */ +/* eslint-disable import/no-unresolved */ +import test from 'ava'; + +test(t => t.pass());