Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
396cd18
Start adding tapable
rogeliog Jan 17, 2018
c04edc7
Use test_path_pattern as a plugin
rogeliog Jan 19, 2018
1f74aa1
Use test_name_pattern as a plugin
rogeliog Jan 19, 2018
03b53b1
Use quit as a plugin
rogeliog Jan 19, 2018
1aeafb8
Fix test interruption
rogeliog Jan 19, 2018
b40f604
Use update snapshot as a plugin
rogeliog Jan 19, 2018
6e97a6e
Use update snapshot interactive as a plugin
rogeliog Jan 25, 2018
ef14ade
Change API to use a class instance
rogeliog Jan 26, 2018
8b999ed
Merge branch 'master' into simpler-plugins
rogeliog Jan 26, 2018
2604965
A bit of clean up and make tests pass
rogeliog Jan 26, 2018
ffc85f1
Change plugin implementation to not use tapable
rogeliog Feb 2, 2018
053d9e4
Better sorting implementation
rogeliog Feb 2, 2018
2036be9
Add back third party plugin functionality
rogeliog Feb 2, 2018
40c4265
Fix flow
rogeliog Feb 2, 2018
44c82ba
Merge branch 'master' into simpler-plugins
rogeliog Feb 2, 2018
7767b71
Fix ESLint
rogeliog Feb 2, 2018
2b084f8
Reset file to state of master
rogeliog Feb 2, 2018
58f1717
Update failing snapshot
rogeliog Feb 2, 2018
13f08e5
Merge branch 'master' into simpler-plugins
rogeliog Feb 6, 2018
d4ecb92
Remove hasSnapshotFailure and hasSnapshotFailureInteractive
rogeliog Feb 6, 2018
8f6513e
Async await for showPrompt and clear active plugin on file change
rogeliog Feb 6, 2018
401e44b
Fix snapshot failure
rogeliog Feb 6, 2018
9ac7d94
Reenable tests
rogeliog Feb 6, 2018
25e0c4b
Implement shouldRunTestSuite
rogeliog Feb 6, 2018
4a68617
Add changelog
rogeliog Feb 6, 2018
3dc8c06
Clean up watch.js a bit
rogeliog Feb 6, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use update snapshot interactive as a plugin
  • Loading branch information
