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(babel-jest): add option excludeJestPreset #15164

Merged
merged 1 commit into from
Jul 5, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

- `[babel-jest]` Add option `excludeJestPreset` to allow opting out of `babel-preset-jest` ([#15164](https://github.com/jestjs/jest/pull/15164))
- `[jest-circus, jest-cli, jest-config]` Add `waitNextEventLoopTurnForUnhandledRejectionEvents` flag to minimise performance impact of correct detection of unhandled promise rejections introduced in [#14315](https://github.com/jestjs/jest/pull/14315) ([#14681](https://github.com/jestjs/jest/pull/14681))
- `[jest-circus]` Add a `waitBeforeRetry` option to `jest.retryTimes` ([#14738](https://github.com/jestjs/jest/pull/14738))
- `[jest-circus]` Add a `retryImmediately` option to `jest.retryTimes` ([#14696](https://github.com/jestjs/jest/pull/14696))
Expand Down
12 changes: 12 additions & 0 deletions docs/CodeTransformation.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ Jest will cache the result of a transformation and attempt to invalidate that re

Jest ships with one transformer out of the box – [`babel-jest`](https://github.com/jestjs/jest/tree/main/packages/babel-jest#setup). It will load your project's Babel configuration and transform any file matching the `/\.[jt]sx?$/` RegExp (in other words, any `.js`, `.jsx`, `.ts` or `.tsx` file). In addition, `babel-jest` will inject the Babel plugin necessary for mock hoisting talked about in [ES Module mocking](ManualMocks.md#using-with-es-module-imports).

:::note

By default, `babel-jest` includes `babel-preset-jest`. You can disable this behavior by specifying `excludeJestPreset: true` to `babel-jest`. Note that this will also stop hoisting `jest.mock`, which may break your tests.

```json
"transform": {
"\\.[jt]sx?$": ["babel-jest", { "excludeJestPreset": true }],
}
```

:::

:::tip

Remember to include the default `babel-jest` transformer explicitly, if you wish to use it alongside with additional code preprocessors:
Expand Down
8 changes: 8 additions & 0 deletions packages/babel-jest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@ You can also pass further [babel options](https://babeljs.io/docs/options)
"\\.[jt]sx?$": ["babel-jest", { "extends": "./babel.config.js", "plugins": ["babel-plugin-transform-import-meta"] }]
},
```

By default, `babel-jest` includes `babel-preset-jest`. In addition to the babel options, we introduce a new option, `excludeJestPreset`, which allows you to disable this behavior. Note that this will break `jest.mock` hoisting.

```json
"transform": {
"\\.[jt]sx?$": ["babel-jest", { "excludeJestPreset": true }],
}
```
31 changes: 31 additions & 0 deletions packages/babel-jest/src/__tests__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,34 @@ test('can pass null to createTransformer', async () => {
}),
);
});

test('include babel-preset-jest by default', () => {
defaultBabelJestTransformer.process(sourceString, 'dummy_path.js', {
cacheFS: new Map<string, string>(),
config: makeProjectConfig(),
configString: JSON.stringify(makeProjectConfig()),
instrument: false,
transformerConfig: {},
} as TransformOptions<BabelTransformOptions>);

expect(loadPartialConfig).toHaveBeenCalledTimes(1);
expect(loadPartialConfig).toHaveBeenCalledWith(
expect.objectContaining({presets: [require.resolve('babel-preset-jest')]}),
);
});

test('can opting out of babel-preset-jest by passing excludeJestPreset: true', async () => {
const transformer = await createTransformer({excludeJestPreset: true});
transformer.process(sourceString, 'dummy_path.js', {
cacheFS: new Map<string, string>(),
config: makeProjectConfig(),
configString: JSON.stringify(makeProjectConfig()),
instrument: false,
transformerConfig: {},
} as TransformOptions<BabelTransformOptions>);

expect(loadPartialConfig).toHaveBeenCalledTimes(1);
expect(loadPartialConfig).toHaveBeenCalledWith(
expect.objectContaining({presets: []}),
);
});
41 changes: 24 additions & 17 deletions packages/babel-jest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import {createHash} from 'crypto';
import * as path from 'path';
import {
type TransformOptions as BabelTransformOptions,
type PartialConfig,
type TransformOptions,
transformSync as babelTransform,
transformAsync as babelTransformAsync,
} from '@babel/core';
Expand All @@ -23,6 +23,10 @@ import type {
} from '@jest/transform';
import {loadPartialConfig, loadPartialConfigAsync} from './loadBabelConfig';

interface TransformerConfig extends BabelTransformOptions {
excludeJestPreset?: boolean;
}

const THIS_FILE = fs.readFileSync(__filename);
const jestPresetPath = require.resolve('babel-preset-jest');
const babelIstanbulPlugin = require.resolve('babel-plugin-istanbul');
Expand All @@ -44,11 +48,11 @@ function assertLoadedBabelConfig(
}

function addIstanbulInstrumentation(
babelOptions: TransformOptions,
babelOptions: BabelTransformOptions,
transformOptions: JestTransformOptions,
): TransformOptions {
): BabelTransformOptions {
if (transformOptions.instrument) {
const copiedBabelOptions: TransformOptions = {...babelOptions};
const copiedBabelOptions: BabelTransformOptions = {...babelOptions};
copiedBabelOptions.auxiliaryCommentBefore = ' istanbul ignore next ';
// Copied from jest-runtime transform.js
copiedBabelOptions.plugins = [
Expand Down Expand Up @@ -106,7 +110,7 @@ function getCacheKeyFromConfig(
function loadBabelConfig(
cwd: string,
filename: string,
transformOptions: TransformOptions,
transformOptions: BabelTransformOptions,
): PartialConfig {
const babelConfig = loadPartialConfig(transformOptions);

Expand All @@ -118,7 +122,7 @@ function loadBabelConfig(
async function loadBabelConfigAsync(
cwd: string,
filename: string,
transformOptions: TransformOptions,
transformOptions: BabelTransformOptions,
): Promise<PartialConfig> {
const babelConfig = await loadPartialConfigAsync(transformOptions);

Expand All @@ -130,9 +134,9 @@ async function loadBabelConfigAsync(
function loadBabelOptions(
cwd: string,
filename: string,
transformOptions: TransformOptions,
transformOptions: BabelTransformOptions,
jestTransformOptions: JestTransformOptions,
): TransformOptions {
): BabelTransformOptions {
const {options} = loadBabelConfig(cwd, filename, transformOptions);

return addIstanbulInstrumentation(options, jestTransformOptions);
Expand All @@ -141,19 +145,19 @@ function loadBabelOptions(
async function loadBabelOptionsAsync(
cwd: string,
filename: string,
transformOptions: TransformOptions,
transformOptions: BabelTransformOptions,
jestTransformOptions: JestTransformOptions,
): Promise<TransformOptions> {
): Promise<BabelTransformOptions> {
const {options} = await loadBabelConfigAsync(cwd, filename, transformOptions);

return addIstanbulInstrumentation(options, jestTransformOptions);
}

export const createTransformer: TransformerCreator<
SyncTransformer<TransformOptions>,
TransformOptions
> = userOptions => {
const inputOptions = userOptions ?? {};
SyncTransformer<TransformerConfig>,
TransformerConfig
> = transformerConfig => {
const {excludeJestPreset, ...inputOptions} = transformerConfig ?? {};

const options = {
...inputOptions,
Expand All @@ -167,14 +171,17 @@ export const createTransformer: TransformerCreator<
},
compact: false,
plugins: inputOptions.plugins ?? [],
presets: [...(inputOptions.presets ?? []), jestPresetPath],
presets: [
...(inputOptions.presets ?? []),
...(excludeJestPreset === true ? [] : [jestPresetPath]),
],
sourceMaps: 'both',
} satisfies TransformOptions;
} satisfies BabelTransformOptions;

function mergeBabelTransformOptions(
filename: string,
transformOptions: JestTransformOptions,
): TransformOptions {
): BabelTransformOptions {
const {cwd, rootDir} = transformOptions.config;
// `cwd` and `root` first to allow incoming options to override it
return {
Expand Down
Loading