Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to unload files from require cache (redux) #3726

Merged
merged 7 commits into from Feb 14, 2019
4 changes: 1 addition & 3 deletions lib/cli/run-helpers.js
Expand Up @@ -249,9 +249,7 @@ exports.watchRun = (
};

const purge = () => {
watchFiles.forEach(file => {
delete require.cache[file];
});
watchFiles.forEach(mocha.unloadFile);
};

loadAndRun();
Expand Down
41 changes: 37 additions & 4 deletions lib/mocha.js
Expand Up @@ -301,7 +301,6 @@ Mocha.prototype.ui = function(name) {
};

/**
* @summary
* Loads `files` prior to execution.
*
* @description
Expand All @@ -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) {
Expand All @@ -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) {
plroebuck marked this conversation as resolved.
Show resolved Hide resolved
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.
*
* <strong>Not needed for (or used by) CLI.</strong>
plroebuck marked this conversation as resolved.
Show resolved Hide resolved
*
* @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.
*
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
52 changes: 52 additions & 0 deletions test/unit/mocha.spec.js
Expand Up @@ -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() {
plroebuck marked this conversation as resolved.
Show resolved Hide resolved
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: {}};
Expand Down