From 10fa3a1db271bf5601faa8c12f51596a8832a89e Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 13 Feb 2019 11:59:23 -0600 Subject: [PATCH 1/7] feat(lib/mocha.js): Add ability to unload files Implements `Mocha.unloadFile` and `Mocha.unloadFiles`. --- lib/mocha.js | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/lib/mocha.js b/lib/mocha.js index 1537196167..727efa03be 100644 --- a/lib/mocha.js +++ b/lib/mocha.js @@ -301,7 +301,6 @@ Mocha.prototype.ui = function(name) { }; /** - * @summary * Loads `files` prior to execution. * * @description @@ -310,6 +309,8 @@ Mocha.prototype.ui = function(name) { * * @private * @see {@link Mocha#addFile} + * @see {@link Mocha#run} + * @see {@link Mocha#unloadFiles} * @param {Function} [fn] - Callback invoked upon completion. */ Mocha.prototype.loadFiles = function(fn) { @@ -324,6 +325,38 @@ Mocha.prototype.loadFiles = function(fn) { fn && fn(); }; +/** + * Removes a previously loaded file from Node's `require` cache. + * + * @private + * @see {@link Mocha#unloadFiles} + * @param {string} file - Pathname of file to be unloaded. + */ +Mocha.prototype.unloadFile = function(file) { + delete require.cache[require.resolve(file)]; +}; + +/** + * Unloads `files` from Node's `require` cache. + * + * @description + * This allows files to be "freshly" reloaded, providing the ability + * to reuse a Mocha instance programmatically. + * + * Not needed for (or used by) CLI. + * + * @public + * @see {@link Mocha#unloadFile} + * @see {@link Mocha#loadFiles} + * @see {@link Mocha#run} + * @returns {Mocha} this + * @chainable + */ +Mocha.prototype.unloadFiles = function() { + this.files.forEach(this.unloadFile, this); + return this; +}; + /** * Sets `grep` filter after escaping RegExp special characters. * @@ -741,8 +774,7 @@ Object.defineProperty(Mocha.prototype, 'version', { */ /** - * @summary - * Runs tests and invokes `fn()` when complete. + * Runs root suite and invokes `fn()` when complete. * * @description * To run tests multiple times (or to run tests in files that are @@ -751,6 +783,7 @@ Object.defineProperty(Mocha.prototype, 'version', { * * @public * @see {@link Mocha#loadFiles} + * @see {@link Mocha#unloadFiles} * @see {@link Runner#run} * @param {DoneCB} [fn] - Callback invoked when test execution completed. * @return {Runner} runner instance @@ -787,7 +820,7 @@ Mocha.prototype.run = function(fn) { exports.reporters.Base.hideDiff = options.hideDiff; function done(failures) { - fn = fn || function fn() {}; + fn = fn || utils.noop; if (reporter.done) { reporter.done(failures, fn); } else { From 5ca57618e75ab1cb76ceeed62d0daf2dc4cc3f67 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 13 Feb 2019 12:01:56 -0600 Subject: [PATCH 2/7] refactor(lib/cli/run-helpers.js): Use `Mocha.unloadFile` Eat our own dog food. --- lib/cli/run-helpers.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/cli/run-helpers.js b/lib/cli/run-helpers.js index d953a06909..aa6a310c8c 100644 --- a/lib/cli/run-helpers.js +++ b/lib/cli/run-helpers.js @@ -249,9 +249,7 @@ exports.watchRun = ( }; const purge = () => { - watchFiles.forEach(file => { - delete require.cache[file]; - }); + watchFiles.forEach(mocha.unloadFile); }; loadAndRun(); From 6160e90939afe5e71b106b1033b7af43da20a139 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 13 Feb 2019 13:18:04 -0600 Subject: [PATCH 3/7] test(unit/mocha.spec.js): Add feature tests --- test/unit/mocha.spec.js | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/unit/mocha.spec.js b/test/unit/mocha.spec.js index beb5e2b5e0..60c52ad81b 100644 --- a/test/unit/mocha.spec.js +++ b/test/unit/mocha.spec.js @@ -226,6 +226,58 @@ describe('Mocha', function() { }); }); + describe('.unloadFile()', function() { + before(function() { + if (process.browser) { + this.skip(); + } + }); + + it('should unload a specific file from cache', function() { + var mocha = new Mocha(opts); + var resolvedFilePath; + var filePath = __filename; + + mocha.addFile(filePath); + mocha.loadFiles(); + resolvedFilePath = require.resolve(filePath); + expect(require.cache, 'to have key', resolvedFilePath); + + mocha.unloadFile(filePath); + expect(require.cache, 'not to have key', resolvedFilePath); + }); + }); + + describe('.unloadFiles()', function() { + var path; + + before(function() { + if (process.browser) { + this.skip(); + } else { + path = require('path'); + } + }); + + it('should unload all test files from cache', function() { + var mocha = new Mocha(opts); + var resolvedTestFiles; + var testFiles = [ + __filename, + path.join(__dirname, 'throw.spec.js'), + path.join(__dirname, 'context.spec.js') + ]; + + testFiles.forEach(mocha.addFile, mocha); + mocha.loadFiles(); + resolvedTestFiles = testFiles.map(require.resolve); + expect(require.cache, 'to have keys', resolvedTestFiles); + + mocha.unloadFiles(); + expect(require.cache, 'not to have keys', resolvedTestFiles); + }); + }); + describe('error handling', function() { it('should throw reporter error if an invalid reporter is given', function() { var updatedOpts = {reporter: 'invalidReporter', reporterOptions: {}}; From b03cf1f42034730039a68167655495f8bb660b94 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Thu, 14 Feb 2019 03:00:31 -0600 Subject: [PATCH 4/7] refactor(lib/mocha.js): Convert `unloadFile` to static method --- lib/cli/run-helpers.js | 9 +++++---- lib/mocha.js | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/cli/run-helpers.js b/lib/cli/run-helpers.js index aa6a310c8c..89832083ed 100644 --- a/lib/cli/run-helpers.js +++ b/lib/cli/run-helpers.js @@ -8,12 +8,13 @@ */ const fs = require('fs'); +const path = require('path'); +const ansi = require('ansi-colors'); const debug = require('debug')('mocha:cli:run:helpers'); +const minimatch = require('minimatch'); const Context = require('../context'); -const path = require('path'); +const Mocha = require('../mocha'); const utils = require('../utils'); -const minimatch = require('minimatch'); -const ansi = require('ansi-colors'); const cwd = (exports.cwd = process.cwd()); @@ -249,7 +250,7 @@ exports.watchRun = ( }; const purge = () => { - watchFiles.forEach(mocha.unloadFile); + watchFiles.forEach(Mocha.unloadFile); }; loadAndRun(); diff --git a/lib/mocha.js b/lib/mocha.js index 727efa03be..9707f4c66d 100644 --- a/lib/mocha.js +++ b/lib/mocha.js @@ -329,10 +329,11 @@ Mocha.prototype.loadFiles = function(fn) { * Removes a previously loaded file from Node's `require` cache. * * @private + * @static * @see {@link Mocha#unloadFiles} * @param {string} file - Pathname of file to be unloaded. */ -Mocha.prototype.unloadFile = function(file) { +Mocha.unloadFile = function(file) { delete require.cache[require.resolve(file)]; }; @@ -343,17 +344,17 @@ Mocha.prototype.unloadFile = function(file) { * This allows files to be "freshly" reloaded, providing the ability * to reuse a Mocha instance programmatically. * - * Not needed for (or used by) CLI. + * Intended for consumers — not used internally * * @public - * @see {@link Mocha#unloadFile} + * @see {@link Mocha.unloadFile} * @see {@link Mocha#loadFiles} * @see {@link Mocha#run} * @returns {Mocha} this * @chainable */ Mocha.prototype.unloadFiles = function() { - this.files.forEach(this.unloadFile, this); + this.files.forEach(Mocha.unloadFile); return this; }; From 96694e4e812f1981c5bc18c5ead5cd2976bc9d7a Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Thu, 14 Feb 2019 03:47:20 -0600 Subject: [PATCH 5/7] test(node-unit/mocha.spec.js): Migrate tests from "unit" to "node-unit" --- test/node-unit/mocha.spec.js | 41 ++++++++++++++++++++++++++++ test/unit/mocha.spec.js | 52 ------------------------------------ 2 files changed, 41 insertions(+), 52 deletions(-) create mode 100644 test/node-unit/mocha.spec.js diff --git a/test/node-unit/mocha.spec.js b/test/node-unit/mocha.spec.js new file mode 100644 index 0000000000..336a67a7f9 --- /dev/null +++ b/test/node-unit/mocha.spec.js @@ -0,0 +1,41 @@ +'use strict'; + +const path = require('path'); +const Mocha = require('../../lib/mocha'); +const utils = require('../../lib/utils'); + +describe('Mocha', function() { + const opts = {reporter: utils.noop}; // no output + + describe('.unloadFile()', function() { + it('should unload a specific file from cache', function() { + const resolvedFilePath = require.resolve(__filename); + + require(__filename); + expect(require.cache, 'to have key', resolvedFilePath); + + Mocha.unloadFile(__filename); + expect(require.cache, 'not to have key', resolvedFilePath); + }); + }); + + describe('.unloadFiles()', function() { + it('should unload all test files from cache', function() { + const mocha = new Mocha(opts); + let resolvedTestFiles; + const testFiles = [ + __filename, + path.join(__dirname, 'cli', 'config.spec.js'), + path.join(__dirname, 'cli', 'run.spec.js') + ]; + + testFiles.forEach(mocha.addFile, mocha); + mocha.loadFiles(); + resolvedTestFiles = testFiles.map(require.resolve); + expect(require.cache, 'to have keys', resolvedTestFiles); + + mocha.unloadFiles(); + expect(require.cache, 'not to have keys', resolvedTestFiles); + }); + }); +}); diff --git a/test/unit/mocha.spec.js b/test/unit/mocha.spec.js index 60c52ad81b..beb5e2b5e0 100644 --- a/test/unit/mocha.spec.js +++ b/test/unit/mocha.spec.js @@ -226,58 +226,6 @@ describe('Mocha', function() { }); }); - describe('.unloadFile()', function() { - before(function() { - if (process.browser) { - this.skip(); - } - }); - - it('should unload a specific file from cache', function() { - var mocha = new Mocha(opts); - var resolvedFilePath; - var filePath = __filename; - - mocha.addFile(filePath); - mocha.loadFiles(); - resolvedFilePath = require.resolve(filePath); - expect(require.cache, 'to have key', resolvedFilePath); - - mocha.unloadFile(filePath); - expect(require.cache, 'not to have key', resolvedFilePath); - }); - }); - - describe('.unloadFiles()', function() { - var path; - - before(function() { - if (process.browser) { - this.skip(); - } else { - path = require('path'); - } - }); - - it('should unload all test files from cache', function() { - var mocha = new Mocha(opts); - var resolvedTestFiles; - var testFiles = [ - __filename, - path.join(__dirname, 'throw.spec.js'), - path.join(__dirname, 'context.spec.js') - ]; - - testFiles.forEach(mocha.addFile, mocha); - mocha.loadFiles(); - resolvedTestFiles = testFiles.map(require.resolve); - expect(require.cache, 'to have keys', resolvedTestFiles); - - mocha.unloadFiles(); - expect(require.cache, 'not to have keys', resolvedTestFiles); - }); - }); - describe('error handling', function() { it('should throw reporter error if an invalid reporter is given', function() { var updatedOpts = {reporter: 'invalidReporter', reporterOptions: {}}; From 43ec92213b0ce9dd25387b35fc48d0479aa7438d Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Thu, 14 Feb 2019 05:14:49 -0600 Subject: [PATCH 6/7] test(node-unit/mocha.spec.js): Refactor and beef up tests Migrated `Mocha#addFiles` here. Created `Mocha#loadFiles`. Added chainable tests where applicable. Refactored. --- test/node-unit/mocha.spec.js | 55 ++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/test/node-unit/mocha.spec.js b/test/node-unit/mocha.spec.js index 336a67a7f9..314a012023 100644 --- a/test/node-unit/mocha.spec.js +++ b/test/node-unit/mocha.spec.js @@ -6,11 +6,46 @@ const utils = require('../../lib/utils'); describe('Mocha', function() { const opts = {reporter: utils.noop}; // no output + const testFiles = [ + __filename, + path.join(__dirname, 'cli', 'config.spec.js'), + path.join(__dirname, 'cli', 'run.spec.js') + ]; + const resolvedTestFiles = testFiles.map(require.resolve); - describe('.unloadFile()', function() { + describe('#addFile', function() { + it('should add the given file to the files array', function() { + const mocha = new Mocha(opts); + mocha.addFile(__filename); + expect(mocha.files, 'to have length', 1).and('to contain', __filename); + }); + + it('should be chainable', function() { + const mocha = new Mocha(opts); + expect(mocha.addFile(__filename), 'to be', mocha); + }); + }); + + describe('#loadFiles', function() { + it('should load all files from the files array', function() { + const mocha = new Mocha(opts); + + testFiles.forEach(mocha.addFile, mocha); + mocha.loadFiles(); + expect(require.cache, 'to have keys', resolvedTestFiles); + }); + + it('should execute the optional callback if given', function() { + const mocha = new Mocha(opts); + expect(cb => { + mocha.loadFiles(cb); + }, 'to call the callback'); + }); + }); + + describe('.unloadFile', function() { it('should unload a specific file from cache', function() { const resolvedFilePath = require.resolve(__filename); - require(__filename); expect(require.cache, 'to have key', resolvedFilePath); @@ -19,23 +54,19 @@ describe('Mocha', function() { }); }); - describe('.unloadFiles()', function() { + describe('#unloadFiles', function() { it('should unload all test files from cache', function() { const mocha = new Mocha(opts); - let resolvedTestFiles; - const testFiles = [ - __filename, - path.join(__dirname, 'cli', 'config.spec.js'), - path.join(__dirname, 'cli', 'run.spec.js') - ]; testFiles.forEach(mocha.addFile, mocha); mocha.loadFiles(); - resolvedTestFiles = testFiles.map(require.resolve); - expect(require.cache, 'to have keys', resolvedTestFiles); - mocha.unloadFiles(); expect(require.cache, 'not to have keys', resolvedTestFiles); }); + + it('should be chainable', function() { + const mocha = new Mocha(opts); + expect(mocha.unloadFiles(), 'to be', mocha); + }); }); }); From cbef1e363510c2f4a28e8518017f7ed51d49c1b8 Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Thu, 14 Feb 2019 05:20:50 -0600 Subject: [PATCH 7/7] test(unit/mocha.spec.js): Add missing chainable tests Migrated `Mocha#addFile` to "node-unit". Added missing chainable tests for `Mocha#allowUncaught`, `Mocha#bail`, `Mocha#delay`, and `Mocha#noHighlighting`. --- test/unit/mocha.spec.js | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/test/unit/mocha.spec.js b/test/unit/mocha.spec.js index beb5e2b5e0..73c74f6b8b 100644 --- a/test/unit/mocha.spec.js +++ b/test/unit/mocha.spec.js @@ -21,6 +21,7 @@ describe('Mocha', function() { sandbox.stub(Mocha.prototype, 'useColors').returnsThis(); sandbox.stub(utils, 'deprecate'); }); + it('should prefer "color" over "useColors"', function() { // eslint-disable-next-line no-new new Mocha({useColors: true, color: false}); @@ -70,14 +71,6 @@ describe('Mocha', function() { }); }); - describe('.addFile()', function() { - it('should add the given file to the files array', function() { - var mocha = new Mocha(opts); - mocha.addFile('myFile.js'); - expect(mocha.files, 'to have length', 1).and('to contain', 'myFile.js'); - }); - }); - describe('.invert()', function() { it('should set the invert option to true', function() { var mocha = new Mocha(opts); @@ -153,6 +146,7 @@ describe('Mocha', function() { expect(mocha.options, 'to have property', 'growl', true); }); }); + describe('if not capable of notifications', function() { it('should set the growl option to false', function() { var mocha = new Mocha(opts); @@ -163,6 +157,7 @@ describe('Mocha', function() { expect(mocha.options, 'to have property', 'growl', false); }); }); + it('should be chainable', function() { var mocha = new Mocha(opts); expect(mocha.growl(), 'to be', mocha); @@ -195,11 +190,17 @@ describe('Mocha', function() { }); describe('.noHighlighting()', function() { + // :NOTE: Browser-only option... it('should set the noHighlighting option to true', function() { var mocha = new Mocha(opts); mocha.noHighlighting(); expect(mocha.options, 'to have property', 'noHighlighting', true); }); + + it('should be chainable', function() { + var mocha = new Mocha(opts); + expect(mocha.noHighlighting(), 'to be', mocha); + }); }); describe('.allowUncaught()', function() { @@ -208,6 +209,11 @@ describe('Mocha', function() { mocha.allowUncaught(); expect(mocha.options, 'to have property', 'allowUncaught', true); }); + + it('should be chainable', function() { + var mocha = new Mocha(opts); + expect(mocha.allowUncaught(), 'to be', mocha); + }); }); describe('.delay()', function() { @@ -216,6 +222,11 @@ describe('Mocha', function() { mocha.delay(); expect(mocha.options, 'to have property', 'delay', true); }); + + it('should be chainable', function() { + var mocha = new Mocha(opts); + expect(mocha.delay(), 'to be', mocha); + }); }); describe('.bail()', function() { @@ -224,6 +235,11 @@ describe('Mocha', function() { mocha.bail(); expect(mocha.suite._bail, 'to be', true); }); + + it('should be chainable', function() { + var mocha = new Mocha(opts); + expect(mocha.bail(), 'to be', mocha); + }); }); describe('error handling', function() {