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

Transformer configs #7288

Merged
merged 27 commits into from Jun 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bd728ed
working version of passing config to transformers via config file.
eightypop Oct 16, 2018
e8c084b
ignore flow errors
eightypop Oct 26, 2018
2c4228d
refactor normalize for babel jest and fix tests
eightypop Oct 26, 2018
6b73a0d
remove fixme's from setup since flow annot was removed
eightypop Oct 26, 2018
eecd99b
e2e test
eightypop Oct 26, 2018
c918098
fix failing test and remove console log
eightypop Nov 24, 2018
3e322bb
fix typo
eightypop Nov 27, 2018
6956e54
update normalize to handle ts
eightypop Dec 31, 2018
653abf0
update changelog
eightypop Dec 31, 2018
04351cb
Update CHANGELOG.md
SimenB Jan 2, 2019
836e700
Update packages/jest-config/src/__tests__/normalize.test.js
thymikee Jan 12, 2019
7c57d0a
use preset instead of transform
eightypop Jan 12, 2019
c49fef3
update copyright headers
eightypop Jan 12, 2019
d2b958e
Update CHANGELOG.md
jeysal Jan 22, 2019
58f5ac9
add a specific configuration example.
eightypop Jan 22, 2019
f6e8179
clean up copy pasta :sweat-smile:
eightypop Jan 22, 2019
614f6df
Merge branch 'master' into transformer-configs
SimenB Jan 27, 2019
48af06b
Merge commit '544984ea118f248017f83ddb5bf10c21a69d9dd6' into transfor…
SimenB Jun 26, 2019
305930c
Merge commit '7ae3f076a03e24e570857db52ce43df263d22f67' into transfor…
SimenB Jun 26, 2019
118b1f2
Merge commit 'e998c9230cb78b3befe0b1b57b36fd5353e766f0' into transfor…
SimenB Jun 26, 2019
f933bd4
Merge commit 'ecf7636426ffba5530ad07b513f13179dc4f4e07' into transfor…
SimenB Jun 26, 2019
8556974
Merge branch 'master' into transformer-configs
SimenB Jun 26, 2019
b1a60e9
remove old files
SimenB Jun 26, 2019
c02aa9d
tweak normalize
SimenB Jun 26, 2019
00a5539
reduce diff
SimenB Jun 26, 2019
192f170
fix lint error
SimenB Jun 26, 2019
94c9a74
normalize for 3.5
SimenB Jun 26, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -9,6 +9,7 @@
- `[*]` Manage the global timeout with `--testTimeout` command line argument. ([#8456](https://github.com/facebook/jest/pull/8456))
- `[pretty-format]` Render custom displayName of memoized components
- `[jest-validate]` Allow `maxWorkers` as part of the `jest.config.js` ([#8565](https://github.com/facebook/jest/pull/8565))
- `[jest-runtime]` Allow passing configuration objects to transformers ([#7288](https://github.com/facebook/jest/pull/7288))

### Fixes

Expand Down
4 changes: 3 additions & 1 deletion docs/Configuration.md
Expand Up @@ -1072,14 +1072,16 @@ Default: `real`

Setting this value to `fake` allows the use of fake timers for functions such as `setTimeout`. Fake timers are useful when a piece of code sets a long timeout that we don't want to wait for in a test.

### `transform` [object<string, string>]
### `transform` [object<string, pathToTransformer | [pathToTransformer, object]>]

Default: `undefined`

A map from regular expressions to paths to transformers. A transformer is a module that provides a synchronous function for transforming source files. For example, if you wanted to be able to use a new language feature in your modules or tests that isn't yet supported by node, you might plug in one of many compilers that compile a future version of JavaScript to a current one. Example: see the [examples/typescript](https://github.com/facebook/jest/blob/master/examples/typescript/package.json#L16) example or the [webpack tutorial](Webpack.md).

Examples of such compilers include [Babel](https://babeljs.io/), [TypeScript](http://www.typescriptlang.org/) and [async-to-gen](http://github.com/leebyron/async-to-gen#jest).

You can pass configuration to a transformer like `{filePattern: ['path-to-transformer', {options}]}` For example, to configure babel-jest for non-default behavior, `{"\\.js$": ['babel-jest', {rootMode: "upward"}]}`

_Note: a transformer is only run once per file unless the file has changed. During development of a transformer it can be useful to run Jest with `--no-cache` to frequently [delete Jest's cache](Troubleshooting.md#caching-issues)._

_Note: if you are using the `babel-jest` transformer and want to use an additional code preprocessor, keep in mind that when "transform" is overwritten in any way the `babel-jest` is not loaded automatically anymore. If you want to use it to compile JavaScript code it has to be explicitly defined. See [babel-jest plugin](https://github.com/facebook/jest/tree/master/packages/babel-jest#setup)_
Expand Down
9 changes: 9 additions & 0 deletions e2e/__tests__/__snapshots__/transform.test.ts.snap
Expand Up @@ -35,3 +35,12 @@ All files | 83.33 | 100 | 50 | 80 | |
------------|----------|----------|----------|----------|-------------------|

`;

exports[`transformer-config instruments only specific files and collects coverage 1`] = `
"------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
------------|----------|----------|----------|----------|-------------------|
All files | 83.33 | 100 | 50 | 80 | |
Covered.js | 83.33 | 100 | 50 | 80 | 13 |
------------|----------|----------|----------|----------|-------------------|"
`;
26 changes: 26 additions & 0 deletions e2e/__tests__/transform.test.ts
Expand Up @@ -159,3 +159,29 @@ describe('ecmascript-modules-support', () => {
expect(json.numTotalTests).toBeGreaterThanOrEqual(1);
});
});

describe('transformer-config', () => {
const dir = path.resolve(__dirname, '..', 'transform/transformer-config');

beforeEach(() => {
run('yarn', dir);
});

it('runs transpiled code', () => {
// --no-cache because babel can cache stuff and result in false green
const {json} = runWithJson(dir, ['--no-cache']);
expect(json.success).toBe(true);
expect(json.numTotalTests).toBeGreaterThanOrEqual(1);
});

it('instruments only specific files and collects coverage', () => {
const {stdout} = runJest(dir, ['--coverage', '--no-cache'], {
stripAnsi: true,
});
expect(stdout).toMatch('Covered.js');
expect(stdout).not.toMatch('NotCovered.js');
expect(stdout).not.toMatch('ExcludedFromCoverage.js');
// coverage result should not change
expect(stdout).toMatchSnapshot();
});
});
1 change: 1 addition & 0 deletions e2e/transform/transformer-config/.babelrc
@@ -0,0 +1 @@
{}
12 changes: 12 additions & 0 deletions e2e/transform/transformer-config/NotCovered.js
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/

const thisFunctionIsNeverInstrumented = () => null;

module.exports = {
thisFunctionIsNeverInstrumented,
};
@@ -0,0 +1,15 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/

'use strict';

require('../this-directory-is-covered/ExcludedFromCoverage');

it('strips flowtypes using babel-jest and config passed to transformer', () => {
const a: string = 'a';
expect(a).toBe('a');
});
25 changes: 25 additions & 0 deletions e2e/transform/transformer-config/package.json
@@ -0,0 +1,25 @@
{
"dependencies": {
"@babel/preset-flow": "7.0.0"
},
"jest": {
"collectCoverageOnlyFrom": {
"<rootDir>/this-directory-is-covered/Covered.js": true,
"<rootDir>/this-directory-is-covered/ExcludedFromCoverage.js": true
},
"coveragePathIgnorePatterns": [
"ExcludedFromCoverage"
],
"testEnvironment": "node",
"transform": {
"\\.js$": [
"babel-jest",
{
"presets": [
"@babel/preset-flow"
]
}
]
}
}
}
@@ -0,0 +1,19 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/

const thisFunctionIsCovered = (): null => null;

thisFunctionIsCovered();

const thisFunctionIsNotCovered = (): void => {
throw new Error('Never Called');
};

module.exports = {
thisFunctionIsCovered,
thisFunctionIsNotCovered,
};
@@ -0,0 +1,15 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/

require('./Covered');
require('../NotCovered');

const thisFunctionIsNeverInstrumented = () => null;

module.exports = {
thisFunctionIsNeverInstrumented,
};
34 changes: 34 additions & 0 deletions e2e/transform/transformer-config/yarn.lock
@@ -0,0 +1,34 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


babel-plugin-syntax-flow@^6.8.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d"
integrity sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=

babel-plugin-transform-flow-strip-types@6.8.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.8.0.tgz#2351d85e3a52152e1a55d3f08ae635e21ece17a0"
integrity sha1-I1HYXjpSFS4aVdPwiuY14h7OF6A=
dependencies:
babel-plugin-syntax-flow "^6.8.0"
babel-runtime "^6.0.0"

babel-runtime@^6.0.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
integrity sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"

core-js@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
integrity sha1-TekR5mew6ukSTjQlS1OupvxhjT4=

regenerator-runtime@^0.10.0:
version "0.10.4"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.4.tgz#74cb6598d3ba2eb18694e968a40e2b3b4df9cf93"
integrity sha1-dMtlmNO6LrGGlOlopA4rO035z5M=
18 changes: 18 additions & 0 deletions packages/jest-config/src/__tests__/normalize.test.js
Expand Up @@ -331,6 +331,24 @@ describe('transform', () => {
['abs-path', '/qux/quux'],
]);
});
it("pulls in config if it's passed as an array", () => {
const {options} = normalize(
{
rootDir: '/root/',
transform: {
[DEFAULT_CSS_PATTERN]: '<rootDir>/node_modules/jest-regex-util',
[DEFAULT_JS_PATTERN]: ['babel-jest', {rootMode: 'upward'}],
'abs-path': '/qux/quux',
},
},
{},
);
expect(options.transform).toEqual([
[DEFAULT_CSS_PATTERN, '/root/node_modules/jest-regex-util'],
[DEFAULT_JS_PATTERN, require.resolve('babel-jest'), {rootMode: 'upward'}],
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if we pay any perf penalty for making this an array of variable length (previously always a tuple, now an array of 2 or 3 items). It's accessed before every file transform, so definitely something worth double-checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

wouldn't it be uniform in most cases that are using only one config file?

['abs-path', '/qux/quux'],
]);
});
});

describe('haste', () => {
Expand Down
95 changes: 55 additions & 40 deletions packages/jest-config/src/normalize.ts
Expand Up @@ -46,19 +46,29 @@ type AllOptions = Config.ProjectConfig & Config.GlobalConfig;
const createConfigError = (message: string) =>
new ValidationError(ERROR, message, DOCUMENTATION_NOTE);

const mergeOptionWithPreset = (
// TS 3.5 forces us to split these into 2
Copy link
Member

Choose a reason for hiding this comment

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

@jeysal is this something you know how to fix? 😀

Copy link
Member

Choose a reason for hiding this comment

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

worked without split on 3.4 (I forgot to run yarn).

This wonderful error on 3.5
image

Essentially, since the index signature does not match, it gets super confused even though we'll only be merging 1 at a time

const mergeModuleNameMapperWithPreset = (
options: Config.InitialOptions,
preset: Config.InitialOptions,
) => {
if (options['moduleNameMapper'] && preset['moduleNameMapper']) {
options['moduleNameMapper'] = {
...options['moduleNameMapper'],
...preset['moduleNameMapper'],
...options['moduleNameMapper'],
};
}
};

const mergeTransformWithPreset = (
options: Config.InitialOptions,
preset: Config.InitialOptions,
optionName: keyof Pick<
Config.InitialOptions,
'moduleNameMapper' | 'transform'
>,
) => {
if (options[optionName] && preset[optionName]) {
options[optionName] = {
...options[optionName],
...preset[optionName],
...options[optionName],
if (options['transform'] && preset['transform']) {
options['transform'] = {
...options['transform'],
...preset['transform'],
...options['transform'],
};
}
};
Expand Down Expand Up @@ -121,8 +131,8 @@ const setupPreset = (
options.modulePathIgnorePatterns,
);
}
mergeOptionWithPreset(options, preset, 'moduleNameMapper');
mergeOptionWithPreset(options, preset, 'transform');
mergeModuleNameMapperWithPreset(options, preset);
mergeTransformWithPreset(options, preset);

return {...preset, ...options};
};
Expand All @@ -140,27 +150,26 @@ const setupBabelJest = (options: Config.InitialOptions) => {
return regex.test('a.ts') || regex.test('a.tsx');
});

if (customJSPattern) {
const customJSTransformer = transform[customJSPattern];

if (customJSTransformer === 'babel-jest') {
babelJest = require.resolve('babel-jest');
transform[customJSPattern] = babelJest;
} else if (customJSTransformer.includes('babel-jest')) {
babelJest = customJSTransformer;
}
}

if (customTSPattern) {
const customTSTransformer = transform[customTSPattern];

if (customTSTransformer === 'babel-jest') {
babelJest = require.resolve('babel-jest');
transform[customTSPattern] = babelJest;
} else if (customTSTransformer.includes('babel-jest')) {
babelJest = customTSTransformer;
[customJSPattern, customTSPattern].forEach(pattern => {
if (pattern) {
const customTransformer = transform[pattern];
if (Array.isArray(customTransformer)) {
if (customTransformer[0] === 'babel-jest') {
babelJest = require.resolve('babel-jest');
customTransformer[0] = babelJest;
} else if (customTransformer[0].includes('babel-jest')) {
babelJest = customTransformer[0];
}
} else {
if (customTransformer === 'babel-jest') {
babelJest = require.resolve('babel-jest');
transform[pattern] = babelJest;
} else if (customTransformer.includes('babel-jest')) {
babelJest = customTransformer;
}
}
}
}
});
} else {
babelJest = require.resolve('babel-jest');
options.transform = {
Expand Down Expand Up @@ -620,14 +629,20 @@ export default function normalize(
const transform = oldOptions[key];
value =
transform &&
Object.keys(transform).map(regex => [
regex,
resolve(newOptions.resolver, {
filePath: transform[regex],
key,
rootDir: options.rootDir,
}),
]);
Object.keys(transform).map(regex => {
const transformElement = transform[regex];
return [
regex,
resolve(newOptions.resolver, {
filePath: Array.isArray(transformElement)
? transformElement[0]
: transformElement,
key,
rootDir: options.rootDir,
}),
...(Array.isArray(transformElement) ? [transformElement[1]] : []),
];
});
break;
case 'coveragePathIgnorePatterns':
case 'modulePathIgnorePatterns':
Expand Down