Skip to content

Commit de21fd4

Browse files
rogeliogSimenB
authored andcommitted
Allow watch plugin to be configured (#6603)
1 parent 2208288 commit de21fd4

8 files changed

Lines changed: 131 additions & 21 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### Features
44

5+
- `[jest-cli]` Allow watch plugin to be configured ([#6603](https://github.com/facebook/jest/pull/6603))
56
- `[jest-snapshot]` Introduce `toMatchInlineSnapshot` and `toThrowErrorMatchingInlineSnapshot` matchers ([#6380](https://github.com/facebook/jest/pull/6380))
67

78
### Fixes

docs/WatchPlugins.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,36 @@ class MyWatchPlugin {
148148
}
149149
}
150150
```
151+
152+
## Customization
153+
154+
Plugins can be customized via your Jest configuration.
155+
156+
```javascript
157+
// jest.config.js
158+
module.exports = {
159+
// ...
160+
watchPlugins: [
161+
[
162+
'path/to/yourWatchPlugin',
163+
{
164+
key: 'k', // <- your custom key
165+
prompt: 'show a custom prompt',
166+
},
167+
],
168+
],
169+
};
170+
```
171+
172+
Recommended config names:
173+
174+
- `key`: Modifies the plugin key.
175+
- `prompt`: Allows user to customize the text in the plugin prompt.
176+
177+
If the user provided a custom configuration, it will be passed as an argument to the plugin constructor.
178+
179+
```javascript
180+
class MyWatchPlugin {
181+
constructor({config}) {}
182+
}
183+
```

packages/jest-cli/src/__tests__/__snapshots__/watch.test.js.snap

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@ Watch Usage
2121
]
2222
`;
2323

24+
exports[`Watch mode flows allows WatchPlugins to be configured 1`] = `
25+
Array [
26+
"
27+
Watch Usage
28+
› Press a to run all tests.
29+
› Press f to run only failed tests.
30+
› Press p to filter by a filename regex pattern.
31+
› Press t to filter by a test name regex pattern.
32+
› Press q to quit watch mode.
33+
› Press k to filter with a custom prompt.
34+
› Press Enter to trigger a test run.
35+
",
36+
]
37+
`;
38+
2439
exports[`Watch mode flows allows WatchPlugins to override internal plugins 1`] = `
2540
Array [
2641
"

packages/jest-cli/src/__tests__/watch.test.js

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ describe('Watch mode flows', () => {
176176
await watch(
177177
Object.assign({}, globalConfig, {
178178
rootDir: __dirname,
179-
watchPlugins: [watchPluginPath],
179+
watchPlugins: [{config: {}, path: watchPluginPath}],
180180
}),
181181
contexts,
182182
pipe,
@@ -195,7 +195,10 @@ describe('Watch mode flows', () => {
195195
ci_watch(
196196
Object.assign({}, globalConfig, {
197197
rootDir: __dirname,
198-
watchPlugins: [watchPlugin2Path, watchPluginPath],
198+
watchPlugins: [
199+
{config: {}, path: watchPluginPath},
200+
{config: {}, path: watchPlugin2Path},
201+
],
199202
}),
200203
contexts,
201204
pipe,
@@ -302,7 +305,7 @@ describe('Watch mode flows', () => {
302305
watch(
303306
Object.assign({}, globalConfig, {
304307
rootDir: __dirname,
305-
watchPlugins: [pluginPath],
308+
watchPlugins: [{config: {}, path: pluginPath}],
306309
}),
307310
contexts,
308311
pipe,
@@ -338,7 +341,7 @@ describe('Watch mode flows', () => {
338341
watch(
339342
Object.assign({}, globalConfig, {
340343
rootDir: __dirname,
341-
watchPlugins: [pluginPath],
344+
watchPlugins: [{config: {}, path: pluginPath}],
342345
}),
343346
contexts,
344347
pipe,
@@ -356,6 +359,47 @@ describe('Watch mode flows', () => {
356359
expect(run).toHaveBeenCalled();
357360
});
358361

362+
it('allows WatchPlugins to be configured', async () => {
363+
const pluginPath = `${__dirname}/__fixtures__/plugin_path_with_config`;
364+
jest.doMock(
365+
pluginPath,
366+
() =>
367+
class WatchPlugin {
368+
constructor({config}) {
369+
this._key = config.key;
370+
this._prompt = config.prompt;
371+
}
372+
onKey() {}
373+
run() {}
374+
getUsageInfo() {
375+
return {
376+
key: this._key || 'z',
377+
prompt: this._prompt || 'default prompt',
378+
};
379+
}
380+
},
381+
{virtual: true},
382+
);
383+
384+
watch(
385+
Object.assign({}, globalConfig, {
386+
rootDir: __dirname,
387+
watchPlugins: [
388+
{
389+
config: {key: 'k', prompt: 'filter with a custom prompt'},
390+
path: pluginPath,
391+
},
392+
],
393+
}),
394+
contexts,
395+
pipe,
396+
hasteMapInstances,
397+
stdin,
398+
);
399+
400+
expect(pipe.write.mock.calls.reverse()[0]).toMatchSnapshot();
401+
});
402+
359403
it('allows WatchPlugins to hook into file system changes', async () => {
360404
const onFileChange = jest.fn();
361405
const pluginPath = `${__dirname}/__fixtures__/plugin_path_fs_change`;
@@ -373,7 +417,7 @@ describe('Watch mode flows', () => {
373417
watch(
374418
Object.assign({}, globalConfig, {
375419
rootDir: __dirname,
376-
watchPlugins: [pluginPath],
420+
watchPlugins: [{config: {}, path: pluginPath}],
377421
}),
378422
contexts,
379423
pipe,
@@ -414,7 +458,7 @@ describe('Watch mode flows', () => {
414458
watch(
415459
Object.assign({}, globalConfig, {
416460
rootDir: __dirname,
417-
watchPlugins: [pluginPath],
461+
watchPlugins: [{config: {}, path: pluginPath}],
418462
}),
419463
contexts,
420464
pipe,
@@ -474,7 +518,10 @@ describe('Watch mode flows', () => {
474518
watch(
475519
Object.assign({}, globalConfig, {
476520
rootDir: __dirname,
477-
watchPlugins: [pluginPath, pluginPath2],
521+
watchPlugins: [
522+
{config: {}, path: pluginPath},
523+
{config: {}, path: pluginPath2},
524+
],
478525
}),
479526
contexts,
480527
pipe,

packages/jest-cli/src/watch.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ export default function watch(
106106
const watchPlugins: Array<WatchPlugin> = INTERNAL_PLUGINS.map(
107107
InternalPlugin => new InternalPlugin({stdin, stdout: outputStream}),
108108
);
109-
110109
watchPlugins.forEach((plugin: WatchPlugin) => {
111110
const hookSubscriber = hooks.getSubscriber();
112111
if (plugin.apply) {
@@ -115,10 +114,11 @@ export default function watch(
115114
});
116115

117116
if (globalConfig.watchPlugins != null) {
118-
for (const pluginModulePath of globalConfig.watchPlugins) {
117+
for (const pluginWithConfig of globalConfig.watchPlugins) {
119118
// $FlowFixMe dynamic require
120-
const ThirdPartyPlugin = require(pluginModulePath);
119+
const ThirdPartyPlugin = require(pluginWithConfig.path);
121120
const plugin: WatchPlugin = new ThirdPartyPlugin({
121+
config: pluginWithConfig.config,
122122
stdin,
123123
stdout: outputStream,
124124
});

packages/jest-config/src/__tests__/normalize.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,8 +1127,8 @@ describe('watchPlugins', () => {
11271127
);
11281128

11291129
expect(options.watchPlugins).toEqual([
1130-
'/node_modules/my-watch-plugin',
1131-
'/root/path/to/plugin',
1130+
{config: {}, path: '/node_modules/my-watch-plugin'},
1131+
{config: {}, path: '/root/path/to/plugin'},
11321132
]);
11331133
});
11341134
});

packages/jest-config/src/normalize.js

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -579,13 +579,27 @@ export default function normalize(options: InitialOptions, argv: Argv) {
579579
value = options[key];
580580
break;
581581
case 'watchPlugins':
582-
value = (options[key] || []).map(watchPlugin =>
583-
resolve(newOptions.resolver, {
584-
filePath: watchPlugin,
585-
key,
586-
rootDir: options.rootDir,
587-
}),
588-
);
582+
value = (options[key] || []).map(watchPlugin => {
583+
if (typeof watchPlugin === 'string') {
584+
return {
585+
config: {},
586+
path: resolve(newOptions.resolver, {
587+
filePath: watchPlugin,
588+
key,
589+
rootDir: options.rootDir,
590+
}),
591+
};
592+
} else {
593+
return {
594+
config: watchPlugin[1] || {},
595+
path: resolve(newOptions.resolver, {
596+
filePath: watchPlugin[0],
597+
key,
598+
rootDir: options.rootDir,
599+
}),
600+
};
601+
}
602+
});
589603
break;
590604
}
591605
newOptions[key] = value;

types/Config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ export type InitialOptions = {
178178
watch?: boolean,
179179
watchAll?: boolean,
180180
watchman?: boolean,
181-
watchPlugins?: Array<string>,
181+
watchPlugins?: Array<string | [string, Object]>,
182182
};
183183

184184
export type SnapshotUpdateState = 'all' | 'new' | 'none';
@@ -235,7 +235,7 @@ export type GlobalConfig = {|
235235
watch: boolean,
236236
watchAll: boolean,
237237
watchman: boolean,
238-
watchPlugins: ?Array<string>,
238+
watchPlugins: ?Array<{path: string, config: Object}>,
239239
|};
240240

241241
export type ProjectConfig = {|

0 commit comments

Comments
 (0)