Aller au contenu principal
Version : 30.0

Modules ECMAScript (ESM)

Traduction Bêta Non Officielle

Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →

attention

Jest inclut une prise en charge expérimentale des modules ECMAScript (ESM).

L'implémentation peut contenir des bugs et manquer de fonctionnalités. Pour connaître le statut actuel, consultez le ticket et le label dans le suivi des problèmes.

Notez également que les APIs utilisées par Jest pour implémenter la prise en charge ESM sont toujours considérées comme expérimentales par Node.js (à partir de la version 18.8.0).

Maintenant que les mises en garde sont faites, voici comment activer la prise en charge ESM dans vos tests.

  1. Assurez-vous soit de désactiver les transformations de code en passant transform: {}, soit de configurer votre transformateur pour produire du ESM plutôt que du CommonJS (CJS) par défaut.

  2. Exécutez node avec --experimental-vm-modules, par exemple node --experimental-vm-modules node_modules/jest/bin/jest.js ou NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules" npx jest etc.

    Sur Windows, vous pouvez utiliser cross-env pour définir les variables d'environnement.

    Si vous utilisez Yarn, vous pouvez employer yarn node --experimental-vm-modules $(yarn bin jest). Cette commande fonctionne également avec Yarn Plug'n'Play.

    Si votre codebase inclut des imports ESM depuis des fichiers *.wasm, vous n'avez pas besoin de passer --experimental-wasm-modules à node. L'implémentation actuelle des imports WebAssembly dans Jest repose sur les modules VM expérimentaux, mais cela pourrait changer à l'avenir.

  3. Au-delà de cela, nous tentons de suivre la logique de node pour activer le "mode ESM" (comme examiner le champ type dans package.json ou les fichiers .mjs), consultez leur documentation pour les détails.

  4. Si vous souhaitez traiter d'autres extensions de fichiers (comme .jsx ou .ts) comme du ESM, utilisez l'option extensionsToTreatAsEsm.

Différences entre ESM et CommonJS

La plupart des différences sont expliquées dans la documentation de Node.js, mais en plus des éléments mentionnés, Jest injecte une variable spéciale dans tous les fichiers exécutés - l'objet jest. Pour accéder à cet objet en ESM, vous devez l'importer depuis le module @jest/globals ou utiliser import.meta.

import {jest} from '@jest/globals';

jest.useFakeTimers();

// etc.

// alternatively
import.meta.jest.useFakeTimers();

// jest === import.meta.jest => true

Simulation de modules en ESM

Puisque ESM évalue les instructions import statiques avant d'examiner le code, le hoisting des appels jest.mock qui fonctionne en CJS ne s'applique pas à ESM. Pour simuler des modules en ESM, vous devez utiliser require ou un import() dynamique après les appels jest.mock pour charger les modules simulés - cela s'applique également aux modules qui chargent les modules simulés.

La simulation ESM est prise en charge via jest.unstable_mockModule. Comme son nom l'indique, cette API est encore en développement, suivez ce ticket pour les mises à jour.

L'utilisation de jest.unstable_mockModule est essentiellement identique à jest.mock avec deux différences : la fonction factory est obligatoire et peut être synchrone ou asynchrone :

import {jest} from '@jest/globals';

jest.unstable_mockModule('node:child_process', () => ({
execSync: jest.fn(),
// etc.
}));

const {execSync} = await import('node:child_process');

// etc.

Désactivation de la simulation en ESM

esm-module.mjs
export default () => {
return 'default';
};

export const namedFn = () => {
return 'namedFn';
};
esm-module.test.mjs
import {jest, test} from '@jest/globals';

test('test esm-module', async () => {
jest.unstable_mockModule('./esm-module.js', () => ({
default: () => 'default implementation',
namedFn: () => 'namedFn implementation',
}));

const mockModule = await import('./esm-module.js');

console.log(mockModule.default()); // 'default implementation'
console.log(mockModule.namedFn()); // 'namedFn implementation'

jest.unstable_unmockModule('./esm-module.js');

const originalModule = await import('./esm-module.js');

console.log(originalModule.default()); // 'default'
console.log(originalModule.namedFn()); // 'namedFn'

/* !!! WARNING !!! Don`t override */
jest.unstable_mockModule('./esm-module.js', () => ({
default: () => 'default override implementation',
namedFn: () => 'namedFn override implementation',
}));

const mockModuleOverride = await import('./esm-module.js');

console.log(mockModuleOverride.default()); // 'default implementation'
console.log(mockModuleOverride.namedFn()); // 'namedFn implementation'
});

Simulation de modules CJS

Pour simuler des modules CJS, vous devez continuer à utiliser jest.mock. Voir l'exemple ci-dessous :

main.cjs
const {BrowserWindow, app} = require('electron');

// etc.

module.exports = {example};
main.test.cjs
import {createRequire} from 'node:module';
import {jest} from '@jest/globals';

const require = createRequire(import.meta.url);

jest.mock('electron', () => ({
app: {
on: jest.fn(),
whenReady: jest.fn(() => Promise.resolve()),
},
BrowserWindow: jest.fn().mockImplementation(() => ({
// partial mocks.
})),
}));

const {BrowserWindow} = require('electron');
const exported = require('./main.cjs');

// alternatively
const {BrowserWindow} = (await import('electron')).default;
const exported = await import('./main.cjs');

// etc.