bigint-crypto-utils/node_modules/mocha/lib/cli/watch-run.js

192 lines
4.3 KiB
JavaScript
Raw Normal View History

'use strict';
const path = require('path');
const chokidar = require('chokidar');
const Context = require('../context');
const collectFiles = require('./collect-files');
/**
* Exports the `watchRun` function that runs mocha in "watch" mode.
* @see module:lib/cli/run-helpers
* @module
* @private
*/
/**
* Run Mocha in "watch" mode
* @param {Mocha} mocha - Mocha instance
* @param {Object} opts - Options
* @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
* `chokidar.watch`.
* @param {string[]} opts.watchIgnore - List of paths and patterns to
* exclude from watching. See `ignored` option of `chokidar`.
* @param {Object} fileCollectParams - Parameters that control test
* file collection. See `lib/cli/collect-files.js`.
* @param {string[]} fileCollectParams.extension - List of extensions
* to watch if `opts.watchFiles` is not given.
* @private
*/
module.exports = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
if (!watchFiles) {
watchFiles = fileCollectParams.extension.map(ext => `**/*.${ext}`);
}
const watcher = chokidar.watch(watchFiles, {
ignored: watchIgnore,
ignoreInitial: true
});
const rerunner = createRerunner(mocha, () => {
getWatchedFiles(watcher).forEach(file => {
delete require.cache[file];
});
mocha.files = collectFiles(fileCollectParams);
});
watcher.on('ready', () => {
rerunner.run();
});
watcher.on('all', () => {
rerunner.scheduleRun();
});
console.log();
hideCursor();
process.on('exit', () => {
showCursor();
});
process.on('SIGINT', () => {
showCursor();
console.log('\n');
process.exit(128 + 2);
});
// Keyboard shortcut for restarting when "rs\n" is typed (ala Nodemon)
process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data', data => {
const str = data
.toString()
.trim()
.toLowerCase();
if (str === 'rs') rerunner.scheduleRun();
});
};
/**
* Create an object that allows you to rerun tests on the mocha
* instance. `beforeRun` is called everytime before `mocha.run()` is
* called.
*
* @param {Mocha} mocha - Mocha instance
* @param {function} beforeRun - Called just before `mocha.run()`
*/
const createRerunner = (mocha, beforeRun) => {
// Set to a `Runner` when mocha is running. Set to `null` when mocha is not
// running.
let runner = null;
let rerunScheduled = false;
const run = () => {
try {
beforeRun();
resetMocha(mocha);
runner = mocha.run(() => {
runner = null;
if (rerunScheduled) {
rerun();
}
});
} catch (e) {
console.log(e.stack);
}
};
const scheduleRun = () => {
if (rerunScheduled) {
return;
}
rerunScheduled = true;
if (runner) {
runner.abort();
} else {
rerun();
}
};
const rerun = () => {
rerunScheduled = false;
eraseLine();
run();
};
return {
scheduleRun,
run
};
};
/**
* Return the list of absolute paths watched by a chokidar watcher.
*
* @param watcher - Instance of a chokidar watcher
* @return {string[]} - List of absolute paths
*/
const getWatchedFiles = watcher => {
const watchedDirs = watcher.getWatched();
let watchedFiles = [];
Object.keys(watchedDirs).forEach(dir => {
watchedFiles = watchedFiles.concat(
watchedDirs[dir].map(file => path.join(dir, file))
);
});
return watchedFiles;
};
/**
* Reset the internal state of the mocha instance so that tests can be rerun.
*
* @param {Mocha} mocha - Mocha instance
* @private
*/
const resetMocha = mocha => {
mocha.unloadFiles();
mocha.suite = mocha.suite.clone();
mocha.suite.ctx = new Context();
// Registers a callback on `mocha.suite` that wires new context to the DSL
// (e.g. `describe`) that is exposed as globals when the test files are
// reloaded.
mocha.ui(mocha.options.ui);
};
/**
* Hide the cursor.
* @ignore
* @private
*/
const hideCursor = () => {
process.stdout.write('\u001b[?25l');
};
/**
* Show the cursor.
* @ignore
* @private
*/
const showCursor = () => {
process.stdout.write('\u001b[?25h');
};
/**
* Erases the line on stdout
* @private
*/
const eraseLine = () => {
process.stdout.write('\u001b[2K');
};