rogeliog committed Jan 25, 2018
commit 6e97a6e61974738cd730314688415751ec1abbcd
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Watch mode flows Failing snapshot 1`] = `1`;

exports[`Watch mode flows Runs Jest in a non-interactive environment not showing usage 1`] = `
Array [
"
Expand Down
6 changes: 5 additions & 1 deletion packages/jest-cli/src/__tests__/watch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ describe('Watch mode flows', () => {
expect(pipeMockCalls.slice(determiningTestsToRun + 1)).toMatchSnapshot();
});

it('Failing snapshot', () => {
expect(1).toMatchSnapshot();
});

xit('triggers enter on a WatchPlugin when its key is pressed', () => {
const plugin = require(watchPluginPath);

Expand Down Expand Up @@ -275,7 +279,7 @@ describe('Watch mode flows', () => {
// updateSnapshot is not sticky after a run.
expect(runJestMock.mock.calls[1][0].globalConfig).toMatchObject({
updateSnapshot: 'new',
watch: false,
watch: true,
});
});
it('passWithNoTest should be set to true in watch mode', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ describe('Watch mode flows', () => {

// Write a enter pattern mode
stdin.emit(KEYS.P);
await nextTick();
expect(pipe.write).toBeCalledWith(' pattern › ');

const assertPattern = hex => {
Expand Down Expand Up @@ -168,8 +169,10 @@ describe('Watch mode flows', () => {
await nextTick();

stdin.emit(KEYS.C);
await nextTick();
pipe.write.mockReset();
stdin.emit(KEYS.P);
await nextTick();
expect(pipe.write.mock.calls.join('\n')).toMatchSnapshot();
});
});
Expand Down
5 changes: 3 additions & 2 deletions packages/jest-cli/src/plugins/test_name_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Prompt from '../lib/Prompt';
const PLUGIN_NAME = 'test-name-pattern';
const testPathPatternPlugin: WatchPlugin = {
apply: (jestHooks, {stdin, stdout}) => {
const showPrompt = globalConfig => {
const showPrompt = (globalConfig, updateConfigAndRun) => {
return new Promise((res, rej) => {
let exited = false;
const prompt = new Prompt();
Expand All @@ -29,7 +29,8 @@ const testPathPatternPlugin: WatchPlugin = {
testPathPatternPrompt.run(
(value: string) => {
exited = true;
res({testNamePattern: value});
updateConfigAndRun({testNamePattern: value});
res();
},
() => {
exited = true;
Expand Down
5 changes: 3 additions & 2 deletions packages/jest-cli/src/plugins/test_path_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Prompt from '../lib/Prompt';
const PLUGIN_NAME = 'test-path-pattern';
const testPathPatternPlugin: WatchPlugin = {
apply: (jestHooks, {stdin, stdout}) => {
const showPrompt = globalConfig => {
const showPrompt = (globalConfig, updateConfigAndRun) => {
return new Promise((res, rej) => {
let exited = false;
const prompt = new Prompt();
Expand All @@ -29,7 +29,8 @@ const testPathPatternPlugin: WatchPlugin = {
testPathPatternPrompt.run(
(value: string) => {
exited = true;
res({testPathPattern: value});
updateConfigAndRun({testPathPattern: value});
res();
},
() => {
exited = true;
Expand Down
8 changes: 6 additions & 2 deletions packages/jest-cli/src/plugins/update_snapshots.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ import type {WatchPlugin} from '../types';
const PLUGIN_NAME = 'update-snapshots';
const updateSnapshotsPlugin: WatchPlugin = {
apply: (watchPromptHooks, {stdin, stdout}) => {
watchPromptHooks.showPrompt.tapPromise(PLUGIN_NAME, () =>
Promise.resolve({updateSnapshot: 'all'}),
watchPromptHooks.showPrompt.tapPromise(
PLUGIN_NAME,
(globalConfig, updateConfigAndRun) => {
updateConfigAndRun({updateSnapshot: 'all'});
return Promise.resolve();
},
);
},
key: 'u'.codePointAt(0),
Expand Down
63 changes: 63 additions & 0 deletions packages/jest-cli/src/plugins/update_snapshots_interactive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {WatchPlugin} from '../types';
import {getFailedSnapshotTests} from 'jest-util';
import SnapshotInteractiveMode from '../snapshot_interactive_mode';

const PLUGIN_NAME = 'update-snapshots-interactive';
const updateSnapshotsInteractivePlugin: WatchPlugin = {
apply: (jestHooks, {stdin, stdout}) => {
let failedSnapshotTestPaths = [];
const snapshotInteractiveMode = new SnapshotInteractiveMode(stdout);

jestHooks.testRunComplete.tap(PLUGIN_NAME, results => {
failedSnapshotTestPaths = getFailedSnapshotTests(results);
if (snapshotInteractiveMode.isActive()) {
snapshotInteractiveMode.updateWithResults(results);
}
});

stdin.on('data', key => {
if (snapshotInteractiveMode.isActive()) {
snapshotInteractiveMode.put(key);
}
});

jestHooks.showPrompt.tapPromise(
PLUGIN_NAME,
(globalConfig, updateConfigAndRun) => {
if (failedSnapshotTestPaths.length) {
return new Promise(res => {
snapshotInteractiveMode.run(
failedSnapshotTestPaths,
(path: string, shouldUpdateSnapshot: boolean) => {
updateConfigAndRun({
testNamePattern: '',
testPathPattern: path,
updateSnapshot: shouldUpdateSnapshot ? 'all' : 'none',
});
if (!snapshotInteractiveMode.isActive()) {
res();
}
},
);
});
} else {
return Promise.resolve();
}
},
);
},
key: 'i'.codePointAt(0),
name: PLUGIN_NAME,
prompt: 'update failing snapshots interactively',
shouldShowUsage: (globalConfig, hasSnapshotFailures) => hasSnapshotFailures,
};

export default updateSnapshotsInteractivePlugin;
1 change: 1 addition & 0 deletions packages/jest-cli/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {GlobalConfig} from 'types/Config';

export type JestHooks = {
showPrompt: any,
testRunComplete: any,
};

export type WatchPlugin = {
Expand Down
97 changes: 34 additions & 63 deletions packages/jest-cli/src/watch.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,26 @@ import exit from 'exit';
import {replacePathSepForRegex} from 'jest-regex-util';
import HasteMap from 'jest-haste-map';
import isValidPath from './lib/is_valid_path';
import {getFailedSnapshotTests, isInteractive} from 'jest-util';
import {isInteractive} from 'jest-util';
import {print as preRunMessagePrint} from './pre_run_message';
import createContext from './lib/create_context';
import runJest from './run_jest';
import updateGlobalConfig from './lib/update_global_config';
import SearchSource from './search_source';
import SnapshotInteractiveMode from './snapshot_interactive_mode';
import TestWatcher from './test_watcher';
import Prompt from './lib/Prompt';
import FailedTestsCache from './failed_tests_cache';
import WatchPluginRegistry from './lib/watch_plugin_registry';
import {KEYS, CLEAR} from './constants';
import {AsyncSeriesWaterfallHook} from 'tapable';
import {AsyncSeriesWaterfallHook, SyncHook} from 'tapable';

let hasExitListener = false;

const internalPlugins = [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will get cleaned up

require.resolve('./plugins/test_path_pattern'),
require.resolve('./plugins/test_name_pattern'),
require.resolve('./plugins/update_snapshots'),
require.resolve('./plugins/update_snapshots_interactive'),
require.resolve('./plugins/quit'),
];

Expand All @@ -59,7 +59,11 @@ export default function watch(
});

const hooks = {
showPrompt: new AsyncSeriesWaterfallHook(['globalConfig']),
showPrompt: new AsyncSeriesWaterfallHook([
'globalConfig',
'updateConfigAndRun',
]),
testRunComplete: new SyncHook(['results']),
};

hooks.showPrompt.intercept({
Expand All @@ -76,6 +80,27 @@ export default function watch(
},
});

const updateConfigAndRun = ({
testNamePattern,
testPathPattern,
updateSnapshot,
} = {}) => {
const previousUpdateSnapshot = globalConfig.updateSnapshot;
globalConfig = updateGlobalConfig(globalConfig, {
mode: 'watch',
testNamePattern,
testPathPattern: replacePathSepForRegex(testPathPattern || ''),
updateSnapshot: updateSnapshot || globalConfig.updateSnapshot,
});

startRun(globalConfig);
globalConfig = updateGlobalConfig(globalConfig, {
// updateSnapshot is not sticky after a run.
updateSnapshot:
previousUpdateSnapshot === 'all' ? 'none' : previousUpdateSnapshot,
});
};

const watchPlugins = new WatchPluginRegistry(globalConfig.rootDir);

internalPlugins.forEach(pluginPath => {
Expand All @@ -97,8 +122,6 @@ export default function watch(

const failedTestsCache = new FailedTestsCache();
const prompt = new Prompt();
const snapshotInteractiveMode = new SnapshotInteractiveMode(outputStream);
let failedSnapshotTestPaths = [];
let searchSources = contexts.map(context => ({
context,
searchSource: new SearchSource(context),
Expand Down Expand Up @@ -163,7 +186,7 @@ export default function watch(
onComplete: results => {
isRunning = false;
hasSnapshotFailure = !!results.snapshot.failure;
failedSnapshotTestPaths = getFailedSnapshotTests(results);
hooks.testRunComplete.call(results);

// Create a new testWatcher instance so that re-runs won't be blocked.
// The old instance that was passed to Jest will still be interrupted
Expand All @@ -173,10 +196,6 @@ export default function watch(
// Do not show any Watch Usage related stuff when running in a
// non-interactive environment
if (isInteractive) {
if (snapshotInteractiveMode.isActive()) {
snapshotInteractiveMode.updateWithResults(results);
return;
}
if (shouldDisplayWatchUsage) {
outputStream.write(
usage(globalConfig, watchPlugins, hasSnapshotFailure),
Expand Down Expand Up @@ -217,11 +236,6 @@ export default function watch(
return;
}

if (snapshotInteractiveMode.isActive()) {
snapshotInteractiveMode.put(key);
return;
}

// Abort test run
const pluginKeys = watchPlugins
.getPluginsOrderedByKey()
Expand All @@ -245,25 +259,10 @@ export default function watch(
// "activate" the plugin, which has jest ignore keystrokes so the plugin
// can handle them
activePlugin = matchingWatchPlugin;
hooks.showPrompt.promise(globalConfig).then(
({testNamePattern, testPathPattern, updateSnapshot} = {}) => {
hooks.showPrompt.promise(globalConfig, updateConfigAndRun).then(
() => {
activePlugin = null;
const previousUpdateSnapshot = globalConfig.updateSnapshot;
globalConfig = updateGlobalConfig(globalConfig, {
mode: 'watch',
testNamePattern,
testPathPattern: replacePathSepForRegex(testPathPattern || ''),
updateSnapshot: updateSnapshot || globalConfig.updateSnapshot,
});

startRun(globalConfig);
globalConfig = updateGlobalConfig(globalConfig, {
// updateSnapshot is not sticky after a run.
updateSnapshot:
previousUpdateSnapshot === 'all'
? 'none'
: previousUpdateSnapshot,
});
updateConfigAndRun();
},
() => {
activePlugin = null;
Expand All @@ -276,26 +275,6 @@ export default function watch(
case KEYS.ENTER:
startRun(globalConfig);
break;
case KEYS.I:
if (hasSnapshotFailure) {
snapshotInteractiveMode.run(
failedSnapshotTestPaths,
(path: string, shouldUpdateSnapshot: boolean) => {
globalConfig = updateGlobalConfig(globalConfig, {
mode: 'watch',
testNamePattern: '',
testPathPattern: replacePathSepForRegex(path),
updateSnapshot: shouldUpdateSnapshot ? 'all' : 'none',
});
startRun(globalConfig);
globalConfig = updateGlobalConfig(globalConfig, {
// updateSnapshot is not sticky after a run.
updateSnapshot: 'none',
});
},
);
}
break;
case KEYS.A:
globalConfig = updateGlobalConfig(globalConfig, {
mode: 'watchAll',
Expand All @@ -305,12 +284,10 @@ export default function watch(
startRun(globalConfig);
break;
case KEYS.C:
globalConfig = updateGlobalConfig(globalConfig, {
mode: 'watch',
updateConfigAndRun({
testNamePattern: '',
testPathPattern: '',
});
startRun(globalConfig);
break;
case KEYS.F:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a plugin as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, this one should be a plugin... I can do it in this PR of as follow up PRs

Copy link
Contributor Author

@rogeliog rogeliog Feb 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also want to wait for it because it will require some refactor

globalConfig = updateGlobalConfig(globalConfig, {
Expand Down Expand Up @@ -415,12 +392,6 @@ const usage = (
chalk.dim(' to only run tests related to changed files.')
: null,

snapshotFailure
? chalk.dim(' \u203A Press ') +
'i' +
chalk.dim(' to update failing snapshots interactively.')
: null,

...watchPlugins
.getPluginsOrderedByKey()
.filter(plugin => {
Expand Down