From 9dc6cc4cae507385e26bd2ab2fa66c8b3ce48c69 Mon Sep 17 00:00:00 2001 From: Andy Niccolai Date: Fri, 19 Aug 2016 11:40:53 -0700 Subject: [PATCH 1/3] Add --watchAll option --- packages/jest-cli/src/cli/args.js | 20 +++++++++++++++----- packages/jest-cli/src/jest.js | 8 +++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/jest-cli/src/cli/args.js b/packages/jest-cli/src/cli/args.js index 13fb3a0e1e4d..81ea87692883 100644 --- a/packages/jest-cli/src/cli/args.js +++ b/packages/jest-cli/src/cli/args.js @@ -28,9 +28,11 @@ const check = (argv: Object) => { ); } - if (argv.watchExtensions && argv.watch === undefined) { + if (argv.onlyChanged && argv.watchAll) { throw new Error( - '--watchExtensions can only be specified together with --watch.', + 'Both --onlyChanged and --watchAll were specified, but these two ' + + 'options do not make sense together. Try the --watch option which ' + + 'reruns only tests related to changed files.', ); } @@ -148,10 +150,18 @@ const options = { watch: { description: wrap( 'Watch files for changes and rerun tests related to changed files. ' + - 'If you want to re-run all tests when a file has changed, you can ' + - 'call Jest using `--watch=all`.', + 'If you want to re-run all tests when a file has changed, use the ' + + '`--watchAll` option.', ), - type: 'string', + type: 'boolean', + }, + watchAll: { + description: wrap( + 'Watch files for changes and rerun all tests. If you want to re-run ' + + 'only the tests related to the changed files, use the ' + + '`--watch` option.', + ), + type: 'boolean', }, bail: { alias: 'b', diff --git a/packages/jest-cli/src/jest.js b/packages/jest-cli/src/jest.js index 77fbccb9f3e6..39fabab9e95b 100644 --- a/packages/jest-cli/src/jest.js +++ b/packages/jest-cli/src/jest.js @@ -51,7 +51,7 @@ function buildTestPathPatternInfo(argv) { return { lastCommit: argv.lastCommit, onlyChanged: true, - watch: argv.watch !== undefined, + watch: argv.watch, }; } if (argv.testPathPattern) { @@ -151,10 +151,8 @@ function runCLI(argv: Object, root: Path, onComplete: () => void) { pipe.write('test framework = ' + testFramework.name + '\n'); pipe.write('config = ' + JSON.stringify(config, null, ' ') + '\n'); } - if (argv.watch !== undefined) { - if (argv.watch !== 'all') { - argv.onlyChanged = true; - } + if (argv.watch || argv.watchAll) { + argv.onlyChanged = !argv.watchAll; return new Promise(resolve => { getWatcher(config, root, watcher => { From 2e734c1185500a9b9ce52eab7eb4a2082e08aa98 Mon Sep 17 00:00:00 2001 From: Andy Niccolai Date: Fri, 19 Aug 2016 12:05:23 -0700 Subject: [PATCH 2/3] Run tests immediately on start up when using --watch or --watchAll --- packages/jest-cli/src/jest.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/jest-cli/src/jest.js b/packages/jest-cli/src/jest.js index 39fabab9e95b..fa6b9ddfc093 100644 --- a/packages/jest-cli/src/jest.js +++ b/packages/jest-cli/src/jest.js @@ -158,8 +158,18 @@ function runCLI(argv: Object, root: Path, onComplete: () => void) { getWatcher(config, root, watcher => { let timer; let isRunning; + const startRun = () => { + isRunning = true; + runJest(config, argv, pipe, () => isRunning = false) + .then( + resolve, + error => console.error(chalk.red(error)), + ); + }; pipe.write(CLEAR); + startRun(); + watcher.on('all', (_, filePath) => { pipe.write(CLEAR); filePath = path.join(root, filePath); @@ -170,17 +180,7 @@ function runCLI(argv: Object, root: Path, onComplete: () => void) { clearTimeout(timer); timer = null; } - timer = setTimeout( - () => { - isRunning = true; - runJest(config, argv, pipe, () => isRunning = false) - .then( - resolve, - error => console.error(chalk.red(error)), - ); - }, - WATCHER_DEBOUNCE, - ); + timer = setTimeout(startRun, WATCHER_DEBOUNCE); } }); }); From 46392221d94b90ad46dbaa4b6ad844ca5db6a71e Mon Sep 17 00:00:00 2001 From: Andy Niccolai Date: Mon, 22 Aug 2016 16:14:12 -0700 Subject: [PATCH 3/3] Update snapshots from within watch mode --- packages/jest-cli/src/jest.js | 100 ++++++++++++------ .../jest-cli/src/reporters/SummaryReporter.js | 15 ++- packages/jest-config/src/defaults.js | 1 + packages/jest-config/src/setFromArgv.js | 5 + packages/jest-snapshot/src/SnapshotFile.js | 1 + types/Config.js | 1 + 6 files changed, 88 insertions(+), 35 deletions(-) diff --git a/packages/jest-cli/src/jest.js b/packages/jest-cli/src/jest.js index fa6b9ddfc093..bbd5daa89c3c 100644 --- a/packages/jest-cli/src/jest.js +++ b/packages/jest-cli/src/jest.js @@ -34,6 +34,12 @@ const CLEAR = '\x1B[2J\x1B[H'; const VERSION = require('../package.json').version; const WATCHER_DEBOUNCE = 200; const WATCHMAN_BIN = 'watchman'; +const KEYS = { + CONTROL_C: '03', + CONTROL_D: '04', + ENTER: '0d', + U: '75', +}; function getMaxWorkers(argv) { if (argv.runInBand) { @@ -154,37 +160,71 @@ function runCLI(argv: Object, root: Path, onComplete: () => void) { if (argv.watch || argv.watchAll) { argv.onlyChanged = !argv.watchAll; - return new Promise(resolve => { - getWatcher(config, root, watcher => { - let timer; - let isRunning; - const startRun = () => { - isRunning = true; - runJest(config, argv, pipe, () => isRunning = false) - .then( - resolve, - error => console.error(chalk.red(error)), - ); - }; - - pipe.write(CLEAR); - startRun(); - - watcher.on('all', (_, filePath) => { - pipe.write(CLEAR); - filePath = path.join(root, filePath); - const isValidPath = - config.testPathDirs.some(dir => filePath.startsWith(dir)); - if (!isRunning && isValidPath) { - if (timer) { - clearTimeout(timer); - timer = null; - } - timer = setTimeout(startRun, WATCHER_DEBOUNCE); - } - }); - }); + let isRunning: ?boolean; + let timer: ?number; + + const startRun = (overrideConfig: Object = {}) => { + if (isRunning) { + return; + } + + pipe.write(CLEAR); + isRunning = true; + runJest( + Object.freeze(Object.assign({}, config, overrideConfig)), + argv, + pipe, + () => { + isRunning = false; + }, + ).then( + () => {}, + error => console.error(chalk.red(error)), + ); + }; + + const onKeypress = (key: string) => { + switch (key) { + case KEYS.CONTROL_C: + process.exit(0); + break; + case KEYS.CONTROL_D: + process.exit(0); + break; + case KEYS.ENTER: + startRun(); + break; + case KEYS.U: + startRun({updateSnapshot: true}); + break; + } + }; + + const onFileChange = (_, filePath: string) => { + filePath = path.join(root, filePath); + const isValidPath = + config.testPathDirs.some(dir => filePath.startsWith(dir)); + + if (!isValidPath) { + return; + } + if (timer) { + clearTimeout(timer); + timer = null; + } + timer = setTimeout(startRun, WATCHER_DEBOUNCE); + }; + + if (typeof process.stdin.setRawMode === 'function') { + process.stdin.setRawMode(true); + process.stdin.resume(); + process.stdin.setEncoding('hex'); + process.stdin.on('data', onKeypress); + } + getWatcher(config, root, watcher => { + watcher.on('all', onFileChange); }); + startRun(); } else { return runJest(config, argv, pipe, onComplete); } diff --git a/packages/jest-cli/src/reporters/SummaryReporter.js b/packages/jest-cli/src/reporters/SummaryReporter.js index 45c7dbbb7095..47b301f9435e 100644 --- a/packages/jest-cli/src/reporters/SummaryReporter.js +++ b/packages/jest-cli/src/reporters/SummaryReporter.js @@ -62,7 +62,7 @@ class SummareReporter extends BaseReporter { } this._printSummary(aggregatedResults, config); - this._printSnapshotSummary(snapshots); + this._printSnapshotSummary(snapshots, config); if (totalTestSuites) { results += `${PASS_COLOR(`${pluralize('test', passedTests)} passed`)} (` + @@ -73,7 +73,7 @@ class SummareReporter extends BaseReporter { } } - _printSnapshotSummary(snapshots: SnapshotSummary) { + _printSnapshotSummary(snapshots: SnapshotSummary, config: Config) { if ( snapshots.added || snapshots.filesRemoved || @@ -81,10 +81,15 @@ class SummareReporter extends BaseReporter { snapshots.unmatched || snapshots.updated ) { + let updateCommand; const event = process.env.npm_lifecycle_event; - const updateCommand = - (!event ? 're-' : '') + 'run with `' + - (event ? 'npm ' + event + ' -- ' : '') + '-u`'; + if (config.watch) { + updateCommand = 'press "u"'; + } else if (event) { + updateCommand = `run with \`npm ${event} -- -u\``; + } else { + updateCommand = 're-run with `-u`'; + } this.log('\n' + SNAPSHOT_SUMMARY('Snapshot Summary')); if (snapshots.added) { diff --git a/packages/jest-config/src/defaults.js b/packages/jest-config/src/defaults.js index a3c2757c1e02..afc9f3355402 100644 --- a/packages/jest-config/src/defaults.js +++ b/packages/jest-config/src/defaults.js @@ -49,4 +49,5 @@ module.exports = ({ testURL: 'about:blank', useStderr: false, verbose: false, + watch: false, }: DefaultConfig); diff --git a/packages/jest-config/src/setFromArgv.js b/packages/jest-config/src/setFromArgv.js index 12a633ea5a79..76d8aba8465c 100644 --- a/packages/jest-config/src/setFromArgv.js +++ b/packages/jest-config/src/setFromArgv.js @@ -64,6 +64,11 @@ function setFromArgv(config, argv) { if (argv.updateSnapshot) { config.updateSnapshot = argv.updateSnapshot; } + + if (argv.watch || argv.watchAll) { + config.watch = true; + } + config.noStackTrace = argv.noStackTrace; config.testcheckOptions = { diff --git a/packages/jest-snapshot/src/SnapshotFile.js b/packages/jest-snapshot/src/SnapshotFile.js index 658a73ea156b..ef36c337d4ef 100644 --- a/packages/jest-snapshot/src/SnapshotFile.js +++ b/packages/jest-snapshot/src/SnapshotFile.js @@ -63,6 +63,7 @@ class SnapshotFile { this._content = Object.create(null); if (this.fileExists(filename)) { try { + delete require.cache[require.resolve(filename)]; /* eslint-disable no-useless-call */ Object.assign(this._content, require.call(null, filename)); /* eslint-enable no-useless-call */ diff --git a/types/Config.js b/types/Config.js index a068b757efa2..efe4446b2c54 100644 --- a/types/Config.js +++ b/types/Config.js @@ -44,6 +44,7 @@ type BaseConfig = { testURL: string, useStderr: boolean, verbose: boolean, + watch: boolean, }; export type DefaultConfig = BaseConfig & {