From 4a2ed2d1dba67fad76b7f1fac3f4c26bd26158df Mon Sep 17 00:00:00 2001 From: Thomas Scholtes Date: Sat, 15 Jun 2019 16:34:28 +0200 Subject: [PATCH] Collect test files later This commit prepares improvements to the watch mode behavior. In the future we want Mocha in watch mode to pick up new test files. This requires that the test files are collected inside `watchRun` instead of before. To accomplish this change we rename `handleFiles` to `collectFiles` and move it to its own module. Instead of calling `collectFiles` in `lib/cli/run` and passing the files on to `watchRun` or `singleRun` we pass down the file collection parameters through `runMocha` and call `collectFiles` in both `watchRun` and `singleRun`. --- lib/cli/collect-files.js | 84 +++++++++++++++++++++++++ lib/cli/run-helpers.js | 130 ++++++++++----------------------------- lib/cli/run.js | 6 +- lib/cli/watch-run.js | 11 ++-- 4 files changed, 126 insertions(+), 105 deletions(-) create mode 100644 lib/cli/collect-files.js diff --git a/lib/cli/collect-files.js b/lib/cli/collect-files.js new file mode 100644 index 0000000000..ff35ed3d36 --- /dev/null +++ b/lib/cli/collect-files.js @@ -0,0 +1,84 @@ +'use strict'; + +const path = require('path'); +const ansi = require('ansi-colors'); +const debug = require('debug')('mocha:cli:run:helpers'); +const minimatch = require('minimatch'); +const utils = require('../utils'); + +/** + * Exports a function that collects test files from CLI parameters. + * @see module:lib/cli/run-helpers + * @see module:lib/cli/watch-run + * @module + * @private + */ + +/** + * Smash together an array of test files in the correct order + * @param {Object} opts - Options + * @param {string[]} opts.extension - File extensions to use + * @param {string[]} opts.spec - Files, dirs, globs to run + * @param {string[]} opts.ignore - Files, dirs, globs to ignore + * @param {string[]} opts.file - List of additional files to include + * @param {boolean} opts.recursive - Find files recursively + * @param {boolean} opts.sort - Sort test files + * @returns {string[]} List of files to test + * @private + */ +module.exports = ({ignore, extension, file, recursive, sort, spec} = {}) => { + let files = []; + const unmatched = []; + spec.forEach(arg => { + let newFiles; + try { + newFiles = utils.lookupFiles(arg, extension, recursive); + } catch (err) { + if (err.code === 'ERR_MOCHA_NO_FILES_MATCH_PATTERN') { + unmatched.push({message: err.message, pattern: err.pattern}); + return; + } + + throw err; + } + + if (typeof newFiles !== 'undefined') { + if (typeof newFiles === 'string') { + newFiles = [newFiles]; + } + newFiles = newFiles.filter(fileName => + ignore.every(pattern => !minimatch(fileName, pattern)) + ); + } + + files = files.concat(newFiles); + }); + + if (!files.length) { + // give full message details when only 1 file is missing + const noneFoundMsg = + unmatched.length === 1 + ? `Error: No test files found: ${JSON.stringify(unmatched[0].pattern)}` // stringify to print escaped characters raw + : 'Error: No test files found'; + console.error(ansi.red(noneFoundMsg)); + process.exit(1); + } else { + // print messages as an warning + unmatched.forEach(warning => { + console.warn(ansi.yellow(`Warning: ${warning.message}`)); + }); + } + + const fileArgs = file.map(filepath => path.resolve(filepath)); + files = files.map(filepath => path.resolve(filepath)); + + // ensure we don't sort the stuff from fileArgs; order is important! + if (sort) { + files.sort(); + } + + // add files given through --file to be ran first + files = fileArgs.concat(files); + debug('files (in order): ', files); + return files; +}; diff --git a/lib/cli/run-helpers.js b/lib/cli/run-helpers.js index a3848598f9..fce5e6250c 100644 --- a/lib/cli/run-helpers.js +++ b/lib/cli/run-helpers.js @@ -9,11 +9,9 @@ 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 utils = require('../utils'); const watchRun = require('./watch-run'); +const collectFiles = require('./collect-files'); const cwd = (exports.cwd = process.cwd()); @@ -94,90 +92,18 @@ exports.handleRequires = (requires = []) => { }; /** - * Smash together an array of test files in the correct order - * @param {Object} [opts] - Options - * @param {string[]} [opts.extension] - File extensions to use - * @param {string[]} [opts.spec] - Files, dirs, globs to run - * @param {string[]} [opts.ignore] - Files, dirs, globs to ignore - * @param {boolean} [opts.recursive=false] - Find files recursively - * @param {boolean} [opts.sort=false] - Sort test files - * @returns {string[]} List of files to test - * @private - */ -exports.handleFiles = ({ - ignore = [], - extension = [], - file = [], - recursive = false, - sort = false, - spec = [] -} = {}) => { - let files = []; - const unmatched = []; - spec.forEach(arg => { - let newFiles; - try { - newFiles = utils.lookupFiles(arg, extension, recursive); - } catch (err) { - if (err.code === 'ERR_MOCHA_NO_FILES_MATCH_PATTERN') { - unmatched.push({message: err.message, pattern: err.pattern}); - return; - } - - throw err; - } - - if (typeof newFiles !== 'undefined') { - if (typeof newFiles === 'string') { - newFiles = [newFiles]; - } - newFiles = newFiles.filter(fileName => - ignore.every(pattern => !minimatch(fileName, pattern)) - ); - } - - files = files.concat(newFiles); - }); - - if (!files.length) { - // give full message details when only 1 file is missing - const noneFoundMsg = - unmatched.length === 1 - ? `Error: No test files found: ${JSON.stringify(unmatched[0].pattern)}` // stringify to print escaped characters raw - : 'Error: No test files found'; - console.error(ansi.red(noneFoundMsg)); - process.exit(1); - } else { - // print messages as an warning - unmatched.forEach(warning => { - console.warn(ansi.yellow(`Warning: ${warning.message}`)); - }); - } - - const fileArgs = file.map(filepath => path.resolve(filepath)); - files = files.map(filepath => path.resolve(filepath)); - - // ensure we don't sort the stuff from fileArgs; order is important! - if (sort) { - files.sort(); - } - - // add files given through --file to be ran first - files = fileArgs.concat(files); - debug('files (in order): ', files); - return files; -}; - -/** - * Give Mocha files and tell it to run + * Collect test files and run mocha instance. * @param {Mocha} mocha - Mocha instance - * @param {Options} [opts] - Options - * @param {string[]} [opts.files] - List of test files + * @param {Options} [opts] - Command line options * @param {boolean} [opts.exit] - Whether or not to force-exit after tests are complete + * @param {Object} fileCollectParams - Parameters that control test + * file collection. See `lib/cli/collect-files.js`. * @returns {Runner} * @private */ -exports.singleRun = (mocha, {files = [], exit = false} = {}) => { +exports.singleRun = (mocha, {exit}, fileCollectParams) => { + const files = collectFiles(fileCollectParams); + debug('running tests with files', files); mocha.files = files; return mocha.run(exit ? exitMocha : exitMochaLater); }; @@ -185,24 +111,36 @@ exports.singleRun = (mocha, {files = [], exit = false} = {}) => { /** * Actually run tests * @param {Mocha} mocha - Mocha instance - * @param {Object} [opts] - Options - * @param {boolean} [opts.watch=false] - Enable watch mode - * @param {string[]} [opts.extension] - List of extensions to watch - * @param {string|RegExp} [opts.grep] - Grep for test titles - * @param {string} [opts.ui=bdd] - User interface - * @param {boolean} [opts.exit=false] - Force-exit Mocha when tests done - * @param {string[]} [files] - Array of test files + * @param {Object} opts - Command line options * @private */ -exports.runMocha = ( - mocha, - {watch = false, extension = [], grep = '', ui = 'bdd', exit = false} = {}, - files = [] -) => { +exports.runMocha = (mocha, options) => { + const { + watch = false, + extension = [], + grep = '', + ui = 'bdd', + exit = false, + ignore = [], + file = [], + recursive = false, + sort = false, + spec = [] + } = options; + + const fileCollectParams = { + ignore, + extension, + file, + recursive, + sort, + spec + }; + if (watch) { - watchRun(mocha, {extension, grep, ui, files}); + watchRun(mocha, {ui, grep}, fileCollectParams); } else { - exports.singleRun(mocha, {files, exit}); + exports.singleRun(mocha, {exit}, fileCollectParams); } }; diff --git a/lib/cli/run.js b/lib/cli/run.js index da5ffd7b6a..bb7c021998 100644 --- a/lib/cli/run.js +++ b/lib/cli/run.js @@ -16,7 +16,6 @@ const { const { list, - handleFiles, handleRequires, validatePlugin, runMocha @@ -290,8 +289,5 @@ exports.builder = yargs => exports.handler = argv => { debug('post-yargs config', argv); const mocha = new Mocha(argv); - const files = handleFiles(argv); - - debug('running tests with files', files); - runMocha(mocha, argv, files); + runMocha(mocha, argv); }; diff --git a/lib/cli/watch-run.js b/lib/cli/watch-run.js index 54765b7cf7..10d4407673 100644 --- a/lib/cli/watch-run.js +++ b/lib/cli/watch-run.js @@ -3,6 +3,7 @@ const utils = require('../utils'); const Context = require('../context'); const Mocha = require('../mocha'); +const collectFiles = require('./collect-files'); /** * Exports the `watchRun` function that runs mocha in "watch" mode. @@ -15,14 +16,16 @@ const Mocha = require('../mocha'); * Run Mocha in "watch" mode * @param {Mocha} mocha - Mocha instance * @param {Object} opts - Options - * @param {string[]} opts.extension - List of extensions to watch * @param {string|RegExp} opts.grep - Grep for test titles * @param {string} opts.ui - User interface - * @param {string[]} opts.files - Array of test files + * @param {Object} fileCollectParams - Parameters that control test + * file collection. See `lib/cli/collect-files.js`. + * @param {string[]} fileCollectParams.extension - List of extensions to watch * @private */ -module.exports = (mocha, {extension, grep, ui, files}) => { +module.exports = (mocha, {grep, ui}, fileCollectParams) => { let runner; + const files = collectFiles(fileCollectParams); console.log(); hideCursor(); @@ -34,7 +37,7 @@ module.exports = (mocha, {extension, grep, ui, files}) => { process.exit(128 + 2); }); - const watchFiles = utils.files(process.cwd(), extension); + const watchFiles = utils.files(process.cwd(), fileCollectParams.extension); let runAgain = false; const loadAndRun = () => {