Skip to content

Commit

Permalink
Add shorthand for watch plugins and runners (#7213)
Browse files Browse the repository at this point in the history
  • Loading branch information
rogeliog authored and thymikee committed Oct 26, 2018
1 parent e41f0bb commit c22d9f5
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 34 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Features

- `[jest-config]` Add shorthand for watch plugins and runners ([#7213](https://github.com/facebook/jest/pull/7213))
- `[jest-config]` [**BREAKING**] Deprecate `setupTestFrameworkScriptFile` in favor of new `setupFilesAfterEnv` ([#7119](https://github.com/facebook/jest/pull/7119))
- `[jest-jasmine2/jest-circus/jest-cli]` Add test.todo ([#6996](https://github.com/facebook/jest/pull/6996))
- `[pretty-format]` Option to not escape strings in diff messages ([#5661](https://github.com/facebook/jest/pull/5661))
Expand Down
18 changes: 18 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,8 @@ This option allows you to use a custom runner instead of Jest's default test run
- [`jest-runner-tsc`](https://github.com/azz/jest-runner-tsc)
- [`jest-runner-prettier`](https://github.com/keplersj/jest-runner-prettier)

_Note: The `runner` property value can omit the `jest-runner-` prefix of the package name._

To write a test-runner, export a class with which accepts `globalConfig` in the constructor, and has a `runTests` method with the signature:

```ts
Expand Down Expand Up @@ -962,3 +964,19 @@ Default: `[]`
An array of RegExp patterns that are matched against all source file paths before re-running tests in watch mode. If the file path matches any of the patterns, when it is updated, it will not trigger a re-run of tests.

These patterns match against the full path. Use the `<rootDir>` string token to include the path to your project's root directory to prevent it from accidentally ignoring all of your files in different environments that may have different root directories. Example: `["<rootDir>/node_modules/"]`.

### `watchPlugins` [array<string | [string, Object]>]

Default: `[]`

This option allows you to use a custom watch plugins. Read more about watch plugins [here](watch-plugins).

Examples of watch plugins include:

- [`jest-watch-master`](https://github.com/rickhanlonii/jest-watch-master)
- [`jest-watch-select-projects`](https://github.com/rogeliog/jest-watch-select-projects)
- [`jest-watch-suspend`](https://github.com/unional/jest-watch-suspend)
- [`jest-watch-typeahead`](https://github.com/jest-community/jest-watch-typeahead)
- [`jest-watch-yarn-workspaces`](https://github.com/cameronhunter/jest-watch-directories/tree/master/packages/jest-watch-yarn-workspaces)

_Note: The values in the `watchPlugins` property value can omit the `jest-watch-` prefix of the package name._
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ exports[`rootDir throws if the options is missing a rootDir property 1`] = `
<red></>"
`;
exports[`runner throw error when a runner is not found 1`] = `
"<red><bold><bold>● <bold>Validation Error</>:</>
<red></>
<red> Jest Runner <bold>missing-runner</> cannot be found. Make sure the <bold>runner</> configuration option points to an existing node module.</>
<red></>
<red> <bold>Configuration Documentation:</></>
<red> https://jestjs.io/docs/configuration.html</>
<red></>"
`;
exports[`setupTestFrameworkScriptFile logs a deprecation warning when \`setupTestFrameworkScriptFile\` is used 1`] = `
"<yellow><bold><bold>●<bold> Deprecation Warning</>:</>
<yellow></>
Expand Down Expand Up @@ -93,3 +103,13 @@ exports[`testMatch throws if testRegex and testMatch are both specified 1`] = `
exports[`testPathPattern <regexForTestFiles> ignores invalid regular expressions and logs a warning 1`] = `"<red> Invalid testPattern a( supplied. Running all tests instead.</>"`;
exports[`testPathPattern --testPathPattern ignores invalid regular expressions and logs a warning 1`] = `"<red> Invalid testPattern a( supplied. Running all tests instead.</>"`;
exports[`watchPlugins throw error when a watch plugin is not found 1`] = `
"<red><bold><bold>● <bold>Validation Error</>:</>
<red></>
<red> Watch plugin <bold>missing-plugin</> cannot be found. Make sure the <bold>watchPlugins</> configuration option points to an existing node module.</>
<red></>
<red> <bold>Configuration Documentation:</></>
<red> https://jestjs.io/docs/configuration.html</>
<red></>"
`;
121 changes: 111 additions & 10 deletions packages/jest-config/src/__tests__/normalize.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -671,11 +671,8 @@ describe('testEnvironment', () => {
beforeEach(() => {
Resolver = require('jest-resolve');
Resolver.findNodeModule = jest.fn(name => {
if (name === 'jsdom') {
return 'node_modules/jsdom';
}
if (name === 'jest-environment-jsdom') {
return 'node_modules/jest-environment-jsdom';
if (['jsdom', 'jest-environment-jsdom'].includes(name)) {
return `node_modules/${name}`;
}
if (name.startsWith('/root')) {
return name;
Expand Down Expand Up @@ -1205,15 +1202,79 @@ describe('preset without setupFiles', () => {
});
});

describe('runner', () => {
let Resolver;
beforeEach(() => {
Resolver = require('jest-resolve');
Resolver.findNodeModule = jest.fn(name => {
if (['eslint', 'jest-runner-eslint', 'my-runner-foo'].includes(name)) {
return `node_modules/${name}`;
}
if (name.startsWith('/root')) {
return name;
}
return findNodeModule(name);
});
});

it('defaults to `jest-runner`', () => {
const {options} = normalize({rootDir: '/root'}, {});

expect(options.runner).toBe('jest-runner');
});

it('resolves to runners that do not have the prefix', () => {
const {options} = normalize(
{
rootDir: '/root/',
runner: 'my-runner-foo',
},
{},
);

expect(options.runner).toBe('node_modules/my-runner-foo');
});

it('resolves to runners and prefers jest-runner-`name`', () => {
const {options} = normalize(
{
rootDir: '/root/',
runner: 'eslint',
},
{},
);

expect(options.runner).toBe('node_modules/jest-runner-eslint');
});

it('throw error when a runner is not found', () => {
expect(() =>
normalize(
{
rootDir: '/root/',
runner: 'missing-runner',
},
{},
),
).toThrowErrorMatchingSnapshot();
});
});

describe('watchPlugins', () => {
let Resolver;
beforeEach(() => {
Resolver = require('jest-resolve');
Resolver.findNodeModule = jest.fn(name => {
if (name.startsWith(path.sep)) {
if (
['typeahead', 'jest-watch-typeahead', 'my-watch-plugin'].includes(name)
) {
return `node_modules/${name}`;
}

if (name.startsWith('/root')) {
return name;
}
return path.sep + 'node_modules' + path.sep + name;
return findNodeModule(name);
});
});

Expand All @@ -1223,20 +1284,60 @@ describe('watchPlugins', () => {
expect(options.watchPlugins).toEqual(undefined);
});

it('normalizes watchPlugins', () => {
it('resolves to watch plugins and prefers jest-watch-`name`', () => {
const {options} = normalize(
{
rootDir: '/root/',
watchPlugins: ['my-watch-plugin', '<rootDir>/path/to/plugin'],
watchPlugins: ['typeahead'],
},
{},
);

expect(options.watchPlugins).toEqual([
{config: {}, path: '/node_modules/my-watch-plugin'},
{config: {}, path: 'node_modules/jest-watch-typeahead'},
]);
});

it('resolves watch plugins that do not have the prefix', () => {
const {options} = normalize(
{
rootDir: '/root/',
watchPlugins: ['my-watch-plugin'],
},
{},
);

expect(options.watchPlugins).toEqual([
{config: {}, path: 'node_modules/my-watch-plugin'},
]);
});

it('normalizes multiple watchPlugins', () => {
const {options} = normalize(
{
rootDir: '/root/',
watchPlugins: ['jest-watch-typeahead', '<rootDir>/path/to/plugin'],
},
{},
);

expect(options.watchPlugins).toEqual([
{config: {}, path: 'node_modules/jest-watch-typeahead'},
{config: {}, path: '/root/path/to/plugin'},
]);
});

it('throw error when a watch plugin is not found', () => {
expect(() =>
normalize(
{
rootDir: '/root/',
watchPlugins: ['missing-plugin'],
},
{},
),
).toThrowErrorMatchingSnapshot();
});
});

describe('testPathPattern', () => {
Expand Down
22 changes: 16 additions & 6 deletions packages/jest-config/src/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {
_replaceRootDirTags,
escapeGlobCharacters,
getTestEnvironment,
getRunner,
getWatchPlugin,
resolve,
} from './utils';
import {DEFAULT_JS_PATTERN, DEFAULT_REPORTER_LABEL} from './constants';
Expand Down Expand Up @@ -394,7 +396,10 @@ export default function normalize(options: InitialOptions, argv: Argv) {
}

if (options.testEnvironment) {
options.testEnvironment = getTestEnvironment(options);
options.testEnvironment = getTestEnvironment({
rootDir: options.rootDir,
testEnvironment: options.testEnvironment,
});
}

if (!options.roots && options.testPathDirs) {
Expand Down Expand Up @@ -475,7 +480,6 @@ export default function normalize(options: InitialOptions, argv: Argv) {
case 'globalSetup':
case 'globalTeardown':
case 'moduleLoader':
case 'runner':
case 'snapshotResolver':
case 'testResultsProcessor':
case 'testRunner':
Expand All @@ -488,6 +492,14 @@ export default function normalize(options: InitialOptions, argv: Argv) {
rootDir: options.rootDir,
});
break;
case 'runner':
value =
options[key] &&
getRunner(newOptions.resolver, {
filePath: options[key],
rootDir: options.rootDir,
});
break;
case 'prettierPath':
// We only want this to throw if "prettierPath" is explicitly passed
// from config or CLI, and the requested path isn't found. Otherwise we
Expand Down Expand Up @@ -658,18 +670,16 @@ export default function normalize(options: InitialOptions, argv: Argv) {
if (typeof watchPlugin === 'string') {
return {
config: {},
path: resolve(newOptions.resolver, {
path: getWatchPlugin(newOptions.resolver, {
filePath: watchPlugin,
key,
rootDir: options.rootDir,
}),
};
} else {
return {
config: watchPlugin[1] || {},
path: resolve(newOptions.resolver, {
path: getWatchPlugin(newOptions.resolver, {
filePath: watchPlugin[0],
key,
rootDir: options.rootDir,
}),
};
Expand Down
Loading

0 comments on commit c22d9f5

Please sign in to comment.