Перейти к основной части
Version: 27.2

Преобразование кода

Jest выполняет код вашего проекта как JavaScript, но если вы используете синтаксис, который не поддерживается Node.js из коробки (например, JSX, типы из TypeScript, шаблоны Vue и т. д.), то сначала нужно транспилировать ваш код в чистый JavaScript, по аналогии сборки проектов для клиентской части.

В Jest это можно сделать через опцию конфигурации transform .

Трансформер - это модуль, который предоставляет синхронную функцию для преобразования исходных файлов. Например, если в тестовых файлах вы хотите использовать новые возможности языка, которые ещё не поддерживаются Node. js, вы можете добавить один из множества плагинов для преобразования JavaScript будущего в современный синтаксис.

Jest закэширует результат преобразования, а если исходный файл или параметры конфигурации были изменены, тогда данные в кэше станут недействительными и преобразования будут запущены заново.

Конфигурация по умолчанию#

В Jest есть один преобразователь по-умолчанию - babel-jest. Он автоматически подгружает файл конфигурации Babel для вашего проекта и преобразует все файлы, которые удовлетворяют следующее регулярное выражение: /\.[jt]sx?$/ означает любой .js, .jsx, .ts и .tsx файлы. Также, babel-jest добавляет плагин Babel, необходимый для поднятия имитаций модулей, о которых подробно рассказывается в ES Module mocking.

Если перезаписать параметр конфигурации transform, плагин babel-jest станет неактивным. В таком случае, чтобы продолжать использовать Babel, нужно будет добавить плагин вручную.

Создание пользовательских преобразователей#

Вы можете написать свой собственный преобразователь. Вот как выглядит его API:

interface SyncTransformer<OptionType = unknown> {
/**
* 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) => SyncTransformer<OptionType>;
getCacheKey?: (
sourceText: string,
sourcePath: Config.Path,
options: TransformOptions<OptionType>,
) => string;
getCacheKeyAsync?: (
sourceText: string,
sourcePath: Config.Path,
options: TransformOptions<OptionType>,
) => Promise<string>;
process: (
sourceText: string,
sourcePath: Config.Path,
options: TransformOptions<OptionType>,
) => TransformedSource;
processAsync?: (
sourceText: string,
sourcePath: Config.Path,
options: TransformOptions<OptionType>,
) => Promise<TransformedSource>;
}
interface AsyncTransformer<OptionType = unknown> {
/**
* 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) => AsyncTransformer<OptionType>;
getCacheKey?: (
sourceText: string,
sourcePath: Config.Path,
options: TransformOptions<OptionType>,
) => string;
getCacheKeyAsync?: (
sourceText: string,
sourcePath: Config.Path,
options: TransformOptions<OptionType>,
) => Promise<string>;
process?: (
sourceText: string,
sourcePath: Config.Path,
options: TransformOptions<OptionType>,
) => TransformedSource;
processAsync: (
sourceText: string,
sourcePath: Config.Path,
options: TransformOptions<OptionType>,
) => Promise<TransformedSource>;
}
type Transformer<OptionType = unknown> =
| SyncTransformer<OptionType>
| AsyncTransformer<OptionType>;
interface TransformOptions<OptionType> {
/**
* If a transformer does module resolution and reads files, it should populate `cacheFS` so that
* Jest avoids reading the same files again, improving performance. `cacheFS` stores entries of
* <file path, file contents>
*/
cacheFS: Map<string, string>;
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;
/** the options passed through Jest's config by the user */
transformerConfig: OptionType;
}
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)

Как видно из Api, вам необходимо только добавить метод process, хотя мы также рекомендуем написать собственную реализацию getCacheKey, чтобы не транспилировать зря одни и те же исходные файлы, а считывать их с диска. Функция @jest/create-cache-key-function поможет с написанием метода.

Note that ECMAScript module 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 for details on the differences.

Примеры#

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.

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.

// fileTransformer.js
const path = require('path');
module.exports = {
process(src, filename, config, options) {
return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
},
};
// jest.config.js
module.exports = {
transform: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/fileTransformer.js',
},
};