From 10fa3a1db271bf5601faa8c12f51596a8832a89e Mon Sep 17 00:00:00 2001 From: Paul Roebuck Date: Wed, 13 Feb 2019 11:59:23 -0600 Subject: [PATCH 1/3] 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/3] 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/3] 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: {}};