From 320407773667e8a0346c1d8ddf3bafe079426d9d Mon Sep 17 00:00:00 2001 From: Hikari Hayashi Date: Fri, 5 Jul 2024 23:44:15 +0800 Subject: [PATCH] feat(babel-jest): add option excludeJestPreset --- CHANGELOG.md | 1 + docs/CodeTransformation.md | 12 +++++++ packages/babel-jest/README.md | 8 +++++ packages/babel-jest/src/__tests__/index.ts | 31 ++++++++++++++++ packages/babel-jest/src/index.ts | 41 +++++++++++++--------- 5 files changed, 76 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ccaacd976b9..66f669ff2465 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/docs/CodeTransformation.md b/docs/CodeTransformation.md index 14d96a16f649..010324e24593 100644 --- a/docs/CodeTransformation.md +++ b/docs/CodeTransformation.md @@ -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: diff --git a/packages/babel-jest/README.md b/packages/babel-jest/README.md index 6475e4472bb3..4299b5b11084 100644 --- a/packages/babel-jest/README.md +++ b/packages/babel-jest/README.md @@ -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 }], +} +``` diff --git a/packages/babel-jest/src/__tests__/index.ts b/packages/babel-jest/src/__tests__/index.ts index 2db776993b46..b18844220fc7 100644 --- a/packages/babel-jest/src/__tests__/index.ts +++ b/packages/babel-jest/src/__tests__/index.ts @@ -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(), + config: makeProjectConfig(), + configString: JSON.stringify(makeProjectConfig()), + instrument: false, + transformerConfig: {}, + } as TransformOptions); + + 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(), + config: makeProjectConfig(), + configString: JSON.stringify(makeProjectConfig()), + instrument: false, + transformerConfig: {}, + } as TransformOptions); + + expect(loadPartialConfig).toHaveBeenCalledTimes(1); + expect(loadPartialConfig).toHaveBeenCalledWith( + expect.objectContaining({presets: []}), + ); +}); diff --git a/packages/babel-jest/src/index.ts b/packages/babel-jest/src/index.ts index 300e8b3c8b21..b67b93de8781 100644 --- a/packages/babel-jest/src/index.ts +++ b/packages/babel-jest/src/index.ts @@ -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'; @@ -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'); @@ -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 = [ @@ -106,7 +110,7 @@ function getCacheKeyFromConfig( function loadBabelConfig( cwd: string, filename: string, - transformOptions: TransformOptions, + transformOptions: BabelTransformOptions, ): PartialConfig { const babelConfig = loadPartialConfig(transformOptions); @@ -118,7 +122,7 @@ function loadBabelConfig( async function loadBabelConfigAsync( cwd: string, filename: string, - transformOptions: TransformOptions, + transformOptions: BabelTransformOptions, ): Promise { const babelConfig = await loadPartialConfigAsync(transformOptions); @@ -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); @@ -141,19 +145,19 @@ function loadBabelOptions( async function loadBabelOptionsAsync( cwd: string, filename: string, - transformOptions: TransformOptions, + transformOptions: BabelTransformOptions, jestTransformOptions: JestTransformOptions, -): Promise { +): Promise { const {options} = await loadBabelConfigAsync(cwd, filename, transformOptions); return addIstanbulInstrumentation(options, jestTransformOptions); } export const createTransformer: TransformerCreator< - SyncTransformer, - TransformOptions -> = userOptions => { - const inputOptions = userOptions ?? {}; + SyncTransformer, + TransformerConfig +> = transformerConfig => { + const {excludeJestPreset, ...inputOptions} = transformerConfig ?? {}; const options = { ...inputOptions, @@ -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 {