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

feat: pass ESM options to Babel #9766

Merged
merged 7 commits into from Apr 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,8 @@

### Features

- `[babel-jest]` Support passing `supportsDynamicImport` and `supportsStaticESM` ([#9766](https://github.com/facebook/jest/pull/9766))

### Fixes

### Chore & Maintenance
Expand Down
2 changes: 1 addition & 1 deletion e2e/__tests__/__snapshots__/transform.test.ts.snap
Expand Up @@ -6,7 +6,7 @@ FAIL __tests__/ignoredFile.test.js

babel-jest: Babel ignores __tests__/ignoredFile.test.js - make sure to include the file in Jest's transformIgnorePatterns as well.

at loadBabelConfig (../../../packages/babel-jest/build/index.js:191:13)
at loadBabelConfig (../../../packages/babel-jest/build/index.js:227:13)
`;

exports[`babel-jest instruments only specific files and collects coverage 1`] = `
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-jest/package.json
Expand Up @@ -20,7 +20,7 @@
"dependencies": {
"@jest/transform": "^25.2.6",
"@jest/types": "^25.2.6",
"@types/babel__core": "^7.1.0",
"@types/babel__core": "^7.1.7",
"babel-plugin-istanbul": "^6.0.0",
"babel-preset-jest": "^25.2.6",
"chalk": "^3.0.0",
Expand Down
70 changes: 66 additions & 4 deletions packages/babel-jest/src/__tests__/index.ts
Expand Up @@ -5,9 +5,18 @@
* LICENSE file in the root directory of this source tree.
*/

import babelJest from '../index';
import babelJest = require('../index');
import {loadPartialConfig} from '../loadBabelConfig';
import {makeProjectConfig} from '../../../../TestUtils';

jest.mock('../loadBabelConfig', () => {
const actual = jest.requireActual('@babel/core');

return {
loadPartialConfig: jest.fn((...args) => actual.loadPartialConfig(...args)),
};
});

//Mock data for all the tests
const sourceString = `
const sum = (a, b) => a+b;
Expand All @@ -21,7 +30,11 @@ const customMultiply = (obj, mul) => {
customMultiply({a: 32, dummy: "test"}, 2);
`;

test(`Returns source string with inline maps when no transformOptions is passed`, () => {
beforeEach(() => {
jest.clearAllMocks();
});

test('Returns source string with inline maps when no transformOptions is passed', () => {
const result = babelJest.process(
sourceString,
'dummy_path.js',
Expand All @@ -32,6 +45,55 @@ test(`Returns source string with inline maps when no transformOptions is passed`
expect(result.map).toBeDefined();
expect(result.code).toMatch('//# sourceMappingURL');
expect(result.code).toMatch('customMultiply');
expect(result.map.sources).toEqual(['dummy_path.js']);
expect(JSON.stringify(result.map.sourcesContent)).toMatch('customMultiply');
expect(result.map!.sources).toEqual(['dummy_path.js']);
expect(JSON.stringify(result.map!.sourcesContent)).toMatch('customMultiply');
});

describe('caller option correctly merges from defaults and options', () => {
test.each([
[
{
supportsDynamicImport: true,
supportsStaticESM: true,
},
{
supportsDynamicImport: true,
supportsStaticESM: true,
},
],
[
{
supportsDynamicImport: false,
supportsStaticESM: false,
},
{
supportsDynamicImport: false,
supportsStaticESM: false,
},
],
[
{supportsStaticESM: false},
{
supportsDynamicImport: false,
supportsStaticESM: false,
},
],
[
{supportsDynamicImport: true},
{
supportsDynamicImport: true,
supportsStaticESM: false,
},
],
])('%j -> %j', (input, output) => {
babelJest.process(sourceString, 'dummy_path.js', makeProjectConfig(), {
instrument: false,
...input,
});

expect(loadPartialConfig).toHaveBeenCalledTimes(1);
expect(loadPartialConfig).toHaveBeenCalledWith(
expect.objectContaining({caller: {name: 'babel-jest', ...output}}),
);
});
});
65 changes: 48 additions & 17 deletions packages/babel-jest/src/index.ts
Expand Up @@ -8,14 +8,19 @@
import {createHash} from 'crypto';
import * as fs from 'fs';
import * as path from 'path';
import type {Transformer} from '@jest/transform';
import type {
TransformOptions as JestTransformOptions,
Transformer,
} from '@jest/transform';
import type {Config} from '@jest/types';
import {
PartialConfig,
PluginItem,
TransformCaller,
TransformOptions,
transformSync as babelTransform,
loadPartialConfig,
} from '@babel/core';
import {loadPartialConfig} from './loadBabelConfig';
import chalk = require('chalk');
import slash = require('slash');

Expand All @@ -27,28 +32,51 @@ const babelIstanbulPlugin = require.resolve('babel-plugin-istanbul');
interface BabelJestTransformer extends Transformer {
canInstrument: true;
}
interface BabelJestTransformOptions extends TransformOptions {
caller: TransformCaller;
compact: false;
plugins: Array<PluginItem>;
presets: Array<PluginItem>;
sourceMaps: 'both';
}

const createTransformer = (
options: TransformOptions = {},
inputOptions: TransformOptions = {},
): BabelJestTransformer => {
options = {
...options,
const options: BabelJestTransformOptions = {
...inputOptions,
caller: {
name: 'babel-jest',
supportsDynamicImport: false,
supportsStaticESM: false,
...inputOptions.caller,
},
compact: false,
plugins: (options && options.plugins) || [],
presets: ((options && options.presets) || []).concat(jestPresetPath),
plugins: inputOptions.plugins ?? [],
presets: (inputOptions.presets ?? []).concat(jestPresetPath),
sourceMaps: 'both',
};

function loadBabelConfig(
cwd: Config.Path,
filename: Config.Path,
transformOptions?: JestTransformOptions,
): PartialConfig {
// `cwd` first to allow incoming options to override it
const babelConfig = loadPartialConfig({cwd, ...options, filename});
const babelConfig = loadPartialConfig({
cwd,
...options,
caller: {
...options.caller,
supportsDynamicImport:
transformOptions?.supportsDynamicImport ??
options.caller.supportsDynamicImport,
supportsStaticESM:
transformOptions?.supportsStaticESM ??
options.caller.supportsStaticESM,
},
filename,
});

if (!babelConfig) {
throw new Error(
Expand All @@ -65,13 +93,14 @@ const createTransformer = (

return {
canInstrument: true,
getCacheKey(
fileData,
filename,
configString,
{config, instrument, rootDir},
) {
const babelOptions = loadBabelConfig(config.cwd, filename);
getCacheKey(fileData, filename, configString, cacheKeyOptions) {
const {config, instrument, rootDir} = cacheKeyOptions;

const babelOptions = loadBabelConfig(
config.cwd,
filename,
cacheKeyOptions,
);
const configPath = [
babelOptions.config || '',
babelOptions.babelrc || '',
Expand All @@ -98,9 +127,11 @@ const createTransformer = (
.digest('hex');
},
process(src, filename, config, transformOptions) {
const babelOptions = {...loadBabelConfig(config.cwd, filename).options};
const babelOptions = {
...loadBabelConfig(config.cwd, filename, transformOptions).options,
};

if (transformOptions && transformOptions.instrument) {
if (transformOptions?.instrument) {
babelOptions.auxiliaryCommentBefore = ' istanbul ignore next ';
// Copied from jest-runtime transform.js
babelOptions.plugins = (babelOptions.plugins || []).concat([
Expand Down
9 changes: 9 additions & 0 deletions packages/babel-jest/src/loadBabelConfig.ts
@@ -0,0 +1,9 @@
/**
* 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.
*/

// this is a separate file so it can be mocked in tests
export {loadPartialConfig} from '@babel/core';
6 changes: 1 addition & 5 deletions packages/jest-runtime/src/index.ts
Expand Up @@ -497,11 +497,7 @@ class Runtime {
): TransformationOptions {
return {
...options,
changedFiles: this._coverageOptions.changedFiles,
collectCoverage: this._coverageOptions.collectCoverage,
collectCoverageFrom: this._coverageOptions.collectCoverageFrom,
collectCoverageOnlyFrom: this._coverageOptions.collectCoverageOnlyFrom,
coverageProvider: this._coverageOptions.coverageProvider,
...this._coverageOptions,
};
}

Expand Down
1 change: 1 addition & 0 deletions packages/jest-runtime/tsconfig.json
Expand Up @@ -17,6 +17,7 @@
{"path": "../jest-snapshot"},
{"path": "../jest-source-map"},
{"path": "../jest-test-result"},
{"path": "../jest-transform"},
Copy link
Member Author

Choose a reason for hiding this comment

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

this was missing, sometimes leading to weird type errors

{"path": "../jest-types"},
{"path": "../jest-util"},
{"path": "../jest-validate"},
Expand Down
4 changes: 4 additions & 0 deletions packages/jest-transform/src/ScriptTransformer.ts
Expand Up @@ -101,6 +101,8 @@ export default class ScriptTransformer {
config: this._config,
instrument,
rootDir: this._config.rootDir,
supportsDynamicImport: false,
supportsStaticESM: false,
}),
)
.update(CACHE_VERSION)
Expand Down Expand Up @@ -285,6 +287,8 @@ export default class ScriptTransformer {
if (transform && shouldCallTransform) {
const processed = transform.process(content, filename, this._config, {
instrument,
supportsDynamicImport: false,
supportsStaticESM: false,
});

if (typeof processed === 'string') {
Expand Down
Expand Up @@ -71,6 +71,8 @@ Object {
},
"instrument": true,
"rootDir": "/",
"supportsDynamicImport": false,
"supportsStaticESM": false,
}
`;

Expand Down
1 change: 1 addition & 0 deletions packages/jest-transform/src/index.ts
Expand Up @@ -15,6 +15,7 @@ export type {
Transformer,
ShouldInstrumentOptions,
Options as TransformationOptions,
TransformOptions,
TransformResult,
TransformedSource,
} from './types';
Expand Down
15 changes: 10 additions & 5 deletions packages/jest-transform/src/types.ts
Expand Up @@ -22,6 +22,8 @@ export type Options = ShouldInstrumentOptions &
Partial<{
isCoreModule: boolean;
isInternalModule: boolean;
supportsDynamicImport: boolean;
supportsStaticESM: boolean;
}>;

// extends directly after https://github.com/sandersn/downlevel-dts/issues/33 is fixed
Expand All @@ -38,15 +40,18 @@ export type TransformedSource =

export type TransformResult = TransformTypes.TransformResult;

export type TransformOptions = {
export interface TransformOptions {
instrument: boolean;
};
// names are copied from babel
supportsDynamicImport?: boolean;
supportsStaticESM?: boolean;
}

export type CacheKeyOptions = {
// TODO: For Jest 26 we should combine these into one options shape
export interface CacheKeyOptions extends TransformOptions {
config: Config.ProjectConfig;
instrument: boolean;
rootDir: string;
};
}

export interface Transformer {
canInstrument?: boolean;
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Expand Up @@ -2137,10 +2137,10 @@
resolved "https://registry.yarnpkg.com/@types/babel__code-frame/-/babel__code-frame-7.0.1.tgz#baf2529c4abbfb5e4008c845efcfe39a187e2f99"
integrity sha512-FFfbQozKxYmOnCKFYV+EQprjBI7u2yaNc2ly/K9AhzyC8MzXtCtSRqptpw+HUJxhwCOo5mLwf1ATmzyhOaVbDg==

"@types/babel__core@^7.0.0", "@types/babel__core@^7.0.4", "@types/babel__core@^7.1.0":
version "7.1.6"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.6.tgz#16ff42a5ae203c9af1c6e190ed1f30f83207b610"
integrity sha512-tTnhWszAqvXnhW7m5jQU9PomXSiKXk2sFxpahXvI20SZKu9ylPi8WtIxueZ6ehDWikPT0jeFujMj3X4ZHuf3Tg==
"@types/babel__core@^7.0.0", "@types/babel__core@^7.0.4", "@types/babel__core@^7.1.0", "@types/babel__core@^7.1.7":
version "7.1.7"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89"
integrity sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw==
dependencies:
"@babel/parser" "^7.1.0"
"@babel/types" "^7.0.0"
Expand Down