Skip to content

Commit

Permalink
Allow plugin keys to be overriden by other plugins (#5878)
Browse files Browse the repository at this point in the history
  • Loading branch information
rogeliog authored and cpojer committed Mar 28, 2018
1 parent a9d1c5f commit f099621
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 19 deletions.
14 changes: 14 additions & 0 deletions packages/jest-cli/src/__tests__/__snapshots__/watch.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ Watch Usage
]
`;

exports[`Watch mode flows allows WatchPlugins to override internal plugins 1`] = `
Array [
"
Watch Usage
› Press a to run all tests.
› Press f to run only failed tests.
› Press t to filter by a test name regex pattern.
› Press q to quit watch mode.
› Press p to custom \\"P\\" plugin.
› Press Enter to trigger a test run.
",
]
`;

exports[`Watch mode flows shows prompts for WatchPlugins in alphabetical order 1`] = `
Array [
Array [
Expand Down
41 changes: 41 additions & 0 deletions packages/jest-cli/src/__tests__/watch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,47 @@ describe('Watch mode flows', () => {
expect(apply).toHaveBeenCalled();
});

it('allows WatchPlugins to override internal plugins', async () => {
const run = jest.fn(() => Promise.resolve());
const pluginPath = `${__dirname}/__fixtures__/plugin_path_override`;
jest.doMock(
pluginPath,
() =>
class WatchPlugin {
constructor() {
this.run = run;
}
getUsageInfo() {
return {
key: 'p'.codePointAt(0),
prompt: 'custom "P" plugin',
};
}
},
{virtual: true},
);

watch(
Object.assign({}, globalConfig, {
rootDir: __dirname,
watchPlugins: [pluginPath],
}),
contexts,
pipe,
hasteMapInstances,
stdin,
);

await nextTick();

expect(pipe.write.mock.calls.reverse()[0]).toMatchSnapshot();

stdin.emit(toHex('p'));
await nextTick();

expect(run).toHaveBeenCalled();
});

it('allows WatchPlugins to hook into file system changes', async () => {
const fileChange = jest.fn();
const pluginPath = `${__dirname}/__fixtures__/plugin_path_fs_change`;
Expand Down
51 changes: 51 additions & 0 deletions packages/jest-cli/src/lib/watch_plugins_helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* 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 {GlobalConfig} from 'types/Config';
import type {WatchPlugin, UsageData} from '../types';

export const filterInteractivePlugins = (
watchPlugins: Array<WatchPlugin>,
globalConfig: GlobalConfig,
): Array<WatchPlugin> => {
const usageInfos = watchPlugins.map(
p => p.getUsageInfo && p.getUsageInfo(globalConfig),
);

return watchPlugins.filter((plugin, i, array) => {
if (usageInfos[i]) {
const {key} = usageInfos[i];
return !usageInfos.slice(i + 1).some(u => u && key === u.key);
}

return false;
});
};

export const getSortedUsageRows = (
watchPlugins: Array<WatchPlugin>,
globalConfig: GlobalConfig,
): Array<UsageData> => {
return filterInteractivePlugins(watchPlugins, globalConfig)
.sort((a: WatchPlugin, b: WatchPlugin) => {
if (a.isInternal) {
return -1;
}

const usageInfoA = a.getUsageInfo && a.getUsageInfo(globalConfig);
const usageInfoB = b.getUsageInfo && b.getUsageInfo(globalConfig);

if (usageInfoA && usageInfoB) {
return usageInfoA.key - usageInfoB.key;
}

return 0;
})
.map(p => p.getUsageInfo && p.getUsageInfo(globalConfig))
.filter(Boolean);
};
10 changes: 10 additions & 0 deletions packages/jest-cli/src/plugins/quit.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@
import BaseWatchPlugin from '../base_watch_plugin';

class QuitPlugin extends BaseWatchPlugin {
isInternal: true;

constructor(options: {
stdin: stream$Readable | tty$ReadStream,
stdout: stream$Writable | tty$WriteStream,
}) {
super(options);
this.isInternal = true;
}

async run() {
if (typeof this._stdin.setRawMode === 'function') {
this._stdin.setRawMode(false);
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-cli/src/plugins/test_name_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ import Prompt from '../lib/Prompt';

class TestNamePatternPlugin extends BaseWatchPlugin {
_prompt: Prompt;
isInternal: true;

constructor(options: {
stdin: stream$Readable | tty$ReadStream,
stdout: stream$Writable | tty$WriteStream,
}) {
super(options);
this._prompt = new Prompt();
this.isInternal = true;
}

getUsageInfo() {
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-cli/src/plugins/test_path_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ import Prompt from '../lib/Prompt';

class TestPathPatternPlugin extends BaseWatchPlugin {
_prompt: Prompt;
isInternal: true;

constructor(options: {
stdin: stream$Readable | tty$ReadStream,
stdout: stream$Writable | tty$WriteStream,
}) {
super(options);
this._prompt = new Prompt();
this.isInternal = true;
}

getUsageInfo() {
Expand Down
10 changes: 10 additions & 0 deletions packages/jest-cli/src/plugins/update_snapshots.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ import type {JestHookSubscriber} from '../jest_hooks';

class UpdateSnapshotsPlugin extends BaseWatchPlugin {
_hasSnapshotFailure: boolean;
isInternal: true;

constructor(options: {
stdin: stream$Readable | tty$ReadStream,
stdout: stream$Writable | tty$WriteStream,
}) {
super(options);
this.isInternal = true;
}

run(
globalConfig: GlobalConfig,
updateConfigAndRun: Function,
Expand Down
3 changes: 3 additions & 0 deletions packages/jest-cli/src/plugins/update_snapshots_interactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import SnapshotInteractiveMode from '../snapshot_interactive_mode';

class UpdateSnapshotInteractivePlugin extends BaseWatchPlugin {
_snapshotInteractiveMode: SnapshotInteractiveMode;
_failedSnapshotTestPaths: Array<*>;
_failedSnapshotTestAssertions: Array<AssertionLocation>;
isInternal: true;

constructor(options: {
stdin: stream$Readable | tty$ReadStream,
Expand All @@ -23,6 +25,7 @@ class UpdateSnapshotInteractivePlugin extends BaseWatchPlugin {
super(options);
this._failedSnapshotTestAssertions = [];
this._snapshotInteractiveMode = new SnapshotInteractiveMode(this._stdout);
this.isInternal = true;
}

getFailedSnapshotTestAssertions(
Expand Down
1 change: 1 addition & 0 deletions packages/jest-cli/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type JestHooks = {
};

export interface WatchPlugin {
+isInternal?: boolean;
+apply?: (hooks: JestHookSubscriber) => void;
+getUsageInfo?: (globalConfig: GlobalConfig) => ?UsageData;
+onKey?: (value: string) => void;
Expand Down
27 changes: 8 additions & 19 deletions packages/jest-cli/src/watch.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ import TestNamePatternPlugin from './plugins/test_name_pattern';
import UpdateSnapshotsPlugin from './plugins/update_snapshots';
import UpdateSnapshotsInteractivePlugin from './plugins/update_snapshots_interactive';
import QuitPlugin from './plugins/quit';
import {
getSortedUsageRows,
filterInteractivePlugins,
} from './lib/watch_plugins_helpers';
import activeFilters from './lib/active_filters_message';

let hasExitListener = false;
Expand All @@ -45,24 +49,6 @@ const INTERNAL_PLUGINS = [
QuitPlugin,
];

const getSortedUsageRows = (
watchPlugins: Array<WatchPlugin>,
globalConfig: GlobalConfig,
) => {
const internalPlugins = watchPlugins
.slice(0, INTERNAL_PLUGINS.length)
.map(p => p.getUsageInfo && p.getUsageInfo(globalConfig))
.filter(Boolean);

const thirdPartyPlugins = watchPlugins
.slice(INTERNAL_PLUGINS.length)
.map(p => p.getUsageInfo && p.getUsageInfo(globalConfig))
.filter(Boolean)
.sort((a, b) => a.key - b.key);

return internalPlugins.concat(thirdPartyPlugins);
};

export default function watch(
initialGlobalConfig: GlobalConfig,
contexts: Array<Context>,
Expand Down Expand Up @@ -285,7 +271,10 @@ export default function watch(
return;
}

const matchingWatchPlugin = watchPlugins.find(plugin => {
const matchingWatchPlugin = filterInteractivePlugins(
watchPlugins,
globalConfig,
).find(plugin => {
const usageData =
(plugin.getUsageInfo && plugin.getUsageInfo(globalConfig)) || {};
return usageData.key === parseInt(key, 16);
Expand Down

0 comments on commit f099621

Please sign in to comment.