Saltar al contenido principal
Versión: 29.7

Transformación de Código

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Jest ejecuta el código de tu proyecto como JavaScript, pero si utilizas alguna sintaxis no soportada nativamente por Node (como JSX, TypeScript o plantillas de Vue), necesitarás transformar ese código en JavaScript plano, similar a lo que harías al desarrollar para navegadores.

Jest admite esto mediante la opción de configuración transform.

Un transformador es un módulo que proporciona un método para transformar archivos fuente. Por ejemplo, si quisieras usar una nueva característica del lenguaje en tus módulos o pruebas que aún no sea compatible con Node, podrías incorporar un preprocesador que transpile una versión futura de JavaScript a una actual.

Jest almacenará en caché el resultado de la transformación e intentará invalidarlo según varios factores, como el origen del archivo transformado o cambios en la configuración.

Valores predeterminados

Jest incluye un transformador de forma predeterminada: babel-jest. Este cargará la configuración de Babel de tu proyecto y transformará cualquier archivo que coincida con la expresión regular /\.[jt]sx?$/ (es decir, archivos .js, .jsx, .ts o .tsx). Además, babel-jest inyectará el plugin de Babel necesario para el hoisting de mocks mencionado en simulación de módulos ES.

consejo

Recuerda incluir explícitamente el transformador predeterminado babel-jest si deseas usarlo junto con otros preprocesadores de código:

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

Creando transformadores personalizados

Puedes crear tu propio transformador. La API de un transformador es la siguiente:

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>;
};
nota

Las definiciones anteriores se han simplificado por brevedad. El código completo está disponible en el repositorio de Jest en GitHub (recuerda seleccionar la etiqueta/commit correspondiente a tu versión de Jest).

Existen varias formas de importar código en Jest: mediante Common JS (require) o Módulos ECMAScript (import - que existe en versiones estática y dinámica). Jest transforma los archivos bajo demanda (por ejemplo, cuando se evalúa un require o import). Este proceso, conocido como "transpilación", puede ocurrir sincrónicamente (con require) o asincrónicamente (con import o import(), siendo que este último también funciona en módulos Common JS). Por ello, la interfaz expone ambos pares de métodos para procesos asíncronos y síncronos: process{Async} y getCacheKey{Async}. El último se invoca para determinar si necesitamos llamar a process{Async}.

La transpilación asíncrona puede recurrir a la llamada síncrona process si processAsync no está implementada, pero la transpilación síncrona no puede usar processAsync. Si tu base de código es exclusivamente ESM, implementar las variantes asíncronas es suficiente. Sin embargo, si algún código se carga mediante require (incluyendo createRequire desde ESM), necesitarás implementar la variante síncrona process.

Ten presente que node_modules no se transpila con la configuración predeterminada; debes modificar el ajuste transformIgnorePatterns para lograrlo.

Esto está parcialmente relacionado con las flags de soporte que pasamos (ver CallerTransformOptions arriba), pero deben usarse dentro de la transformación para determinar si debe devolver ESM o CJS, sin afectar directamente la sincronía o asincronía.

Aunque no es obligatorio, recomendamos encarecidamente implementar getCacheKey también, para evitar desperdiciar recursos transpilando cuando podríamos leer su resultado anterior desde el disco. Puedes usar @jest/create-cache-key-function para ayudar en su implementación.

En lugar de hacer que tu transformador personalizado implemente directamente la interfaz Transformer, puedes optar por exportar createTransformer, una función factory para crear transformadores dinámicamente. Esto permite tener una configuración de transformador en tu configuración de Jest.

nota

El soporte de módulos ECMAScript se indica mediante las opciones supports* pasadas. Específicamente supportsDynamicImport: true significa que el transformador puede devolver expresiones import(), compatibles tanto con ESM como con CJS. Si supportsStaticESM: true significa que se admiten declaraciones import de nivel superior y el código se interpretará como ESM, no como CJS. Consulta la documentación de Node para ver las diferencias.

consejo

Asegúrate de que el método process{Async} devuelva el source map junto con el código transformado, para poder reportar información precisa de líneas en la cobertura de código y errores de prueba. Los source maps inline también funcionan pero son más lentos.

Durante el desarrollo de un transformador, puede ser útil ejecutar Jest con --no-cache para eliminar frecuentemente la caché.

Ejemplos

TypeScript con verificación de tipos

Aunque babel-jest transpilará archivos TypeScript por defecto, Babel no verifica los tipos. Si necesitas esa funcionalidad, puedes usar ts-jest.

Transformar imágenes a su ruta

Importar imágenes es una forma de incluirlas en tu bundle para navegadores, pero no son JavaScript válido. Una forma de manejarlo en Jest es reemplazar el valor importado con su nombre de archivo.

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',
},
};