diff --git a/CHANGELOG.md b/CHANGELOG.md index 288fd495717f..65d8e2fee6a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - `[jest-runtime]` [**BREAKING**] remove long-deprecated `jest.addMatchers`, `jest.resetModuleRegistry`, and `jest.runTimersToTime` ([#9853](https://github.com/facebook/jest/pull/9853)) - `[jest-transform]` Show enhanced `SyntaxError` message for all `SyntaxError`s ([#10749](https://github.com/facebook/jest/pull/10749)) - `[jest-transform]` [**BREAKING**] Refactor API to pass an options bag around rather than multiple boolean options ([#10753](https://github.com/facebook/jest/pull/10753)) +- `[jest-transform]` [**BREAKING**] Refactor API of transformers to pass an options bag rather than separate `config` and other options ### Chore & Maintenance diff --git a/docs/CodeTransformation.md b/docs/CodeTransformation.md new file mode 100644 index 000000000000..4748948459e2 --- /dev/null +++ b/docs/CodeTransformation.md @@ -0,0 +1,102 @@ +--- +id: code-transformation +title: Code Transformation +--- + +Jest runs the code in your project as JavaScript, but if you use some syntax not supported by Node.js out of the box (such as JSX, types from TypeScript, Vue templates etc.) then you'll need to transform that code into plain JavaScript, similar to what you would do when building for browsers. + +Jest supports this via the [`transform` configuration option](Configuration.md#transform-objectstring-pathtotransformer--pathtotransformer-object). + +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 aren't yet supported by Node, you might plug in one of many compilers that compile a future version of JavaScript to a current one. + +Jest will cache the result of a transformation and attempt to invalidate that result based on a number of factors, such as the source of the file being transformed and changing configuration. + +## Defaults + +Jest ships with one transformer out of the box - `babel-jest`. It will automatically load your project's Babel configuration and transform any file matching the following RegEx: `/\.[jt]sx?$/` meaning any `.js`, `.jsx`, `.ts` and `.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). + +If you override the `transform` configuration option `babel-jest` will no longer be active, and you'll need to add it manually if you wish to use Babel. + +## Writing custom transformers + +You can write you own transformer. The API of a transformer is as follows: + +```ts +interface Transformer { + /** + * Indicates if the transformer is capabale of instrumenting the code for code coverage. + * + * If V8 coverage is _not_ active, and this is `true`, Jest will assume the code is instrumented. + * If V8 coverage is _not_ active, and this is `false`. Jest will instrument the code returned by this transformer using Babel. + */ + canInstrument?: boolean; + createTransformer?: (options?: OptionType) => Transformer; + + getCacheKey?: ( + sourceText: string, + sourcePath: string, + options: TransformOptions, + ) => string; + + process: ( + sourceText: string, + sourcePath: string, + options: TransformOptions, + ) => TransformedSource; +} + +interface TransformOptions { + config: Config.ProjectConfig; + /** A stringified version of the configuration - useful in cache busting */ + configString: string; + instrument: boolean; + // names are copied from babel: https://babeljs.io/docs/en/options#caller + supportsDynamicImport: boolean; + supportsExportNamespaceFrom: boolean; + supportsStaticESM: boolean; + supportsTopLevelAwait: boolean; +} + +type TransformedSource = + | {code: string; map?: RawSourceMap | string | null} + | string; + +// Config.ProjectConfig can be seen in in code [here](https://github.com/facebook/jest/blob/v26.6.3/packages/jest-types/src/Config.ts#L323) +// RawSourceMap comes from [`source-map`](https://github.com/mozilla/source-map/blob/0.6.1/source-map.d.ts#L6-L12) +``` + +As can be seen, only `process` is mandatory to implement, although we highly recommend implementing `getCacheKey` as well, so we don't waste resources transpiling the same source file when we can read its previous result from disk. You can use [`@jest/create-cache-key-function`](https://www.npmjs.com/package/@jest/create-cache-key-function) to help implement it. + +Note that [ECMAScript module](ECMAScriptModules.md) support is indicated by the passed in `supports*` options. Specifically `supportsDynamicImport: true` means the transformer can return `import()` expressions, which is supported by both ESM and CJS. If `supportsStaticESM: true` it means top level `import` statements are supported and the code will be interpreted as ESM and not CJS. See [Node's docs](https://nodejs.org/api/esm.html#esm_differences_between_es_modules_and_commonjs) for details on the differences. + +### Examples + +### TypeScript with type checking + +While `babel-jest` by default will transpile TypeScript files, Babel will not verify the types. If you want that you can use [`ts-jest`](https://github.com/kulshekhar/ts-jest). + +#### Transforming images to their path + +Importing images is a way to include them in your browser bundle, but they are not valid JavaScript. One way of handling it in Jest is to replace the imported value with its filename. + +```js +// fileTransformer.js +const path = require('path'); + +module.exports = { + process(src, filename, config, options) { + return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';'; + }, +}; +``` + +```js +// jest.config.js + +module.exports = { + transform: { + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/fileTransformer.js', + }, +}; +``` diff --git a/docs/Configuration.md b/docs/Configuration.md index 9a2605816768..1e4d164b125c 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -1263,8 +1263,7 @@ Examples of such compilers include: - [Babel](https://babeljs.io/) - [TypeScript](http://www.typescriptlang.org/) -- [async-to-gen](http://github.com/leebyron/async-to-gen#jest) -- To build your own please visit the [Custom Transformer](TutorialReact.md#custom-transformers) section +- To build your own please visit the [Custom Transformer](CodeTransformation.md#writing-custom-transformers) section 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"}]}` diff --git a/docs/TutorialReact.md b/docs/TutorialReact.md index 491cbd798b85..cca7c1ffd7bf 100644 --- a/docs/TutorialReact.md +++ b/docs/TutorialReact.md @@ -304,7 +304,7 @@ The code for this example is available at [examples/enzyme](https://github.com/f ### Custom transformers -If you need more advanced functionality, you can also build your own transformer. Instead of using babel-jest, here is an example of using babel: +If you need more advanced functionality, you can also build your own transformer. Instead of using `babel-jest`, here is an example of using `@babel/core`: ```javascript // custom-transformer.js @@ -320,7 +320,7 @@ module.exports = { presets: [jestPreset], }); - return result ? result.code : src; + return result || src; }, }; ``` @@ -329,7 +329,7 @@ Don't forget to install the `@babel/core` and `babel-preset-jest` packages for t To make this work with Jest you need to update your Jest configuration with this: `"transform": {"\\.js$": "path/to/custom-transformer.js"}`. -If you'd like to build a transformer with babel support, you can also use babel-jest to compose one and pass in your custom configuration options: +If you'd like to build a transformer with babel support, you can also use `babel-jest` to compose one and pass in your custom configuration options: ```javascript const babelJest = require('babel-jest'); @@ -338,3 +338,5 @@ module.exports = babelJest.createTransformer({ presets: ['my-custom-preset'], }); ``` + +See [dedicated docs](CodeTransformation.md#writing-custom-transformers) for more details. diff --git a/e2e/coverage-transform-instrumented/preprocessor.js b/e2e/coverage-transform-instrumented/preprocessor.js index 4d4b550fb020..b2792096ce55 100644 --- a/e2e/coverage-transform-instrumented/preprocessor.js +++ b/e2e/coverage-transform-instrumented/preprocessor.js @@ -18,16 +18,16 @@ const options = { module.exports = { canInstrument: true, - process(src, filename, config, transformOptions) { + process(src, filename, transformOptions) { options.filename = filename; - if (transformOptions && transformOptions.instrument) { + if (transformOptions.instrument) { options.auxiliaryCommentBefore = ' istanbul ignore next '; options.plugins = [ [ babelIstanbulPlugin, { - cwd: config.rootDir, + cwd: transformOptions.config.rootDir, exclude: [], }, ], diff --git a/e2e/snapshot-serializers/transformer.js b/e2e/snapshot-serializers/transformer.js index 834dd7b59e18..5606ac36381f 100644 --- a/e2e/snapshot-serializers/transformer.js +++ b/e2e/snapshot-serializers/transformer.js @@ -8,7 +8,7 @@ 'use strict'; module.exports = { - process(src, filename, config, options) { + process(src, filename) { if (/bar.js$/.test(filename)) { return `${src};\nmodule.exports = createPlugin('bar');`; } diff --git a/e2e/transform/custom-instrumenting-preprocessor/preprocessor.js b/e2e/transform/custom-instrumenting-preprocessor/preprocessor.js index 8b82efc7783c..b440dd977ed6 100644 --- a/e2e/transform/custom-instrumenting-preprocessor/preprocessor.js +++ b/e2e/transform/custom-instrumenting-preprocessor/preprocessor.js @@ -7,7 +7,7 @@ module.exports = { canInstrument: true, - process(src, filename, config, options) { + process(src, filename, options) { src = `${src};\nglobal.__PREPROCESSED__ = true;`; if (options.instrument) { diff --git a/e2e/transform/multiple-transformers/cssPreprocessor.js b/e2e/transform/multiple-transformers/cssPreprocessor.js index 1e1ddf67f070..5ca52dd30e54 100644 --- a/e2e/transform/multiple-transformers/cssPreprocessor.js +++ b/e2e/transform/multiple-transformers/cssPreprocessor.js @@ -6,7 +6,7 @@ */ module.exports = { - process(src, filename, config, options) { + process() { return ` module.exports = { root: 'App-root', diff --git a/e2e/transform/multiple-transformers/filePreprocessor.js b/e2e/transform/multiple-transformers/filePreprocessor.js index 66c2a52e0f5a..c49b641e62d2 100644 --- a/e2e/transform/multiple-transformers/filePreprocessor.js +++ b/e2e/transform/multiple-transformers/filePreprocessor.js @@ -8,7 +8,7 @@ const path = require('path'); module.exports = { - process(src, filename, config, options) { + process(src, filename) { return ` module.exports = '${path.basename(filename)}'; `; diff --git a/package.json b/package.json index f0f6218ea3ab..3bea730d2ab7 100644 --- a/package.json +++ b/package.json @@ -144,6 +144,7 @@ }, "resolutions": { "@types/jest/jest-diff": "^25.1.0", - "@types/jest/pretty-format": "^25.1.0" + "@types/jest/pretty-format": "^25.1.0", + "fbjs-scripts": "patch:fbjs-scripts@^1.1.0#./patches/fbjs-scripts.patch" } } diff --git a/packages/babel-jest/src/__tests__/index.ts b/packages/babel-jest/src/__tests__/index.ts index 4ee2960bd65e..445a50d8dec8 100644 --- a/packages/babel-jest/src/__tests__/index.ts +++ b/packages/babel-jest/src/__tests__/index.ts @@ -35,11 +35,11 @@ beforeEach(() => { }); test('Returns source string with inline maps when no transformOptions is passed', () => { - const result = babelJest.process( - sourceString, - 'dummy_path.js', - makeProjectConfig(), - ) as any; + const result = babelJest.process(sourceString, 'dummy_path.js', { + config: makeProjectConfig(), + configString: JSON.stringify(makeProjectConfig()), + instrument: false, + }) as any; expect(typeof result).toBe('object'); expect(result.code).toBeDefined(); expect(result.map).toBeDefined(); @@ -86,7 +86,9 @@ describe('caller option correctly merges from defaults and options', () => { }, ], ])('%j -> %j', (input, output) => { - babelJest.process(sourceString, 'dummy_path.js', makeProjectConfig(), { + babelJest.process(sourceString, 'dummy_path.js', { + config: makeProjectConfig(), + configString: JSON.stringify(makeProjectConfig()), instrument: false, ...input, }); @@ -107,7 +109,9 @@ describe('caller option correctly merges from defaults and options', () => { test('can pass null to createTransformer', () => { const transformer = babelJest.createTransformer(null); - transformer.process(sourceString, 'dummy_path.js', makeProjectConfig(), { + transformer.process(sourceString, 'dummy_path.js', { + config: makeProjectConfig(), + configString: JSON.stringify(makeProjectConfig()), instrument: false, }); diff --git a/packages/babel-jest/src/index.ts b/packages/babel-jest/src/index.ts index 07181095ccc7..75e095729cc5 100644 --- a/packages/babel-jest/src/index.ts +++ b/packages/babel-jest/src/index.ts @@ -9,8 +9,6 @@ import {createHash} from 'crypto'; import * as path from 'path'; import { PartialConfig, - PluginItem, - TransformCaller, TransformOptions, transformSync as babelTransform, } from '@babel/core'; @@ -28,23 +26,12 @@ const THIS_FILE = fs.readFileSync(__filename); const jestPresetPath = require.resolve('babel-preset-jest'); const babelIstanbulPlugin = require.resolve('babel-plugin-istanbul'); -// Narrow down the types -interface BabelJestTransformer extends Transformer { - canInstrument: true; -} -interface BabelJestTransformOptions extends TransformOptions { - caller: TransformCaller; - compact: false; - plugins: Array; - presets: Array; - sourceMaps: 'both'; -} - -const createTransformer = ( - userOptions?: TransformOptions | null, -): BabelJestTransformer => { - const inputOptions: TransformOptions = userOptions ?? {}; - const options: BabelJestTransformOptions = { +type CreateTransformer = Transformer['createTransformer']; + +const createTransformer: CreateTransformer = userOptions => { + const inputOptions = userOptions ?? {}; + + const options = { ...inputOptions, caller: { name: 'babel-jest', @@ -58,7 +45,7 @@ const createTransformer = ( plugins: inputOptions.plugins ?? [], presets: (inputOptions.presets ?? []).concat(jestPresetPath), sourceMaps: 'both', - }; + } as const; function loadBabelConfig( cwd: Config.Path, @@ -102,13 +89,13 @@ const createTransformer = ( return { canInstrument: true, - getCacheKey(fileData, filename, configString, cacheKeyOptions) { - const {config, instrument, rootDir} = cacheKeyOptions; + getCacheKey(sourceText, sourcePath, transformOptions) { + const {config, configString, instrument} = transformOptions; const babelOptions = loadBabelConfig( config.cwd, - filename, - cacheKeyOptions, + sourcePath, + transformOptions, ); const configPath = [ babelOptions.config || '', @@ -120,9 +107,9 @@ const createTransformer = ( .update('\0', 'utf8') .update(JSON.stringify(babelOptions.options)) .update('\0', 'utf8') - .update(fileData) + .update(sourceText) .update('\0', 'utf8') - .update(path.relative(rootDir, filename)) + .update(path.relative(config.rootDir, sourcePath)) .update('\0', 'utf8') .update(configString) .update('\0', 'utf8') @@ -135,9 +122,13 @@ const createTransformer = ( .update(process.env.BABEL_ENV || '') .digest('hex'); }, - process(src, filename, config, transformOptions) { + process(sourceText, sourcePath, transformOptions) { const babelOptions = { - ...loadBabelConfig(config.cwd, filename, transformOptions).options, + ...loadBabelConfig( + transformOptions.config.cwd, + sourcePath, + transformOptions, + ).options, }; if (transformOptions?.instrument) { @@ -148,14 +139,14 @@ const createTransformer = ( babelIstanbulPlugin, { // files outside `cwd` will not be instrumented - cwd: config.rootDir, + cwd: transformOptions.config.rootDir, exclude: [], }, ], ]); } - const transformResult = babelTransform(src, babelOptions); + const transformResult = babelTransform(sourceText, babelOptions); if (transformResult) { const {code, map} = transformResult; @@ -164,14 +155,12 @@ const createTransformer = ( } } - return src; + return sourceText; }, }; }; -const transformer: BabelJestTransformer & { - createTransformer: (options?: TransformOptions) => BabelJestTransformer; -} = { +const transformer: Transformer = { ...createTransformer(), // Assigned here so only the exported transformer has `createTransformer`, // instead of all created transformers by the function diff --git a/packages/jest-create-cache-key-function/src/index.ts b/packages/jest-create-cache-key-function/src/index.ts index e606e64f14e8..63f9fbd3add8 100644 --- a/packages/jest-create-cache-key-function/src/index.ts +++ b/packages/jest-create-cache-key-function/src/index.ts @@ -12,18 +12,34 @@ import {readFileSync} from 'fs'; import {relative} from 'path'; import type {Config} from '@jest/types'; -type CacheKeyOptions = { +type OldCacheKeyOptions = { config: Config.ProjectConfig; instrument: boolean; }; -type GetCacheKeyFunction = ( +// Should mirror `import('@jest/transform').TransformOptions` +type NewCacheKeyOptions = { + config: Config.ProjectConfig; + configString: string; + instrument: boolean; +}; + +type OldGetCacheKeyFunction = ( fileData: string, filePath: Config.Path, configStr: string, - options: CacheKeyOptions, + options: OldCacheKeyOptions, ) => string; +// Should mirror `import('@jest/transform').Transformer['getCacheKey']` +type NewGetCacheKeyFunction = ( + sourceText: string, + sourcePath: Config.Path, + options: NewCacheKeyOptions, +) => string; + +type GetCacheKeyFunction = OldGetCacheKeyFunction | NewGetCacheKeyFunction; + function getGlobalCacheKey(files: Array, values: Array) { return [ process.env.NODE_ENV, @@ -39,14 +55,18 @@ function getGlobalCacheKey(files: Array, values: Array) { } function getCacheKeyFunction(globalCacheKey: string): GetCacheKeyFunction { - return (src, file, _configString, options) => { - const {config, instrument} = options; + return (sourceText, sourcePath, configString, options) => { + // Jest 27 passes a single options bag which contains `configString` rather than as a separate argument. + // We can hide that API difference, though, so this module is usable for both jest@<27 and jest@>=27 + const inferredOptions = options || configString; + const {config, instrument} = inferredOptions; + return createHash('md5') .update(globalCacheKey) .update('\0', 'utf8') - .update(src) + .update(sourceText) .update('\0', 'utf8') - .update(config.rootDir ? relative(config.rootDir, file) : '') + .update(config.rootDir ? relative(config.rootDir, sourcePath) : '') .update('\0', 'utf8') .update(instrument ? 'instrument' : '') .digest('hex'); diff --git a/packages/jest-repl/src/cli/repl.ts b/packages/jest-repl/src/cli/repl.ts index 831b2323489a..c5211f5354cd 100644 --- a/packages/jest-repl/src/cli/repl.ts +++ b/packages/jest-repl/src/cli/repl.ts @@ -28,7 +28,15 @@ const evalCommand: repl.REPLEval = ( const transformResult = transformer.process( cmd, jestGlobalConfig.replname || 'jest.js', - jestProjectConfig, + { + config: jestProjectConfig, + configString: JSON.stringify(jestProjectConfig), + instrument: false, + supportsDynamicImport: false, + supportsExportNamespaceFrom: false, + supportsStaticESM: false, + supportsTopLevelAwait: false, + }, ); cmd = typeof transformResult === 'string' diff --git a/packages/jest-reporters/src/generateEmptyCoverage.ts b/packages/jest-reporters/src/generateEmptyCoverage.ts index cc23ba8c0339..443293c9f782 100644 --- a/packages/jest-reporters/src/generateEmptyCoverage.ts +++ b/packages/jest-reporters/src/generateEmptyCoverage.ts @@ -70,7 +70,13 @@ export default function ( const {code} = new ScriptTransformer(config).transformSource( filename, source, - {instrument: true}, + { + instrument: true, + supportsDynamicImport: true, + supportsExportNamespaceFrom: true, + supportsStaticESM: true, + supportsTopLevelAwait: true, + }, ); // TODO: consider passing AST const extracted = readInitialCoverage(code); diff --git a/packages/jest-transform/src/ScriptTransformer.ts b/packages/jest-transform/src/ScriptTransformer.ts index f99310ab3911..61540e9d5a0e 100644 --- a/packages/jest-transform/src/ScriptTransformer.ts +++ b/packages/jest-transform/src/ScriptTransformer.ts @@ -28,7 +28,7 @@ import handlePotentialSyntaxError from './enhanceUnexpectedTokenMessage'; import shouldInstrument from './shouldInstrument'; import type { Options, - TransformOptions, + ReducedTransformOptions, TransformResult, TransformedSource, Transformer, @@ -93,7 +93,7 @@ export default class ScriptTransformer { private _getCacheKey( fileData: string, filename: Config.Path, - options: TransformOptions, + options: ReducedTransformOptions, ): string { const configString = this._cache.configString; const transformer = this._getTransformer(filename); @@ -101,14 +101,10 @@ export default class ScriptTransformer { if (transformer && typeof transformer.getCacheKey === 'function') { return createHash('md5') .update( - transformer.getCacheKey(fileData, filename, configString, { + transformer.getCacheKey(fileData, filename, { + ...options, config: this._config, - instrument: options.instrument, - rootDir: this._config.rootDir, - supportsDynamicImport: options.supportsDynamicImport, - supportsExportNamespaceFrom: options.supportsExportNamespaceFrom, - supportsStaticESM: options.supportsStaticESM, - supportsTopLevelAwait: options.supportsTopLevelAwait, + configString, }), ) .update(CACHE_VERSION) @@ -127,7 +123,7 @@ export default class ScriptTransformer { private _getFileCachePath( filename: Config.Path, content: string, - options: TransformOptions, + options: ReducedTransformOptions, ): Config.Path { const baseCacheDir = HasteMap.getCacheFilePath( this._config.cacheDirectory, @@ -206,7 +202,7 @@ export default class ScriptTransformer { filename: Config.Path, input: TransformedSource, canMapToInput: boolean, - options: TransformOptions, + options: ReducedTransformOptions, ): TransformedSource { const inputCode = typeof input === 'string' ? input : input.code; const inputMap = typeof input === 'string' ? null : input.map; @@ -256,7 +252,7 @@ export default class ScriptTransformer { transformSource( filepath: Config.Path, content: string, - options: TransformOptions, + options: ReducedTransformOptions, ): TransformResult { const filename = tryRealpath(filepath); const transform = this._getTransformer(filename); @@ -290,12 +286,11 @@ export default class ScriptTransformer { }; if (transform && shouldCallTransform) { - const processed = transform.process( - content, - filename, - this._config, - options, - ); + const processed = transform.process(content, filename, { + ...options, + config: this._config, + configString: this._cache.configString, + }); if (typeof processed === 'string') { transformed.code = processed; @@ -376,7 +371,7 @@ export default class ScriptTransformer { private _transformAndBuildScript( filename: Config.Path, options: Options, - transformOptions: TransformOptions, + transformOptions: ReducedTransformOptions, fileSource?: string, ): TransformResult { const {isCoreModule, isInternalModule} = options; @@ -471,17 +466,23 @@ export default class ScriptTransformer { requireAndTranspileModule( moduleName: string, callback?: (module: ModuleType) => void, - transformOptions?: TransformOptions, + transformOptions?: ReducedTransformOptions, ): ModuleType; requireAndTranspileModule( moduleName: string, callback?: (module: ModuleType) => Promise, - transformOptions?: TransformOptions, + transformOptions?: ReducedTransformOptions, ): Promise; requireAndTranspileModule( moduleName: string, callback?: (module: ModuleType) => void | Promise, - transformOptions: TransformOptions = {instrument: false}, + transformOptions: ReducedTransformOptions = { + instrument: false, + supportsDynamicImport: false, + supportsExportNamespaceFrom: false, + supportsStaticESM: false, + supportsTopLevelAwait: false, + }, ): ModuleType | Promise { // Load the transformer to avoid a cycle where we need to load a // transformer in order to transform it in the require hooks diff --git a/packages/jest-transform/src/__tests__/__snapshots__/script_transformer.test.ts.snap b/packages/jest-transform/src/__tests__/__snapshots__/script_transformer.test.ts.snap index c9021bd66fb9..d935cd744c3e 100644 --- a/packages/jest-transform/src/__tests__/__snapshots__/script_transformer.test.ts.snap +++ b/packages/jest-transform/src/__tests__/__snapshots__/script_transformer.test.ts.snap @@ -1,80 +1,98 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ScriptTransformer passes expected transform options to getCacheKey 1`] = ` -Object { - "config": Object { - "automock": false, - "cache": true, - "cacheDirectory": "/cache/", - "clearMocks": false, - "coveragePathIgnorePatterns": Array [], - "cwd": "/test_root_dir/", - "detectLeaks": false, - "detectOpenHandles": false, - "displayName": undefined, - "errorOnDeprecated": false, - "extraGlobals": Array [], - "filter": undefined, - "forceCoverageMatch": Array [], - "globalSetup": undefined, - "globalTeardown": undefined, - "globals": Object {}, - "haste": Object {}, - "injectGlobals": true, - "moduleDirectories": Array [], - "moduleFileExtensions": Array [ - "js", - ], - "moduleLoader": "/test_module_loader_path", - "moduleNameMapper": Array [], - "modulePathIgnorePatterns": Array [], - "modulePaths": Array [], - "name": "test", - "prettierPath": "prettier", - "resetMocks": false, - "resetModules": false, - "resolver": undefined, - "restoreMocks": false, - "rootDir": "/", - "roots": Array [], - "runner": "jest-runner", - "setupFiles": Array [], - "setupFilesAfterEnv": Array [], - "skipFilter": false, - "skipNodeResolution": false, - "slowTestThreshold": 5, - "snapshotResolver": undefined, - "snapshotSerializers": Array [], - "testEnvironment": "node", - "testEnvironmentOptions": Object {}, - "testLocationInResults": false, - "testMatch": Array [], - "testPathIgnorePatterns": Array [], - "testRegex": Array [ - "\\\\.test\\\\.js$", - ], - "testRunner": "jest-jasmine2", - "testURL": "http://localhost", - "timers": "real", - "transform": Array [ - Array [ - "\\\\.js$", - "test_preprocessor", - Object {}, - ], - ], - "transformIgnorePatterns": Array [ - "/node_modules/", +[MockFunction] { + "calls": Array [ + Array [ + "module.exports = \\"banana\\";", + "/fruits/banana.js", + Object { + "collectCoverage": true, + "collectCoverageFrom": Array [], + "collectCoverageOnlyFrom": undefined, + "config": Object { + "automock": false, + "cache": true, + "cacheDirectory": "/cache/", + "clearMocks": false, + "coveragePathIgnorePatterns": Array [], + "cwd": "/test_root_dir/", + "detectLeaks": false, + "detectOpenHandles": false, + "displayName": undefined, + "errorOnDeprecated": false, + "extraGlobals": Array [], + "filter": undefined, + "forceCoverageMatch": Array [], + "globalSetup": undefined, + "globalTeardown": undefined, + "globals": Object {}, + "haste": Object {}, + "injectGlobals": true, + "moduleDirectories": Array [], + "moduleFileExtensions": Array [ + "js", + ], + "moduleLoader": "/test_module_loader_path", + "moduleNameMapper": Array [], + "modulePathIgnorePatterns": Array [], + "modulePaths": Array [], + "name": "test", + "prettierPath": "prettier", + "resetMocks": false, + "resetModules": false, + "resolver": undefined, + "restoreMocks": false, + "rootDir": "/", + "roots": Array [], + "runner": "jest-runner", + "setupFiles": Array [], + "setupFilesAfterEnv": Array [], + "skipFilter": false, + "skipNodeResolution": false, + "slowTestThreshold": 5, + "snapshotResolver": undefined, + "snapshotSerializers": Array [], + "testEnvironment": "node", + "testEnvironmentOptions": Object {}, + "testLocationInResults": false, + "testMatch": Array [], + "testPathIgnorePatterns": Array [], + "testRegex": Array [ + "\\\\.test\\\\.js$", + ], + "testRunner": "jest-jasmine2", + "testURL": "http://localhost", + "timers": "real", + "transform": Array [ + Array [ + "\\\\.js$", + "test_preprocessor", + Object {}, + ], + ], + "transformIgnorePatterns": Array [ + "/node_modules/", + ], + "unmockedModulePathPatterns": undefined, + "watchPathIgnorePatterns": Array [], + }, + "configString": "{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extraGlobals\\":[],\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleLoader\\":\\"/test_module_loader_path\\",\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-jasmine2\\",\\"testURL\\":\\"http://localhost\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}", + "coverageProvider": "babel", + "instrument": true, + "supportsDynamicImport": false, + "supportsExportNamespaceFrom": false, + "supportsStaticESM": false, + "supportsTopLevelAwait": false, + }, ], - "unmockedModulePathPatterns": undefined, - "watchPathIgnorePatterns": Array [], - }, - "instrument": true, - "rootDir": "/", - "supportsDynamicImport": undefined, - "supportsExportNamespaceFrom": undefined, - "supportsStaticESM": undefined, - "supportsTopLevelAwait": undefined, + ], + "results": Array [ + Object { + "type": "return", + "value": "ab", + }, + ], } `; @@ -234,7 +252,7 @@ exports[`ScriptTransformer uses multiple preprocessors 1`] = ` const TRANSFORMED = { filename: '/fruits/banana.js', script: 'module.exports = "banana";', - config: '{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extraGlobals":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleLoader":"/test_module_loader_path","moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-jasmine2","testURL":"http://localhost","timers":"real","transform":[["\\\\.js$","test_preprocessor",{}],["\\\\.css$","css-preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}', + config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extraGlobals":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleLoader":"/test_module_loader_path","moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-jasmine2","testURL":"http://localhost","timers":"real","transform":[["\\\\.js$","test_preprocessor",{}],["\\\\.css$","css-preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extraGlobals\\":[],\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleLoader\\":\\"/test_module_loader_path\\",\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-jasmine2\\",\\"testURL\\":\\"http://localhost\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_preprocessor\\",{}],[\\"\\\\\\\\.css$\\",\\"css-preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}"}', }; `; @@ -251,7 +269,7 @@ exports[`ScriptTransformer uses the supplied preprocessor 1`] = ` const TRANSFORMED = { filename: '/fruits/banana.js', script: 'module.exports = "banana";', - config: '{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extraGlobals":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleLoader":"/test_module_loader_path","moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-jasmine2","testURL":"http://localhost","timers":"real","transform":[["\\\\.js$","test_preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}', + config: '{"collectCoverage":false,"collectCoverageFrom":[],"coverageProvider":"babel","supportsDynamicImport":false,"supportsExportNamespaceFrom":false,"supportsStaticESM":false,"supportsTopLevelAwait":false,"instrument":false,"config":{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extraGlobals":[],"forceCoverageMatch":[],"globals":{},"haste":{},"injectGlobals":true,"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleLoader":"/test_module_loader_path","moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-jasmine2","testURL":"http://localhost","timers":"real","transform":[["\\\\.js$","test_preprocessor",{}]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]},"configString":"{\\"automock\\":false,\\"cache\\":true,\\"cacheDirectory\\":\\"/cache/\\",\\"clearMocks\\":false,\\"coveragePathIgnorePatterns\\":[],\\"cwd\\":\\"/test_root_dir/\\",\\"detectLeaks\\":false,\\"detectOpenHandles\\":false,\\"errorOnDeprecated\\":false,\\"extraGlobals\\":[],\\"forceCoverageMatch\\":[],\\"globals\\":{},\\"haste\\":{},\\"injectGlobals\\":true,\\"moduleDirectories\\":[],\\"moduleFileExtensions\\":[\\"js\\"],\\"moduleLoader\\":\\"/test_module_loader_path\\",\\"moduleNameMapper\\":[],\\"modulePathIgnorePatterns\\":[],\\"modulePaths\\":[],\\"name\\":\\"test\\",\\"prettierPath\\":\\"prettier\\",\\"resetMocks\\":false,\\"resetModules\\":false,\\"restoreMocks\\":false,\\"rootDir\\":\\"/\\",\\"roots\\":[],\\"runner\\":\\"jest-runner\\",\\"setupFiles\\":[],\\"setupFilesAfterEnv\\":[],\\"skipFilter\\":false,\\"skipNodeResolution\\":false,\\"slowTestThreshold\\":5,\\"snapshotSerializers\\":[],\\"testEnvironment\\":\\"node\\",\\"testEnvironmentOptions\\":{},\\"testLocationInResults\\":false,\\"testMatch\\":[],\\"testPathIgnorePatterns\\":[],\\"testRegex\\":[\\"\\\\\\\\.test\\\\\\\\.js$\\"],\\"testRunner\\":\\"jest-jasmine2\\",\\"testURL\\":\\"http://localhost\\",\\"timers\\":\\"real\\",\\"transform\\":[[\\"\\\\\\\\.js$\\",\\"test_preprocessor\\",{}]],\\"transformIgnorePatterns\\":[\\"/node_modules/\\"],\\"watchPathIgnorePatterns\\":[]}"}', }; `; diff --git a/packages/jest-transform/src/__tests__/script_transformer.test.ts b/packages/jest-transform/src/__tests__/script_transformer.test.ts index 02ea4ed4351c..f65218a175d4 100644 --- a/packages/jest-transform/src/__tests__/script_transformer.test.ts +++ b/packages/jest-transform/src/__tests__/script_transformer.test.ts @@ -9,7 +9,7 @@ import {wrap} from 'jest-snapshot-serializer-raw'; import {makeGlobalConfig, makeProjectConfig} from '@jest/test-utils'; import type {Config} from '@jest/types'; -import type {ShouldInstrumentOptions, Transformer} from '../types'; +import type {Options, ShouldInstrumentOptions, Transformer} from '../types'; jest .mock('graceful-fs', () => @@ -38,7 +38,7 @@ jest }, })) .mock('jest-haste-map', () => ({ - getCacheFilePath: (cacheDir, baseDir) => cacheDir + baseDir, + getCacheFilePath: (cacheDir: string, baseDir: string) => cacheDir + baseDir, })) .mock('jest-util', () => ({ ...jest.requireActual('jest-util'), @@ -663,7 +663,7 @@ describe('ScriptTransformer', () => { ); const {getCacheKey} = require('test_preprocessor'); - expect(getCacheKey.mock.calls[0][3]).toMatchSnapshot(); + expect(getCacheKey).toMatchSnapshot(); }); it('creates transformer with config', () => { @@ -793,7 +793,7 @@ describe('ScriptTransformer', () => { function getCoverageOptions( overrides: Partial = {}, -): ShouldInstrumentOptions { +): Options { const globalConfig = makeGlobalConfig(overrides); return { @@ -801,6 +801,10 @@ function getCoverageOptions( collectCoverageFrom: globalConfig.collectCoverageFrom, collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom, coverageProvider: globalConfig.coverageProvider, + supportsDynamicImport: false, + supportsExportNamespaceFrom: false, + supportsStaticESM: false, + supportsTopLevelAwait: false, }; } diff --git a/packages/jest-transform/src/enhanceUnexpectedTokenMessage.ts b/packages/jest-transform/src/enhanceUnexpectedTokenMessage.ts index e666361d4099..99c66484f83a 100644 --- a/packages/jest-transform/src/enhanceUnexpectedTokenMessage.ts +++ b/packages/jest-transform/src/enhanceUnexpectedTokenMessage.ts @@ -56,7 +56,9 @@ ${DOT}If you simply want to mock your non-JS modules (e.g. binary assets) you ca )} config option. You'll find more details and examples of these config options in the docs: -${chalk.cyan('https://jestjs.io/docs/en/configuration.html')} +${chalk.cyan('https://jestjs.io/docs/en/configuration')} +For information about custom transformations, see: +${chalk.cyan('https://jestjs.io/docs/en/code-transformation')} ${chalk.bold.red('Details:')} diff --git a/packages/jest-transform/src/index.ts b/packages/jest-transform/src/index.ts index efcdbfc65ae4..3695baded523 100644 --- a/packages/jest-transform/src/index.ts +++ b/packages/jest-transform/src/index.ts @@ -11,7 +11,6 @@ export { } from './ScriptTransformer'; export {default as shouldInstrument} from './shouldInstrument'; export type { - CacheKeyOptions, CallerTransformOptions, Transformer, ShouldInstrumentOptions, diff --git a/packages/jest-transform/src/types.ts b/packages/jest-transform/src/types.ts index 979c16c8ad42..bae59571bdaa 100644 --- a/packages/jest-transform/src/types.ts +++ b/packages/jest-transform/src/types.ts @@ -40,37 +40,35 @@ export type TransformResult = TransformTypes.TransformResult; export interface CallerTransformOptions { // names are copied from babel: https://babeljs.io/docs/en/options#caller - supportsDynamicImport?: boolean; - supportsExportNamespaceFrom?: boolean; - supportsStaticESM?: boolean; - supportsTopLevelAwait?: boolean; + supportsDynamicImport: boolean; + supportsExportNamespaceFrom: boolean; + supportsStaticESM: boolean; + supportsTopLevelAwait: boolean; } -export interface TransformOptions extends CallerTransformOptions { +export interface ReducedTransformOptions extends CallerTransformOptions { instrument: boolean; } -// TODO: For Jest 26 we should combine these into one options shape -export interface CacheKeyOptions extends TransformOptions { +export interface TransformOptions extends ReducedTransformOptions { config: Config.ProjectConfig; - rootDir: string; + /** A stringified version of the configuration - useful in cache busting */ + configString: string; } -export interface Transformer { +export interface Transformer { canInstrument?: boolean; - createTransformer?: (options?: any) => Transformer; + createTransformer?: (options?: OptionType) => Transformer; getCacheKey?: ( - fileData: string, - filePath: Config.Path, - configStr: string, - options: CacheKeyOptions, + sourceText: string, + sourcePath: Config.Path, + options: TransformOptions, ) => string; process: ( sourceText: string, sourcePath: Config.Path, - config: Config.ProjectConfig, - options?: TransformOptions, + options: TransformOptions, ) => TransformedSource; } diff --git a/patches/fbjs-scripts.patch b/patches/fbjs-scripts.patch new file mode 100644 index 000000000000..d3da4a8c1950 --- /dev/null +++ b/patches/fbjs-scripts.patch @@ -0,0 +1,13 @@ +diff --git a/jest/createCacheKeyFunction.js b/jest/createCacheKeyFunction.js +index 890918962daebefedee59a48cd02906447f9de5b..2e73413d30a9964891608eb9ec02568b981b5ba0 100644 +--- a/jest/createCacheKeyFunction.js ++++ b/jest/createCacheKeyFunction.js +@@ -32,6 +32,8 @@ function getGlobalCacheKey(files, values) { + + function getCacheKeyFunction(globalCacheKey) { + return (src, file, configString, options) => { ++ // Jest 27 passes a single options bag which contains `configString` rather than as a separate argument ++ options = options || configString; + const {instrument, config} = options; + const rootDir = config && config.rootDir; + diff --git a/website/sidebars.json b/website/sidebars.json index 1cb762c601d6..be6ad0a82e9a 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -40,7 +40,8 @@ "jest-object", "configuration", "cli", - "environment-variables" + "environment-variables", + "code-transformation" ] } } diff --git a/website/versioned_docs/version-22.x/TutorialReact.md b/website/versioned_docs/version-22.x/TutorialReact.md index 4e42be51f78c..063203b88a72 100644 --- a/website/versioned_docs/version-22.x/TutorialReact.md +++ b/website/versioned_docs/version-22.x/TutorialReact.md @@ -305,7 +305,7 @@ The code for this example is available at [examples/enzyme](https://github.com/f ### Custom transformers -If you need more advanced functionality, you can also build your own transformer. Instead of using babel-jest, here is an example of using babel: +If you need more advanced functionality, you can also build your own transformer. Instead of using `babel-jest`, here is an example of using `babel-core`: ```javascript // custom-transformer.js @@ -332,7 +332,7 @@ Don't forget to install the `babel-core` and `babel-preset-jest` packages for th To make this work with Jest you need to update your Jest configuration with this: `"transform": {"\\.js$": "path/to/custom-transformer.js"}`. -If you'd like to build a transformer with babel support, you can also use babel-jest to compose one and pass in your custom configuration options: +If you'd like to build a transformer with babel support, you can also use `babel-jest` to compose one and pass in your custom configuration options: ```javascript const babelJest = require('babel-jest'); diff --git a/website/versioned_docs/version-23.x/TutorialReact.md b/website/versioned_docs/version-23.x/TutorialReact.md index 396d67b32b2d..18ab2ae93d1d 100644 --- a/website/versioned_docs/version-23.x/TutorialReact.md +++ b/website/versioned_docs/version-23.x/TutorialReact.md @@ -305,7 +305,7 @@ The code for this example is available at [examples/enzyme](https://github.com/f ### Custom transformers -If you need more advanced functionality, you can also build your own transformer. Instead of using babel-jest, here is an example of using babel: +If you need more advanced functionality, you can also build your own transformer. Instead of using `babel-jest`, here is an example of using `babel-core`: ```javascript // custom-transformer.js @@ -331,7 +331,7 @@ Don't forget to install the `babel-core` and `babel-preset-jest` packages for th To make this work with Jest you need to update your Jest configuration with this: `"transform": {"\\.js$": "path/to/custom-transformer.js"}`. -If you'd like to build a transformer with babel support, you can also use babel-jest to compose one and pass in your custom configuration options: +If you'd like to build a transformer with babel support, you can also use `babel-jest` to compose one and pass in your custom configuration options: ```javascript const babelJest = require('babel-jest'); diff --git a/website/versioned_docs/version-24.x/TutorialReact.md b/website/versioned_docs/version-24.x/TutorialReact.md index 0381c9707be3..96fc597808b7 100644 --- a/website/versioned_docs/version-24.x/TutorialReact.md +++ b/website/versioned_docs/version-24.x/TutorialReact.md @@ -305,7 +305,7 @@ The code for this example is available at [examples/enzyme](https://github.com/f ### Custom transformers -If you need more advanced functionality, you can also build your own transformer. Instead of using babel-jest, here is an example of using babel: +If you need more advanced functionality, you can also build your own transformer. Instead of using `babel-jest`, here is an example of using `@babel/core`: ```javascript // custom-transformer.js @@ -321,7 +321,7 @@ module.exports = { presets: [jestPreset], }); - return result ? result.code : src; + return result || src; }, }; ``` @@ -330,7 +330,7 @@ Don't forget to install the `@babel/core` and `babel-preset-jest` packages for t To make this work with Jest you need to update your Jest configuration with this: `"transform": {"\\.js$": "path/to/custom-transformer.js"}`. -If you'd like to build a transformer with babel support, you can also use babel-jest to compose one and pass in your custom configuration options: +If you'd like to build a transformer with babel support, you can also use `babel-jest` to compose one and pass in your custom configuration options: ```javascript const babelJest = require('babel-jest'); diff --git a/yarn.lock b/yarn.lock index 2c6bfbee05de..f06703de94a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8998,7 +8998,7 @@ __metadata: languageName: node linkType: hard -"fbjs-scripts@npm:^1.1.0": +fbjs-scripts@^1.1.0: version: 1.2.0 resolution: "fbjs-scripts@npm:1.2.0" dependencies: @@ -9016,6 +9016,24 @@ __metadata: languageName: node linkType: hard +"fbjs-scripts@patch:fbjs-scripts@^1.1.0#./patches/fbjs-scripts.patch::locator=%40jest%2Fmonorepo%40workspace%3A.": + version: 1.2.0 + resolution: "fbjs-scripts@patch:fbjs-scripts@npm%3A1.2.0#./patches/fbjs-scripts.patch::version=1.2.0&hash=f23fdb&locator=%40jest%2Fmonorepo%40workspace%3A." + dependencies: + "@babel/core": ^7.0.0 + ansi-colors: ^1.0.1 + babel-preset-fbjs: ^3.2.0 + core-js: ^2.4.1 + cross-spawn: ^5.1.0 + fancy-log: ^1.3.2 + object-assign: ^4.0.1 + plugin-error: ^0.1.2 + semver: ^5.1.0 + through2: ^2.0.0 + checksum: 908b412866a6d1dd625b466153834f2f1e417f903e2c4a110840a14c2d7973e9ae9f03101be947ca01faf99dd198370cc405181a9223066ee803c84e41110190 + languageName: node + linkType: hard + "fbjs@npm:^1.0.0": version: 1.0.0 resolution: "fbjs@npm:1.0.0"