Vai al contenuto principale
{ "message": "Versione: 29.7", "description": "" }

Trasformazione del Codice

Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

Jest esegue il codice nel tuo progetto come JavaScript, ma se utilizzi una sintassi non supportata nativamente da Node (come JSX, TypeScript o template Vue), dovrai trasformare quel codice in JavaScript semplice, simile a quanto faresti quando costruisci per i browser.

Jest supporta questa funzionalità tramite l'opzione di configurazione transform.

Un trasformatore è un modulo che fornisce un metodo per trasformare file sorgente. Ad esempio, se desideri utilizzare una nuova funzionalità linguistica nei tuoi moduli o test non ancora supportata da Node, potresti integrare un preprocessore di codice che transpili una versione futura di JavaScript in una corrente.

Jest memorizza nella cache il risultato di una trasformazione e tenta di invalidarlo in base a diversi fattori, come l'origine del file trasformato o modifiche alla configurazione.

Impostazioni Predefinite

Jest include un trasformatore predefinito – babel-jest. Caricherà la configurazione Babel del tuo progetto e trasformerà qualsiasi file corrispondente all'espressione regolare /\.[jt]sx?$/ (ovvero qualsiasi file .js, .jsx, .ts o .tsx). Inoltre, babel-jest inietterà il plugin Babel necessario per l'hoisting dei mock discusso in Mocking di moduli ES.

suggerimento

Ricorda di includere esplicitamente il trasformatore predefinito babel-jest se desideri utilizzarlo insieme ad altri preprocessori di codice:

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

Scrittura di trasformatori personalizzati

Puoi creare il tuo trasformatore personalizzato. L'API di un trasformatore è la seguente:

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

Le definizioni sopra sono state ridotte per brevità. Il codice completo è disponibile nel repository Jest su GitHub (ricorda di selezionare il tag/commit corretto per la tua versione di Jest).

Esistono diversi modi per importare codice in Jest: utilizzando Common JS (require) o Moduli ECMAScript (import - disponibile in versioni statica e dinamica). Jest elabora i file attraverso la trasformazione del codice su richiesta (ad esempio quando viene valutato un require o import). Questo processo, noto anche come "transpilazione", può avvenire in modo sincrono (nel caso di require) o asincrono (nel caso di import o import(), quest'ultimo funzionante anche da moduli Common JS). Per questo motivo, l'interfaccia espone coppie di metodi per processi asincroni e sincroni: process{Async} e getCacheKey{Async}. Quest'ultimo viene chiamato per determinare se è necessario invocare process{Async}.

La transpilazione asincrona può ripiegare sulla chiamata sincrona process se processAsync non è implementato, ma la transpilazione sincrona non può utilizzare la chiamata asincrona processAsync. Se la tua codebase è esclusivamente ESM, implementare le varianti asincrone è sufficiente. Altrimenti, se del codice viene caricato tramite require (incluso createRequire da ESM), devi implementare la variante sincrona process.

Tieni presente che node_modules non viene transpilato con la configurazione predefinita: l'impostazione transformIgnorePatterns deve essere modificata per farlo.

Parzialmente correlati a questo sono i flag di supporto che passiamo (vedi CallerTransformOptions sopra), ma questi dovrebbero essere usati all'interno della trasformazione per determinare se restituire ESM o CJS, senza influire direttamente sulla scelta tra sincrono e asincrono.

Sebbene non obbligatorio, raccomandiamo vivamente di implementare anche getCacheKey, per evitare di sprecare risorse nel transpilare codice quando potremmo invece leggere il risultato precedente dal disco. Puoi usare @jest/create-cache-key-function per implementarlo.

Invece di far implementare direttamente l'interfaccia Transformer al tuo trasformatore personalizzato, puoi scegliere di esportare createTransformer, una factory function per creare trasformatori dinamicamente. Questo permette di avere una configurazione del trasformatore nel tuo file di configurazione Jest.

nota

Il supporto ai moduli ECMAScript è indicato dalle opzioni supports* passate. In particolare supportsDynamicImport: true significa che il trasformatore può restituire espressioni import(), supportate sia da ESM che da CJS. Se supportsStaticESM: true significa che sono supportate le istruzioni import di primo livello e il codice sarà interpretato come ESM anziché CJS. Consulta la documentazione di Node per i dettagli sulle differenze.

suggerimento

Assicurati che il metodo process{Async} restituisca la source map insieme al codice trasformato, per permettere una segnalazione precisa delle informazioni di riga nella code coverage e negli errori dei test. Anche le source map inline funzionano ma sono più lente.

Durante lo sviluppo di un trasformatore può essere utile eseguire Jest con --no-cache per eliminare frequentemente la cache.

Esempi

TypeScript con controllo dei tipi

Sebbene babel-jest transpili i file TypeScript per impostazione predefinita, Babel non verifica i tipi. Se desideri questa funzionalità puoi usare ts-jest.

Trasformare le immagini nel loro percorso

Importare immagini è un modo per includerle nel bundle del browser, ma non sono JavaScript valido. Un modo per gestirle in Jest è sostituire il valore importato con il nome del file.

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