Ir para o conteúdo principal
Versão: 29.7

Transformação de Código

Tradução Beta Não Oficial

Esta página foi traduzida por PageTurner AI (beta). Não é oficialmente endossada pelo projeto. Encontrou um erro? Reportar problema →

O Jest executa o código do seu projeto como JavaScript, mas se você usar alguma sintaxe não suportada nativamente pelo Node (como JSX, TypeScript ou templates Vue), será necessário transformar esse código em JavaScript puro, similar ao que você faria ao desenvolver para navegadores.

O Jest oferece suporte a isso através da opção de configuração transform.

Um transformer é um módulo que fornece um método para transformar arquivos fonte. Por exemplo, se você quiser usar um novo recurso de linguagem em seus módulos ou testes que ainda não é suportado pelo Node, pode integrar um pré-processador que transpilaria uma versão futura do JavaScript para a versão atual.

O Jest armazena em cache o resultado de uma transformação e tenta invalidar esse resultado com base em diversos fatores, como a origem do arquivo sendo transformado e mudanças na configuração.

Padrões

O Jest inclui um transformer pronto para uso – babel-jest. Ele carregará a configuração do Babel do seu projeto e transformará qualquer arquivo que corresponda à expressão regular /\.[jt]sx?$/ (ou seja, qualquer arquivo .js, .jsx, .ts ou .tsx). Além disso, o babel-jest injetará o plugin do Babel necessário para o hoisting de mocks discutido em Mocking de módulos ES.

"message": "dica"

Lembre-se de incluir explicitamente o transformer padrão babel-jest se quiser usá-lo junto com outros pré-processadores:

"transform": {
"\\.[jt]sx?$": "babel-jest",
"\\.css$": "some-css-transformer",
}

Criando transformers personalizados

Você pode criar seu próprio transformer. A API de um transformer é a seguinte:

interface TransformOptions<TransformerConfig = unknown> {
supportsDynamicImport: boolean;
supportsExportNamespaceFrom: boolean;
/**
* The value is:
* - `false` if Jest runs without Node ESM flag `--experimental-vm-modules`
* - `true` if the file extension is defined in [extensionsToTreatAsEsm](Configuration.md#extensionstotreatasesm-arraystring)
* and Jest runs with Node ESM flag `--experimental-vm-modules`
*
* See more at https://jestjs.io/docs/next/ecmascript-modules
*/
supportsStaticESM: boolean;
supportsTopLevelAwait: boolean;
instrument: boolean;
/** Cached file system which is used by `jest-runtime` to improve performance. */
cacheFS: Map<string, string>;
/** Jest configuration of currently running project. */
config: ProjectConfig;
/** Stringified version of the `config` - useful in cache busting. */
configString: string;
/** Transformer configuration passed through `transform` option by the user. */
transformerConfig: TransformerConfig;
}

type TransformedSource = {
code: string;
map?: RawSourceMap | string | null;
};

interface SyncTransformer<TransformerConfig = unknown> {
canInstrument?: boolean;

getCacheKey?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => string;

getCacheKeyAsync?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => Promise<string>;

process: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => TransformedSource;

processAsync?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => Promise<TransformedSource>;
}

interface AsyncTransformer<TransformerConfig = unknown> {
canInstrument?: boolean;

getCacheKey?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => string;

getCacheKeyAsync?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => Promise<string>;

process?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => TransformedSource;

processAsync: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => Promise<TransformedSource>;
}

type Transformer<TransformerConfig = unknown> =
| SyncTransformer<TransformerConfig>
| AsyncTransformer<TransformerConfig>;

type TransformerCreator<
X extends Transformer<TransformerConfig>,
TransformerConfig = unknown,
> = (transformerConfig?: TransformerConfig) => X;

type TransformerFactory<X extends Transformer> = {
createTransformer: TransformerCreator<X>;
};
"message": "nota"

As definições acima foram simplificadas por brevidade. O código completo pode ser encontrado no repositório do Jest no GitHub (lembre-se de escolher a tag/commit correta para sua versão do Jest).

Existem algumas formas de importar código no Jest - usando Common JS (require) ou Módulos ECMAScript (import, que possui versões estáticas e dinâmicas). O Jest processa arquivos através da transformação de código sob demanda (por exemplo, quando um require ou import é avaliado). Esse processo, também conhecido como "transpilação", pode ocorrer de forma síncrona (no caso de require) ou assíncrona (no caso de import ou import(), sendo que este último também funciona a partir de módulos Common JS). Por esse motivo, a interface expõe ambos os pares de métodos para processos assíncronos e síncronos: process{Async} e getCacheKey{Async}. O último é chamado para determinar se precisamos invocar process{Async}.

A transpilação assíncrona pode recorrer à chamada síncrona process se processAsync não estiver implementado, mas a transpilação síncrona não pode usar a chamada assíncrona processAsync. Se sua base de código é apenas ESM, implementar as variantes assíncronas é suficiente. Caso contrário, se qualquer código for carregado via require (incluindo createRequire a partir de ESM), você precisará implementar a variante síncrona process.

Esteja ciente de que node_modules não é transpilado na configuração padrão - a configuração transformIgnorePatterns deve ser modificada para isso.

Semi-relacionado a isso estão os flags de suporte que passamos (veja CallerTransformOptions acima), mas eles devem ser usados dentro da transformação para determinar se deve retornar ESM ou CJS, sem relação direta com síncrono vs assíncrono.

Embora não obrigatório, recomendamos fortemente implementar getCacheKey também, para evitar desperdiçar recursos retranspilando quando poderíamos ler o resultado anterior do disco. Você pode usar @jest/create-cache-key-function para ajudar na implementação.

Em vez de fazer seu transformador personalizado implementar diretamente a interface Transformer, você pode optar por exportar createTransformer, uma função factory para criar transformadores dinamicamente. Isso permite ter configurações de transformador no seu jest.config.

"message": "nota"

O suporte a módulos ECMAScript é indicado pelas opções supports* passadas. Especificamente supportsDynamicImport: true significa que o transformador pode retornar expressões import(), suportadas tanto por ESM quanto CJS. Se supportsStaticESM: true, significa que declarações import de nível superior são suportadas e o código será interpretado como ESM, não CJS. Consulte a documentação do Node para detalhes sobre as diferenças.

"message": "dica"

Certifique-se que o método process{Async} retorne o source map junto com o código transformado, para permitir relatar informações de linha precisas na cobertura de código e erros de teste. Source maps inline também funcionam, mas são mais lentos.

Durante o desenvolvimento de um transformador, pode ser útil executar o Jest com --no-cache para apagar o cache frequentemente.

Exemplos

TypeScript com verificação de tipos

Enquanto o babel-jest transpila arquivos TypeScript por padrão, o Babel não verifica os tipos. Se você precisa dessa verificação, pode usar ts-jest.

Transformando imagens em seus caminhos

Importar imagens é uma forma de incluí-las no bundle do navegador, mas elas não são JavaScript válido. Uma maneira de lidar com isso no Jest é substituir o valor importado pelo nome do arquivo.

fileTransformer.js
const path = require('path');

module.exports = {
process(sourceText, sourcePath, options) {
return {
code: `module.exports = ${JSON.stringify(path.basename(sourcePath))};`,
};
},
};
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',
},
};