Hopp til hovedinnhold
Versjon: Neste

Kodetransformasjon

Unofficial Beta Translation

This page was AI-translated by PageTurner (beta). Not officially endorsed by the project. Found an error? Report issue →

Jest kjører koden i prosjektet ditt som JavaScript, men hvis du bruker syntaks som ikke støttes direkte av Node (som JSX, TypeScript eller Vue-maler), må du transformere denne koden til vanlig JavaScript - akkurat som du ville gjort når du bygger for nettlesere.

Jest støtter dette via konfigurasjonsvalget transform.

En transformer er en modul som tilbyr en metode for å transformere kildefiler. For eksempel, hvis du ønsker å bruke en ny språkfunksjonalitet i moduler eller tester som ikke støttes av Node ennå, kan du bruke en kode-preprosessor som transpilerer en fremtidig JavaScript-versjon til dagens versjon.

Jest vil mellomlagre resultatet av en transformasjon og forsøke å ugyldiggjøre dette resultatet basert på flere faktorer, som kilden til filen som transformeres og endringer i konfigurasjonen.

Standardoppsett

Jest leveres med én transformer ut av boksen – babel-jest. Den vil laste prosjektets Babel-konfigurasjon og transformere alle filer som samsvarer med regex-mønsteret /\.[jt]sx?$/ (altså alle .js-, .jsx-, .ts- eller .tsx-filer). I tillegg vil babel-jest injisere Babel-pluginen som trengs for mock-heving beskrevet i ES-modul-mocking.

notat

Som standard inkluderer babel-jest babel-preset-jest. Du kan deaktivere dette ved å spesifisere excludeJestPreset: true for babel-jest. Merk at dette også vil stoppe heving av jest.mock, noe som kan bryte testene dine.

"transform": {
"\\.[jt]sx?$": ["babel-jest", { "excludeJestPreset": true }],
}
tips

Husk å inkludere standard babel-jest-transformeren eksplisitt hvis du ønsker å bruke den sammen med andre kode-preprosessorer:

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

Skrive egendefinerte transformere

Du kan skrive dine egne transformere. API-et for en transformer er som følger:

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

Definisjonene ovenfor er forkortet for korthets skyld. Fullstendig kode finnes i Jest-repoet på GitHub (husk å velge riktig tag/commit for din Jest-versjon).

Det er flere måter å importere kode til Jest på - enten via Common JS (require) eller ECMAScript-moduler (import, som finnes i statiske og dynamiske versjoner). Jest behandler filer gjennom kodetransformasjon på forespørsel (f.eks. når en require eller import evalueres). Denne prosessen, også kalt "transpilering", kan skje synkront (ved require) eller asynkront (ved import eller import(), hvor sistnevnte også fungerer fra Common JS-moduler). Derfor tilbyr grensesnittet både asynkrone og synkrone metodepar: process{Async} og getCacheKey{Async}. Sistnevnte kalles for å avgjøre om process{Async} må kalles i det hele tatt.

Asynkron transpilering kan falle tilbake på synkron process-kall hvis processAsync ikke er implementert, men synkron transpilering kan ikke bruke asynkrone processAsync-kall. Hvis kodebasen din kun bruker ESM, er det tilstrekkelig å implementere de asynkrone variantene. Hvis derimot kode lastes via require (inkludert createRequire fra ESM), må du implementere den synkrone process-varianten.

Vær oppmerksom på at node_modules ikke transpileres med standardkonfigurasjon - innstillingen transformIgnorePatterns må endres for å gjøre dette.

Dette er delvis relatert til støtteflaggene vi sender (se CallerTransformOptions ovenfor), men disse bør brukes i transformeringen for å avgjøre om den skal returnere ESM eller CJS, og har ingen direkte påvirkning på synkron vs asynkron.

Selv om det ikke er påkrevd, anbefaler vi på det sterkeste å implementere getCacheKey også, slik at vi ikke kaster bort ressurser på transpilering når vi kunne ha lest forrige resultat fra disken. Du kan bruke @jest/create-cache-key-function for å hjelpe til med implementeringen.

I stedet for at din egendefinerte transformer implementerer Transformer-grensesnittet direkte, kan du velge å eksportere createTransformer, en fabrikkfunksjon for å dynamisk opprette transformere. Dette gjør det mulig å ha en transformer-konfigurasjon i Jest-konfigurasjonen din.

notat

Støtte for ECMAScript-moduler indikeres av de medsendte supports*-alternativene. Spesifikt betyr supportsDynamicImport: true at transformeren kan returnere import()-uttrykk, som støttes av både ESM og CJS. Hvis supportsStaticESM: true betyr det at toppnivå import-setninger støttes og koden vil bli tolket som ESM og ikke CJS. Se Node-dokumentasjonen for detaljer om forskjellene.

tips

Sørg for at process{Async}-metoden returnerer kildekart sammen med transformer kode, slik at linjeinformasjon kan rapporteres nøyaktig i kodedekning og testfeil. Inline kildekart fungerer også, men er tregere.

Under utvikling av en transformer kan det være nyttig å kjøre Jest med --no-cache for ofte å slette hurtigbufret.

Eksempler

TypeScript med typekontroll

Mens babel-jest som standard vil transpilere TypeScript-filer, vil ikke Babel verifisere typene. Hvis du ønsker det kan du bruke ts-jest.

Transformering av bilder til filstier

Å importere bilder er en måte å inkludere dem i nettleserpakken din, men de er ikke gyldig JavaScript. En måte å håndtere dette i Jest er å erstatte den importerte verdien med filnavnet.

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