Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small polish to the plugins API #5572

Merged
merged 6 commits into from
Feb 20, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
66 changes: 51 additions & 15 deletions packages/jest-cli/src/__tests__/watch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import chalk from 'chalk';
import TestWatcher from '../test_watcher';
import JestHooks from '../jest_hooks';
import {KEYS} from '../constants';

const runJestMock = jest.fn();
Expand Down Expand Up @@ -37,7 +38,7 @@ jest.doMock(
watchPluginPath,
() =>
class WatchPlugin1 {
getUsageRow() {
getUsageData() {
return {
key: 's'.codePointAt(0),
prompt: 'do nothing',
Expand All @@ -51,7 +52,7 @@ jest.doMock(
watchPlugin2Path,
() =>
class WatchPlugin2 {
getUsageRow() {
getUsageData() {
return {
key: 'u'.codePointAt(0),
prompt: 'do something else',
Expand Down Expand Up @@ -242,17 +243,47 @@ describe('Watch mode flows', () => {
expect(pipeMockCalls.slice(determiningTestsToRun + 1)).toMatchSnapshot();
});

it('allows WatchPlugins to hook into JestHooks', async () => {
const apply = jest.fn();
const pluginPath = `${__dirname}/__fixtures__/plugin_path_register`;
jest.doMock(
pluginPath,
() =>
class WatchPlugin {
constructor() {
this.apply = apply;
}
},
{virtual: true},
);

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

await nextTick();

expect(apply).toHaveBeenCalled();
});

it('triggers enter on a WatchPlugin when its key is pressed', async () => {
const showPrompt = jest.fn(() => Promise.resolve());
const runInteractive = jest.fn(() => Promise.resolve());
const pluginPath = `${__dirname}/__fixtures__/plugin_path`;
jest.doMock(
pluginPath,
() =>
class WatchPlugin1 {
constructor() {
this.showPrompt = showPrompt;
this.runInteractive = runInteractive;
}
getUsageRow() {
getUsageData() {
return {
key: 's'.codePointAt(0),
prompt: 'do nothing',
Expand All @@ -277,12 +308,12 @@ describe('Watch mode flows', () => {

await nextTick();

expect(showPrompt).toHaveBeenCalled();
expect(runInteractive).toHaveBeenCalled();
});

it('prevents Jest from handling keys when active and returns control when end is called', async () => {
let resolveShowPrompt;
const showPrompt = jest.fn(
const runInteractive = jest.fn(
() => new Promise(res => (resolveShowPrompt = res)),
);
const pluginPath = `${__dirname}/__fixtures__/plugin_path_1`;
Expand All @@ -291,10 +322,10 @@ describe('Watch mode flows', () => {
() =>
class WatchPlugin1 {
constructor() {
this.showPrompt = showPrompt;
this.runInteractive = runInteractive;
}
onData() {}
getUsageRow() {
onKey() {}
getUsageData() {
return {
key: 's'.codePointAt(0),
prompt: 'do nothing',
Expand All @@ -311,10 +342,10 @@ describe('Watch mode flows', () => {
() =>
class WatchPlugin1 {
constructor() {
this.showPrompt = showPrompt2;
this.runInteractive = showPrompt2;
}
onData() {}
getUsageRow() {
onKey() {}
getUsageData() {
return {
key: 'z'.codePointAt(0),
prompt: 'also do nothing',
Expand All @@ -337,7 +368,7 @@ describe('Watch mode flows', () => {

stdin.emit(Number('s'.charCodeAt(0)).toString(16));
await nextTick();
expect(showPrompt).toHaveBeenCalled();
expect(runInteractive).toHaveBeenCalled();
stdin.emit(Number('z'.charCodeAt(0)).toString(16));
await nextTick();
expect(showPrompt2).not.toHaveBeenCalled();
Expand Down Expand Up @@ -382,11 +413,15 @@ describe('Watch mode flows', () => {
});

it('Pressing "u" reruns the tests in "update snapshot" mode', async () => {
const hooks = new JestHooks();

globalConfig.updateSnapshot = 'new';

watch(globalConfig, contexts, pipe, hasteMapInstances, stdin);
watch(globalConfig, contexts, pipe, hasteMapInstances, stdin, hooks);
runJestMock.mockReset();

hooks.getEmitter().testRunComplete({snapshot: {failure: true}});

stdin.emit(KEYS.U);
await nextTick();

Expand All @@ -403,6 +438,7 @@ describe('Watch mode flows', () => {
watch: false,
});
});

it('passWithNoTest should be set to true in watch mode', () => {
globalConfig.passWithNoTests = false;
watch(globalConfig, contexts, pipe, hasteMapInstances, stdin);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
*/
import type {GlobalConfig} from 'types/Config';
import type {JestHookSubscriber} from './jest_hooks';
import type {UsageRow} from './types';
import type {WatchPlugin, UsageData} from './types';

class WatchPlugin {
class BaseWatchPlugin implements WatchPlugin {
_stdin: stream$Readable | tty$ReadStream;
_stdout: stream$Writable | tty$WriteStream;
constructor({
Expand All @@ -24,20 +24,20 @@ class WatchPlugin {
this._stdout = stdout;
}

registerHooks(hooks: JestHookSubscriber) {}
apply(hooks: JestHookSubscriber) {}

getUsageRow(globalConfig: GlobalConfig): UsageRow {
return {hide: true, key: 0, prompt: ''};
getUsageData(globalConfig: GlobalConfig): ?UsageData {
return null;
}

onData(value: string) {}
onKey(value: string) {}

showPrompt(
runInteractive(
globalConfig: GlobalConfig,
updateConfigAndRun: Function,
): Promise<void | boolean> {
return Promise.resolve();
}
}

export default WatchPlugin;
export default BaseWatchPlugin;
8 changes: 4 additions & 4 deletions packages/jest-cli/src/plugins/quit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@
*
* @flow
*/
import WatchPlugin from '../watch_plugin';
import BaseWatchPlugin from '../base_watch_plugin';

class QuitPlugin extends WatchPlugin {
async showPrompt() {
class QuitPlugin extends BaseWatchPlugin {
async runInteractive() {
if (typeof this._stdin.setRawMode === 'function') {
this._stdin.setRawMode(false);
}
this._stdout.write('\n');
process.exit(0);
}

getUsageRow() {
getUsageData() {
return {
key: 'q'.codePointAt(0),
prompt: 'quit watch mode',
Expand Down
10 changes: 5 additions & 5 deletions packages/jest-cli/src/plugins/test_name_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
* @flow
*/
import type {GlobalConfig} from 'types/Config';
import WatchPlugin from '../watch_plugin';
import BaseWatchPlugin from '../base_watch_plugin';
import TestNamePatternPrompt from '../test_name_pattern_prompt';
import activeFilters from '../lib/active_filters_message';
import Prompt from '../lib/Prompt';

class TestNamePatternPlugin extends WatchPlugin {
class TestNamePatternPlugin extends BaseWatchPlugin {
_prompt: Prompt;

constructor(options: {
Expand All @@ -23,18 +23,18 @@ class TestNamePatternPlugin extends WatchPlugin {
this._prompt = new Prompt();
}

getUsageRow() {
getUsageData() {
return {
key: 't'.codePointAt(0),
prompt: 'filter by a test name regex pattern',
};
}

onData(key: string) {
onKey(key: string) {
this._prompt.put(key);
}

showPrompt(
runInteractive(
globalConfig: GlobalConfig,
updateConfigAndRun: Function,
): Promise<void> {
Expand Down
10 changes: 5 additions & 5 deletions packages/jest-cli/src/plugins/test_path_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
*/

import type {GlobalConfig} from 'types/Config';
import WatchPlugin from '../watch_plugin';
import BaseWatchPlugin from '../base_watch_plugin';
import TestPathPatternPrompt from '../test_path_pattern_prompt';
import activeFilters from '../lib/active_filters_message';
import Prompt from '../lib/Prompt';

class TestPathPatternPlugin extends WatchPlugin {
class TestPathPatternPlugin extends BaseWatchPlugin {
_prompt: Prompt;

constructor(options: {
Expand All @@ -24,18 +24,18 @@ class TestPathPatternPlugin extends WatchPlugin {
this._prompt = new Prompt();
}

getUsageRow() {
getUsageData() {
return {
key: 'p'.codePointAt(0),
prompt: 'filter by a filename regex pattern',
};
}

onData(key: string) {
onKey(key: string) {
this._prompt.put(key);
}

showPrompt(
runInteractive(
globalConfig: GlobalConfig,
updateConfigAndRun: Function,
): Promise<void> {
Expand Down
24 changes: 14 additions & 10 deletions packages/jest-cli/src/plugins/update_snapshots.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,35 @@
* @flow
*/
import type {GlobalConfig} from 'types/Config';
import WatchPlugin from '../watch_plugin';
import BaseWatchPlugin from '../base_watch_plugin';
import type {JestHookSubscriber} from '../jest_hooks';

class UpdateSnapshotsPlugin extends WatchPlugin {
class UpdateSnapshotsPlugin extends BaseWatchPlugin {
_hasSnapshotFailure: boolean;
showPrompt(
runInteractive(
globalConfig: GlobalConfig,
updateConfigAndRun: Function,
): Promise<boolean> {
updateConfigAndRun({updateSnapshot: 'all'});
return Promise.resolve(false);
}

registerHooks(hooks: JestHookSubscriber) {
apply(hooks: JestHookSubscriber) {
this._hasSnapshotFailure = true;
Copy link
Member

Choose a reason for hiding this comment

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

Is this necessary/intentional or a leftover from debugging?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch

hooks.testRunComplete(results => {
this._hasSnapshotFailure = results.snapshot.failure;
});
}

getUsageRow(globalConfig: GlobalConfig) {
return {
hide: !this._hasSnapshotFailure,
key: 'u'.codePointAt(0),
prompt: 'update failing snapshots',
};
getUsageData(globalConfig: GlobalConfig) {
if (this._hasSnapshotFailure) {
return {
key: 'u'.codePointAt(0),
prompt: 'update failing snapshots',
};
}

return null;
}
}

Expand Down
Loading