Code-Transformation
Diese Seite wurde von PageTurner AI übersetzt (Beta). Nicht offiziell vom Projekt unterstützt. Fehler gefunden? Problem melden →
Jest führt den Code in Ihrem Projekt als JavaScript aus. Wenn Sie jedoch Syntax verwenden, die von Node nicht standardmäßig unterstützt wird (wie JSX, TypeScript oder Vue-Templates), müssen Sie diesen Code in reines JavaScript transformieren, ähnlich wie beim Erstellen für Browser.
Jest unterstützt dies über die Konfigurationsoption transform.
Ein Transformer ist ein Modul, das eine Methode zur Transformation von Quelldateien bereitstellt. Wenn Sie beispielsweise eine neue Sprachfunktion in Ihren Modulen oder Tests verwenden möchten, die von Node noch nicht unterstützt wird, können Sie einen Code-Preprozessor einbinden, der eine zukünftige JavaScript-Version in eine aktuelle transpiliert.
Jest speichert das Ergebnis einer Transformation zwischen und versucht, dieses Ergebnis basierend auf verschiedenen Faktoren zu invalidieren, etwa der Quelle der transformierten Datei oder geänderter Konfiguration.
Standardeinstellungen
Jest wird mit einem Transformer ausgeliefert – babel-jest. Es lädt die Babel-Konfiguration Ihres Projekts und transformiert jede Datei, die auf das Regex-Muster /\.[jt]sx?$/ passt (also jede .js-, .jsx-, .ts- oder .tsx-Datei). Zusätzlich injiziert babel-jest das Babel-Plugin, das für Mock-Hoisting erforderlich ist, wie in ES Module mocking beschrieben.
Standardmäßig enthält babel-jest babel-preset-jest. Sie können dieses Verhalten deaktivieren, indem Sie excludeJestPreset: true für babel-jest festlegen. Beachten Sie, dass dies auch das Hoisting von jest.mock stoppt, was Ihre Tests beeinträchtigen könnte.
"transform": {
"\\.[jt]sx?$": ["babel-jest", { "excludeJestPreset": true }],
}
Vergessen Sie nicht, den Standard-Transformer babel-jest explizit einzubinden, wenn Sie ihn zusammen mit zusätzlichen Code-Preprozessoren verwenden möchten:
"transform": {
"\\.[jt]sx?$": "babel-jest",
"\\.css$": "some-css-transformer",
}
Benutzerdefinierte Transformer erstellen
Sie können Ihre eigenen Transformer schreiben. Die API eines Transformers ist wie folgt definiert:
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>;
};
Die obigen Definitionen wurden der Kürze halber gekürzt. Den vollständigen Code finden Sie im Jest-Repository auf GitHub (wählen Sie den richtigen Tag/Commit für Ihre Jest-Version aus).
Es gibt mehrere Möglichkeiten, Code in Jest zu importieren - über Common JS (require) oder ECMAScript-Module (import, das in statischen und dynamischen Versionen existiert). Jest transformiert Dateien bedarfsgesteuert (z.B. bei der Auswertung von require oder import). Dieser Prozess, auch "Transpilierung" genannt, kann synchron (bei require) oder asynchron (bei import oder import(), wobei Letzteres auch in Common-JS-Modulen funktioniert) ablaufen. Daher bietet die Schnittstelle beide Methodenpaare für synchrone und asynchrone Prozesse: process{Async} und getCacheKey{Async}. Letztere wird aufgerufen, um zu bestimmen, ob process{Async} überhaupt aufgerufen werden muss.
Asynchrone Transpilierung kann auf den synchronen process-Aufruf zurückgreifen, wenn processAsync nicht implementiert ist. Synchrone Transpilierung kann jedoch nicht den asynchronen processAsync-Aufruf nutzen. Wenn Ihre Codebasis ausschließlich ESM verwendet, genügt die Implementierung der asynchronen Varianten. Falls jedoch Code über require geladen wird (einschließlich createRequire aus ESM), müssen Sie die synchrone process-Variante implementieren.
Beachten Sie, dass node_modules in der Standardkonfiguration nicht transpiliert wird. Die Einstellung transformIgnorePatterns muss angepasst werden, um dies zu ermöglichen.
Teilweise damit zusammenhängend sind die Support-Flags, die wir übergeben (siehe oben CallerTransformOptions). Diese sollten jedoch innerhalb des Transforms verwendet werden, um zu entscheiden, ob ESM oder CJS zurückgegeben werden soll. Sie haben keinen direkten Einfluss auf die Synchronität vs. Asynchronität.
Obwohl nicht zwingend erforderlich, empfehlen wir dringend, auch getCacheKey zu implementieren. So vermeiden wir Ressourcenverschwendung durch erneutes Transpilieren, wenn wir stattdessen das vorherige Ergebnis von der Festplatte lesen könnten. Für die Implementierung können Sie @jest/create-cache-key-function verwenden.
Anstatt dass Ihr benutzerdefiniertes Transformer direkt die Transformer-Schnittstelle implementiert, können Sie wahlweise createTransformer exportieren - eine Factory-Funktion zur dynamischen Erstellung von Transforms. Dies ermöglicht die Konfiguration des Transformers in Ihrer Jest-Konfiguration.
Die Unterstützung für ECMAScript-Module wird durch die übergebenen supports*-Optionen angezeigt. Insbesondere supportsDynamicImport: true bedeutet, dass der Transformer import()-Ausdrücke zurückgeben kann, die sowohl von ESM als auch CJS unterstützt werden. Bei supportsStaticESM: true werden Top-Level-import-Anweisungen unterstützt und der Code wird als ESM interpretiert, nicht als CJS. Details zu den Unterschieden finden Sie in Node.js-Dokumentation.
Stellen Sie sicher, dass die process{Async}-Methode neben transformiertem Code auch Source Maps zurückgibt. So können Zeileninformationen in Code Coverage und Testfehlern präzise angezeigt werden. Inline Source Maps funktionieren ebenfalls, sind aber langsamer.
Während der Entwicklung eines Transformers kann es hilfreich sein, Jest mit --no-cache auszuführen, um den Cache regelmäßig zu löschen.
Beispiele
TypeScript mit Typüberprüfung
Während babel-jest standardmäßig TypeScript-Dateien transpiliert, überprüft Babel nicht die Typen. Falls Sie dies benötigen, können Sie ts-jest verwenden.
Umwandlung von Bildern in ihren Pfad
Das Importieren von Bildern ist eine Methode, sie in Ihr Browser-Bundle einzubinden, aber sie sind kein valides JavaScript. Eine Möglichkeit, dies in Jest zu handhaben, besteht darin, den importierten Wert durch seinen Dateinamen zu ersetzen.
const path = require('path');
module.exports = {
process(sourceText, sourcePath, options) {
return {
code: `module.exports = ${JSON.stringify(path.basename(sourcePath))};`,
};
},
};
module.exports = {
transform: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/fileTransformer.js',
},
};