Skip to content

Commit

Permalink
Small polish to the plugins API (#5572)
Browse files Browse the repository at this point in the history
* Small update to types and rename it to BaseWatchPlugin

* Change getUsageRow to return ?UsageData and rename to getUsageData

* A lot of renaming

* Change type to interface

* Address feedback

* Fix eslint
  • Loading branch information
rogeliog authored and cpojer committed Feb 20, 2018
1 parent 6ee2a14 commit 79533a9
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 115 deletions.
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 Pressing "u" reruns the tests in "update snapshot" mode 1`] = `2`;

exports[`Watch mode flows Runs Jest in a non-interactive environment not showing usage 1`] = `
Array [
"
Expand Down
69 changes: 52 additions & 17 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() {
getUsageInfo() {
return {
key: 's'.codePointAt(0),
prompt: 'do nothing',
Expand All @@ -51,7 +52,7 @@ jest.doMock(
watchPlugin2Path,
() =>
class WatchPlugin2 {
getUsageRow() {
getUsageInfo() {
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 run = jest.fn(() => Promise.resolve());
const pluginPath = `${__dirname}/__fixtures__/plugin_path`;
jest.doMock(
pluginPath,
() =>
class WatchPlugin1 {
constructor() {
this.showPrompt = showPrompt;
this.run = run;
}
getUsageRow() {
getUsageInfo() {
return {
key: 's'.codePointAt(0),
prompt: 'do nothing',
Expand All @@ -277,24 +308,22 @@ describe('Watch mode flows', () => {

await nextTick();

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

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

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

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

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 +437,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: ''};
getUsageInfo(globalConfig: GlobalConfig): ?UsageData {
return null;
}

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

showPrompt(
run(
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 run() {
if (typeof this._stdin.setRawMode === 'function') {
this._stdin.setRawMode(false);
}
this._stdout.write('\n');
process.exit(0);
}

getUsageRow() {
getUsageInfo() {
return {
key: 'q'.codePointAt(0),
prompt: 'quit watch mode',
Expand Down
13 changes: 5 additions & 8 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,21 +23,18 @@ class TestNamePatternPlugin extends WatchPlugin {
this._prompt = new Prompt();
}

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

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

showPrompt(
globalConfig: GlobalConfig,
updateConfigAndRun: Function,
): Promise<void> {
run(globalConfig: GlobalConfig, updateConfigAndRun: Function): Promise<void> {
return new Promise((res, rej) => {
const testPathPatternPrompt = new TestNamePatternPrompt(
this._stdout,
Expand Down
13 changes: 5 additions & 8 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,21 +24,18 @@ class TestPathPatternPlugin extends WatchPlugin {
this._prompt = new Prompt();
}

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

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

showPrompt(
globalConfig: GlobalConfig,
updateConfigAndRun: Function,
): Promise<void> {
run(globalConfig: GlobalConfig, updateConfigAndRun: Function): Promise<void> {
return new Promise((res, rej) => {
const testPathPatternPrompt = new TestPathPatternPrompt(
this._stdout,
Expand Down
23 changes: 13 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,34 @@
* @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(
run(
globalConfig: GlobalConfig,
updateConfigAndRun: Function,
): Promise<boolean> {
updateConfigAndRun({updateSnapshot: 'all'});
return Promise.resolve(false);
}

registerHooks(hooks: JestHookSubscriber) {
apply(hooks: JestHookSubscriber) {
hooks.testRunComplete(results => {
this._hasSnapshotFailure = results.snapshot.failure;
});
}

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

return null;
}
}

Expand Down
Loading

0 comments on commit 79533a9

Please sign in to comment.