Skip to content

Commit

Permalink
watch improvements and refactors
Browse files Browse the repository at this point in the history
- print "waiting" msg to stderr (_should_ be ok)
- add "cleaning up" message upon ctrl-c
- remove needless `afterRun`  option from various places
- only run teardown fixtures if they exist
- add win32 fix for testing
- add `Mocha#hasGlobalSetupFixtures()` and `Mocha#hasGlobalTeardownFixtures()`
  • Loading branch information
boneskull committed Jul 17, 2020
1 parent 4617e48 commit fae370f
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 39 deletions.
68 changes: 36 additions & 32 deletions lib/cli/watch-run.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

const logSymbols = require('log-symbols');
const debug = require('debug')('mocha:cli:watch');
const path = require('path');
const chokidar = require('chokidar');
Expand Down Expand Up @@ -65,9 +66,6 @@ exports.watchParallelRun = (
newMocha.lazyLoadFiles(true);
return newMocha;
},
afterRun({watcher}) {
blastCache(watcher);
},
fileCollectParams
});
};
Expand Down Expand Up @@ -120,9 +118,6 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {

return newMocha;
},
afterRun({watcher}) {
blastCache(watcher);
},
fileCollectParams
});
};
Expand All @@ -133,7 +128,6 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
* @param {Object} opts
* @param {BeforeWatchRun} [opts.beforeRun] - Function to call before
* `mocha.run()`
* @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
* @param {string[]} [opts.watchFiles] - List of paths and patterns to watch. If
* not provided all files with an extension included in
* `fileColletionParams.extension` are watched. See first argument of
Expand All @@ -147,7 +141,7 @@ exports.watchRun = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
*/
const createWatcher = (
mocha,
{watchFiles, watchIgnore, beforeRun, afterRun, fileCollectParams}
{watchFiles, watchIgnore, beforeRun, fileCollectParams}
) => {
if (!watchFiles) {
watchFiles = fileCollectParams.extension.map(ext => `**/*.${ext}`);
Expand All @@ -165,13 +159,12 @@ const createWatcher = (
});

const rerunner = createRerunner(mocha, watcher, {
beforeRun,
afterRun
beforeRun
});

watcher.on('ready', async () => {
if (!globalFixtureContext) {
debug('running global setup');
debug('triggering global setup');
globalFixtureContext = await mocha.runGlobalSetup();
}
rerunner.run();
Expand All @@ -185,16 +178,37 @@ const createWatcher = (
process.on('exit', () => {
showCursor();
});

// this is for testing.
// win32 cannot gracefully shutdown via a signal from a parent
// process; a `SIGINT` from a parent will cause the process
// to immediately exit. during normal course of operation, a user
// will type Ctrl-C and the listener will be invoked, but this
// is not possible in automated testing.
// there may be another way to solve this, but it too will be a hack.
// for our watch tests on win32 we must _fork_ mocha with an IPC channel
if (process.connected) {
process.on('message', msg => {
if (msg === 'SIGINT') {
process.emit('SIGINT');
}
});
}

let exiting = false;
process.on('SIGINT', async () => {
showCursor();
console.log('\n');

debug('running global teardown');
try {
await mocha.runGlobalTeardown(globalFixtureContext);
} catch (err) {
console.error(err);
} finally {
console.error(`${logSymbols.warning} [mocha] cleaning up, please wait...`);
if (!exiting) {
exiting = true;
if (mocha.hasGlobalTeardownFixtures()) {
debug('running global teardown');
try {
await mocha.runGlobalTeardown(globalFixtureContext);
} catch (err) {
console.error(err);
}
}
process.exit(130);
}
});
Expand All @@ -220,12 +234,11 @@ const createWatcher = (
* @param {FSWatcher} watcher - chokidar `FSWatcher` instance
* @param {Object} [opts] - Options!
* @param {BeforeWatchRun} [opts.beforeRun] - Function to call before `mocha.run()`
* @param {AfterWatchRun} [opts.afterRun] - Function to call after `mocha.run()`
* @returns {Rerunner}
* @ignore
* @private
*/
const createRerunner = (mocha, watcher, {beforeRun, afterRun} = {}) => {
const createRerunner = (mocha, watcher, {beforeRun} = {}) => {
// Set to a `Runner` when mocha is running. Set to `null` when mocha is not
// running.
let runner = null;
Expand All @@ -238,11 +251,11 @@ const createRerunner = (mocha, watcher, {beforeRun, afterRun} = {}) => {
runner = mocha.run(() => {
debug('finished watch run');
runner = null;
mocha = afterRun ? afterRun({mocha, watcher}) || mocha : mocha;
blastCache(watcher);
if (rerunScheduled) {
rerun();
} else {
debug('waiting for changes...');
console.error(`${logSymbols.info} [mocha] waiting for changes...`);
}
});
};
Expand Down Expand Up @@ -340,15 +353,6 @@ const blastCache = watcher => {
* @returns {Mocha}
*/

/**
* Callback to be run after `mocha.run()` completes. Typically used to clear
* require cache.
* @callback AfterWatchRun
* @private
* @param {{mocha: Mocha, watcher: FSWatcher}} options
* @returns {void}
*/

/**
* Object containing run control methods
* @typedef {Object} Rerunner
Expand Down
33 changes: 26 additions & 7 deletions lib/mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -972,9 +972,7 @@ Mocha.prototype.run = function(fn) {
options.files = this.files;
var runner = new this._runnerClass(suite, {
delay: options.delay,
cleanReferencesAfterRun: this._cleanReferencesAfterRun,
globalSetup: options.globalSetup,
globalTeardown: options.globalTeardown
cleanReferencesAfterRun: this._cleanReferencesAfterRun
});
createStatsCollector(runner);
var reporter = new this._reporter(runner, options);
Expand Down Expand Up @@ -1015,13 +1013,16 @@ Mocha.prototype.run = function(fn) {
}

(async () => {
if (this.options.enableGlobalSetup) {
debug('running global setup');
if (this.options.enableGlobalSetup && this.hasGlobalSetupFixtures()) {
debug('run(): running global setup');
const context = await this.runGlobalSetup(runner);
runner.run(
async failures => {
if (this.options.enableGlobalTeardown) {
debug('running global teardown');
if (
this.options.enableGlobalTeardown &&
this.hasGlobalTeardownFixtures()
) {
debug('run(): running global teardown');
await this.runGlobalTeardown(runner, {context});
}
done(failures);
Expand Down Expand Up @@ -1240,6 +1241,24 @@ Mocha.prototype.enableGlobalTeardown = function enableGlobalTeardown(
return this;
};

/**
* Returns `true` if one or more global setup fixtures have been supplied.
* @public
* @returns {boolean}
*/
Mocha.prototype.hasGlobalSetupFixtures = function hasGlobalSetupFixtures() {
return Boolean(this.options.globalSetup.length);
};

/**
* Returns `true` if one or more global teardown fixtures have been supplied.
* @public
* @returns {boolean}
*/
Mocha.prototype.hasGlobalTeardownFixtures = function hasGlobalTeardownFixtures() {
return Boolean(this.options.globalTeardown.length);
};

/**
* An alternative way to define root hooks that works with parallel runs.
* @typedef {Object} MochaRootHookObject
Expand Down

0 comments on commit fae370f

Please sign in to comment.