From 68b454df16682b2d614bb0bc972e9e4387f959c0 Mon Sep 17 00:00:00 2001 From: Harry Wolff Date: Wed, 3 Jan 2018 08:34:15 -0500 Subject: [PATCH 1/4] Add ability to pass in test files to be ran before positional files via --file Fixes #3181 --- bin/_mocha | 20 ++++++++++++++-- docs/index.md | 1 + .../fixtures/options/file-alpha.fixture.js | 9 +++++++ .../fixtures/options/file-beta.fixture.js | 7 ++++++ test/integration/helpers.js | 7 +++++- test/integration/options.spec.js | 24 +++++++++++++++++++ 6 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 test/integration/fixtures/options/file-alpha.fixture.js create mode 100644 test/integration/fixtures/options/file-beta.fixture.js diff --git a/bin/_mocha b/bin/_mocha index 19cc1c50da..9212b56e87 100755 --- a/bin/_mocha +++ b/bin/_mocha @@ -120,6 +120,12 @@ const play = (arr, interval) => { let files = []; +/** + * File args. + */ + +let fileArgs = []; + /** * Globals. */ @@ -199,7 +205,8 @@ program .option('--delay', 'wait for async suite definition') .option('--allow-uncaught', 'enable uncaught errors to propagate') .option('--forbid-only', 'causes test marked with only to fail the suite') - .option('--forbid-pending', 'causes pending tests and test marked with skip to fail the suite'); + .option('--forbid-pending', 'causes pending tests and test marked with skip to fail the suite') + .option('--file ', 'include a file to be ran during the suite', list, []); program._name = 'mocha'; @@ -271,6 +278,12 @@ program.on('option:require', mod => { requires.push(mod); }); +// --file + +program.on('option:file', mod => { + fileArgs.push(mod); +}); + // If not already done, load mocha.opts if (!process.env.LOADED_MOCHA_OPTS) { getOptions(); @@ -497,13 +510,16 @@ if (!files.length) { } // resolve - +fileArgs = fileArgs.map(path => resolve(path)); files = files.map(path => resolve(path)); if (program.sort) { files.sort(); } +// add files given through --file to be ran first +files = fileArgs.concat(files); + // --watch let runner; diff --git a/docs/index.md b/docs/index.md index c45133ca42..b3ddd690c4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -736,6 +736,7 @@ Mocha supports the `err.expected` and `err.actual` properties of any thrown `Ass --debug-brk enable node's debugger breaking on the first line --globals allow the given comma-delimited global [names] --es_staging enable all staged features + --file include a file to be ran during the suite [file] --harmony<_classes,_generators,...> all node --harmony* flags are available --preserve-symlinks Instructs the module loader to preserve symbolic links when resolving and caching modules --icu-data-dir include ICU data diff --git a/test/integration/fixtures/options/file-alpha.fixture.js b/test/integration/fixtures/options/file-alpha.fixture.js new file mode 100644 index 0000000000..dd74303163 --- /dev/null +++ b/test/integration/fixtures/options/file-alpha.fixture.js @@ -0,0 +1,9 @@ +'use strict'; + +describe('alpha', function () { + it('should be executed first', function () { + if (global.beta) { + throw new Error('alpha was not executed first'); + } + }); +}); diff --git a/test/integration/fixtures/options/file-beta.fixture.js b/test/integration/fixtures/options/file-beta.fixture.js new file mode 100644 index 0000000000..56da4a6523 --- /dev/null +++ b/test/integration/fixtures/options/file-beta.fixture.js @@ -0,0 +1,7 @@ +'use strict'; + +describe('beta', function () { + it('should be executed second', function () { + global.beta = 1; + }); +}); diff --git a/test/integration/helpers.js b/test/integration/helpers.js index ec50116920..09ca5deac9 100644 --- a/test/integration/helpers.js +++ b/test/integration/helpers.js @@ -129,7 +129,12 @@ module.exports = { * @param {Function} done - Callback * @param {string} cwd - Current working directory for mocha run, optional */ - invokeMocha: invokeMocha + invokeMocha: invokeMocha, + + /** + * Resolves the path to a fixture to the full path. + */ + resolveFixturePath: resolveFixturePath }; function invokeMocha (args, fn, cwd) { diff --git a/test/integration/options.spec.js b/test/integration/options.spec.js index e4ecc96cd6..573f4c8814 100644 --- a/test/integration/options.spec.js +++ b/test/integration/options.spec.js @@ -4,6 +4,7 @@ var path = require('path'); var assert = require('assert'); var run = require('./helpers').runMochaJSON; var directInvoke = require('./helpers').invokeMocha; +var resolvePath = require('./helpers').resolveFixturePath; var args = []; describe('options', function () { @@ -91,6 +92,29 @@ describe('options', function () { }); }); + describe.only('--file', function () { + before(function () { + args = ['--file', resolvePath('options/file-alpha.fixture.js')]; + }); + + it('should run tests passed via file first', function (done) { + run('options/file-beta.fixture.js', args, function (err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.stats.pending, 0); + assert.equal(res.stats.passes, 2); + assert.equal(res.stats.failures, 0); + + assert.equal(res.passes[0].fullTitle, + 'alpha should be executed first'); + assert.equal(res.code, 0); + done(); + }); + }); + }); + describe('--delay', function () { before(function () { args = ['--delay']; From 666e5f0d0d17fc6b5c897d973d70c60f2351cd11 Mon Sep 17 00:00:00 2001 From: Harry Wolff Date: Wed, 3 Jan 2018 22:45:07 -0500 Subject: [PATCH 2/4] revert markdown changes --- docs/index.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/index.md b/docs/index.md index b3ddd690c4..4ff1bf663e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,17 +25,17 @@ Mocha is a feature-rich JavaScript test framework running on [Node.js](https://n - [maps uncaught exceptions to the correct test case](#browser-specific-methods) - [async test timeout support](#delayed-root-suite) - [test retry support](#retry-tests) -- [test-specific timeouts](#test-level) +- [test-specific timeouts](#test-level) - [growl notification support](#mochaopts) - [reports test durations](#test-duration) - [highlights slow tests](#dot-matrix) -- [file watcher support](#min) -- [global variable leak detection](#--check-leaks) -- [optionally run tests that match a regexp](#-g---grep-pattern) +- [file watcher support](#min) +- [global variable leak detection](#--check-leaks) +- [optionally run tests that match a regexp](#-g---grep-pattern) - [auto-exit to prevent "hanging" with an active loop](#--exit----no-exit) - [easily meta-generate suites](#markdown) & [test-cases](#list) - [mocha.opts file support](#mochaopts) -- clickable suite titles to filter test execution +- clickable suite titles to filter test execution - [node debugger support](#-d---debug) - detects multiple calls to `done()` - [use any assertion library you want](#assertions) @@ -297,7 +297,7 @@ describe('hooks', function() { }); ``` -> Tests can appear before, after, or interspersed with your hooks. Hooks will run in the order they are defined, as appropriate; all `before()` hooks run (once), then any `beforeEach()` hooks, tests, any `afterEach()` hooks, and finally `after()` hooks (once). +> Tests can appear before, after, or interspersed with your hooks. Hooks will run in the order they are defined, as appropriate; all `before()` hooks run (once), then any `beforeEach()` hooks, tests, any `afterEach()` hooks, and finally `after()` hooks (once). ### Describing Hooks @@ -529,9 +529,9 @@ it('should only test in the correct environment', function() { }); ``` -The above test will be reported as [pending](#pending-tests). It's also important to note that calling `this.skip()` will effectively *abort* the test. +The above test will be reported as [pending](#pending-tests). It's also important to note that calling `this.skip()` will effectively *abort* the test. -> *Best practice*: To avoid confusion, do not execute further instructions in a test or hook after calling `this.skip()`. +> *Best practice*: To avoid confusion, do not execute further instructions in a test or hook after calling `this.skip()`. Contrast the above test with the following code: @@ -736,7 +736,6 @@ Mocha supports the `err.expected` and `err.actual` properties of any thrown `Ass --debug-brk enable node's debugger breaking on the first line --globals allow the given comma-delimited global [names] --es_staging enable all staged features - --file include a file to be ran during the suite [file] --harmony<_classes,_generators,...> all node --harmony* flags are available --preserve-symlinks Instructs the module loader to preserve symbolic links when resolving and caching modules --icu-data-dir include ICU data From 3ba35d67a018d80fd13014e4ceeb19d88a1f59c0 Mon Sep 17 00:00:00 2001 From: Harry Wolff Date: Wed, 3 Jan 2018 23:29:17 -0500 Subject: [PATCH 3/4] PR Feedback --- bin/_mocha | 24 ++++++++----------- docs/index.md | 21 +++++++++------- .../fixtures/options/file-alpha.fixture.js | 2 +- test/integration/options.spec.js | 11 +++++---- 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/bin/_mocha b/bin/_mocha index 9212b56e87..26607f452a 100755 --- a/bin/_mocha +++ b/bin/_mocha @@ -78,6 +78,14 @@ const exit = code => { */ const list = str => str.split(/ *, */); +/** + * Parse multiple flag. + */ +const collect = (val, memo) => { + memo.push(val); + return memo; +}; + /** * Hide the cursor. */ @@ -120,12 +128,6 @@ const play = (arr, interval) => { let files = []; -/** - * File args. - */ - -let fileArgs = []; - /** * Globals. */ @@ -206,7 +208,7 @@ program .option('--allow-uncaught', 'enable uncaught errors to propagate') .option('--forbid-only', 'causes test marked with only to fail the suite') .option('--forbid-pending', 'causes pending tests and test marked with skip to fail the suite') - .option('--file ', 'include a file to be ran during the suite', list, []); + .option('--file [file]', 'include a file to be ran during the suite', collect, []); program._name = 'mocha'; @@ -278,12 +280,6 @@ program.on('option:require', mod => { requires.push(mod); }); -// --file - -program.on('option:file', mod => { - fileArgs.push(mod); -}); - // If not already done, load mocha.opts if (!process.env.LOADED_MOCHA_OPTS) { getOptions(); @@ -510,7 +506,7 @@ if (!files.length) { } // resolve -fileArgs = fileArgs.map(path => resolve(path)); +let fileArgs = program.file.map(path => resolve(path)); files = files.map(path => resolve(path)); if (program.sort) { diff --git a/docs/index.md b/docs/index.md index 4ff1bf663e..5e7f7c6c58 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,17 +25,17 @@ Mocha is a feature-rich JavaScript test framework running on [Node.js](https://n - [maps uncaught exceptions to the correct test case](#browser-specific-methods) - [async test timeout support](#delayed-root-suite) - [test retry support](#retry-tests) -- [test-specific timeouts](#test-level) +- [test-specific timeouts](#test-level) - [growl notification support](#mochaopts) - [reports test durations](#test-duration) - [highlights slow tests](#dot-matrix) -- [file watcher support](#min) -- [global variable leak detection](#--check-leaks) -- [optionally run tests that match a regexp](#-g---grep-pattern) +- [file watcher support](#min) +- [global variable leak detection](#--check-leaks) +- [optionally run tests that match a regexp](#-g---grep-pattern) - [auto-exit to prevent "hanging" with an active loop](#--exit----no-exit) - [easily meta-generate suites](#markdown) & [test-cases](#list) - [mocha.opts file support](#mochaopts) -- clickable suite titles to filter test execution +- clickable suite titles to filter test execution - [node debugger support](#-d---debug) - detects multiple calls to `done()` - [use any assertion library you want](#assertions) @@ -297,7 +297,7 @@ describe('hooks', function() { }); ``` -> Tests can appear before, after, or interspersed with your hooks. Hooks will run in the order they are defined, as appropriate; all `before()` hooks run (once), then any `beforeEach()` hooks, tests, any `afterEach()` hooks, and finally `after()` hooks (once). +> Tests can appear before, after, or interspersed with your hooks. Hooks will run in the order they are defined, as appropriate; all `before()` hooks run (once), then any `beforeEach()` hooks, tests, any `afterEach()` hooks, and finally `after()` hooks (once). ### Describing Hooks @@ -529,9 +529,9 @@ it('should only test in the correct environment', function() { }); ``` -The above test will be reported as [pending](#pending-tests). It's also important to note that calling `this.skip()` will effectively *abort* the test. +The above test will be reported as [pending](#pending-tests). It's also important to note that calling `this.skip()` will effectively *abort* the test. -> *Best practice*: To avoid confusion, do not execute further instructions in a test or hook after calling `this.skip()`. +> *Best practice*: To avoid confusion, do not execute further instructions in a test or hook after calling `this.skip()`. Contrast the above test with the following code: @@ -736,6 +736,7 @@ Mocha supports the `err.expected` and `err.actual` properties of any thrown `Ass --debug-brk enable node's debugger breaking on the first line --globals allow the given comma-delimited global [names] --es_staging enable all staged features + --file include a file to be ran during the suite [file] --harmony<_classes,_generators,...> all node --harmony* flags are available --preserve-symlinks Instructs the module loader to preserve symbolic links when resolving and caching modules --icu-data-dir include ICU data @@ -849,6 +850,10 @@ Specifies the test-case timeout, defaulting to 2 seconds. To override you may pa Specify the "slow" test threshold, defaulting to 75ms. Mocha uses this to highlight test-cases that are taking too long. +### `--file ` + +Add a file you want included first in a test suite. This is useful if you have some generic setup code that must be included within the test suite. The file passed is not effected by any other flags (`--recursive` or `--sort` have no effect). Accepts multiple `--file` flags to include multiple files. + ### `-g, --grep ` The `--grep` option when specified will trigger mocha to only run tests matching the given `pattern` which is internally compiled to a `RegExp`. diff --git a/test/integration/fixtures/options/file-alpha.fixture.js b/test/integration/fixtures/options/file-alpha.fixture.js index dd74303163..0792429604 100644 --- a/test/integration/fixtures/options/file-alpha.fixture.js +++ b/test/integration/fixtures/options/file-alpha.fixture.js @@ -2,7 +2,7 @@ describe('alpha', function () { it('should be executed first', function () { - if (global.beta) { + if (global.beta !== undefined) { throw new Error('alpha was not executed first'); } }); diff --git a/test/integration/options.spec.js b/test/integration/options.spec.js index 573f4c8814..c19b7af388 100644 --- a/test/integration/options.spec.js +++ b/test/integration/options.spec.js @@ -2,9 +2,10 @@ var path = require('path'); var assert = require('assert'); -var run = require('./helpers').runMochaJSON; -var directInvoke = require('./helpers').invokeMocha; -var resolvePath = require('./helpers').resolveFixturePath; +var helpers = require('./helpers'); +var run = helpers.runMochaJSON; +var directInvoke = helpers.invokeMocha; +var resolvePath = helpers.resolveFixturePath; var args = []; describe('options', function () { @@ -92,8 +93,8 @@ describe('options', function () { }); }); - describe.only('--file', function () { - before(function () { + describe('--file', function () { + beforeEach(function () { args = ['--file', resolvePath('options/file-alpha.fixture.js')]; }); From 0008924235c7580b857d35e719d17a617a704c57 Mon Sep 17 00:00:00 2001 From: Harry Wolff Date: Thu, 4 Jan 2018 20:44:03 -0500 Subject: [PATCH 4/4] PR Feedback --- bin/_mocha | 7 ++--- docs/index.md | 2 +- .../fixtures/options/file-alpha.fixture.js | 4 +++ .../fixtures/options/file-beta.fixture.js | 4 +++ .../fixtures/options/file-theta.fixture.js | 7 +++++ test/integration/options.spec.js | 30 +++++++++++++++++-- 6 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 test/integration/fixtures/options/file-theta.fixture.js diff --git a/bin/_mocha b/bin/_mocha index 26607f452a..3802e70b79 100755 --- a/bin/_mocha +++ b/bin/_mocha @@ -81,10 +81,7 @@ const list = str => str.split(/ *, */); /** * Parse multiple flag. */ -const collect = (val, memo) => { - memo.push(val); - return memo; -}; +const collect = (val, memo) => memo.concat(val); /** * Hide the cursor. @@ -208,7 +205,7 @@ program .option('--allow-uncaught', 'enable uncaught errors to propagate') .option('--forbid-only', 'causes test marked with only to fail the suite') .option('--forbid-pending', 'causes pending tests and test marked with skip to fail the suite') - .option('--file [file]', 'include a file to be ran during the suite', collect, []); + .option('--file ', 'include a file to be ran during the suite', collect, []); program._name = 'mocha'; diff --git a/docs/index.md b/docs/index.md index 5e7f7c6c58..113a84d7a2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -852,7 +852,7 @@ Specify the "slow" test threshold, defaulting to 75ms. Mocha uses this to highli ### `--file ` -Add a file you want included first in a test suite. This is useful if you have some generic setup code that must be included within the test suite. The file passed is not effected by any other flags (`--recursive` or `--sort` have no effect). Accepts multiple `--file` flags to include multiple files. +Add a file you want included first in a test suite. This is useful if you have some generic setup code that must be included within the test suite. The file passed is not affected by any other flags (`--recursive` or `--sort` have no effect). Accepts multiple `--file` flags to include multiple files, the order in which the flags are given are the order in which the files are included in the test suite. Can also be used in `mocha.opts`. ### `-g, --grep ` diff --git a/test/integration/fixtures/options/file-alpha.fixture.js b/test/integration/fixtures/options/file-alpha.fixture.js index 0792429604..100d49aeb1 100644 --- a/test/integration/fixtures/options/file-alpha.fixture.js +++ b/test/integration/fixtures/options/file-alpha.fixture.js @@ -5,5 +5,9 @@ describe('alpha', function () { if (global.beta !== undefined) { throw new Error('alpha was not executed first'); } + + if (global.theta !== undefined) { + throw new Error('alpha was not executed first'); + } }); }); diff --git a/test/integration/fixtures/options/file-beta.fixture.js b/test/integration/fixtures/options/file-beta.fixture.js index 56da4a6523..ce5dc3c0a8 100644 --- a/test/integration/fixtures/options/file-beta.fixture.js +++ b/test/integration/fixtures/options/file-beta.fixture.js @@ -3,5 +3,9 @@ describe('beta', function () { it('should be executed second', function () { global.beta = 1; + + if (global.theta !== undefined) { + throw new Error('beta was not executed second'); + } }); }); diff --git a/test/integration/fixtures/options/file-theta.fixture.js b/test/integration/fixtures/options/file-theta.fixture.js new file mode 100644 index 0000000000..9d5c7d8c96 --- /dev/null +++ b/test/integration/fixtures/options/file-theta.fixture.js @@ -0,0 +1,7 @@ +'use strict'; + +describe('theta', function () { + it('should be executed third', function () { + global.theta = 1; + }); +}); diff --git a/test/integration/options.spec.js b/test/integration/options.spec.js index c19b7af388..607af6083b 100644 --- a/test/integration/options.spec.js +++ b/test/integration/options.spec.js @@ -94,11 +94,9 @@ describe('options', function () { }); describe('--file', function () { - beforeEach(function () { + it('should run tests passed via file first', function (done) { args = ['--file', resolvePath('options/file-alpha.fixture.js')]; - }); - it('should run tests passed via file first', function (done) { run('options/file-beta.fixture.js', args, function (err, res) { if (err) { done(err); @@ -114,6 +112,32 @@ describe('options', function () { done(); }); }); + + it('should run multiple tests passed via file first', function (done) { + args = [ + '--file', resolvePath('options/file-alpha.fixture.js'), + '--file', resolvePath('options/file-beta.fixture.js') + ]; + + run('options/file-theta.fixture.js', args, function (err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.stats.pending, 0); + assert.equal(res.stats.passes, 3); + assert.equal(res.stats.failures, 0); + + assert.equal(res.passes[0].fullTitle, + 'alpha should be executed first'); + assert.equal(res.passes[1].fullTitle, + 'beta should be executed second'); + assert.equal(res.passes[2].fullTitle, + 'theta should be executed third'); + assert.equal(res.code, 0); + done(); + }); + }); }); describe('--delay', function () {