Moduli ECMAScript
Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →
Jest include un supporto sperimentale per i Moduli ECMAScript (ESM).
L'implementazione potrebbe contenere bug e mancare di alcune funzionalità. Per lo stato aggiornato consulta l'issue e l'etichetta sul tracker dei problemi.
Nota inoltre che le API utilizzate da Jest per implementare il supporto ESM sono ancora considerate sperimentali da Node (alla versione 18.8.0).
Fatte queste premesse, ecco come attivare il supporto ESM nei tuoi test.
-
Assicurati di disabilitare le trasformazioni del codice passando
transform: {}oppure configura il tuo transformer per produrre ESM anziché il CommonJS (CJS) predefinito. -
Esegui
nodecon--experimental-vm-modules, ad esempionode --experimental-vm-modules node_modules/jest/bin/jest.jsoNODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules" npx jestecc.Su Windows, puoi usare
cross-envper impostare le variabili d'ambiente.Se usi Yarn, puoi usare
yarn node --experimental-vm-modules $(yarn bin jest). Questo comando funziona anche con Yarn Plug'n'Play.Se il tuo codice include import ESM da file
*.wasm, non è necessario passare--experimental-wasm-modulesanode. L'implementazione corrente degli import WebAssembly in Jest si basa sui moduli VM sperimentali, ma questo potrebbe cambiare in futuro. -
Oltre a questo, cerchiamo di seguire la logica di
nodeper attivare la "modalità ESM" (come controllaretypeinpackage.jsono i file.mjs), vedi la loro documentazione per i dettagli. -
Se vuoi trattare altre estensioni di file (come
.jsxo.ts) come ESM, usa l'opzioneextensionsToTreatAsEsm.
Differenze tra ESM e CommonJS
La maggior parte delle differenze è spiegata nella documentazione di Node, ma oltre a quanto menzionato, Jest inietta una variabile speciale in tutti i file eseguiti - l'oggetto jest. Per accedere a questo oggetto in ESM, devi importarlo dal modulo @jest/globals o usare import.meta.
import {jest} from '@jest/globals';
jest.useFakeTimers();
// etc.
// alternatively
import.meta.jest.useFakeTimers();
// jest === import.meta.jest => true
Mocking di moduli in ESM
Poiché ESM valuta le istruzioni import statiche prima di esaminare il codice, l'hoisting delle chiamate jest.mock che avviene in CJS non funzionerà per ESM. Per fare il mocking dei moduli in ESM, devi usare require o import() dinamico dopo le chiamate jest.mock per caricare i moduli mockati - lo stesso vale per i moduli che caricano i moduli mockati.
Il mocking ESM è supportato tramite jest.unstable_mockModule. Come suggerisce il nome, questa API è ancora in fase di sviluppo, segui questo issue per aggiornamenti.
L'utilizzo di jest.unstable_mockModule è essenzialmente identico a jest.mock con due differenze: la funzione factory è obbligatoria e può essere sincrona o asincrona:
import {jest} from '@jest/globals';
jest.unstable_mockModule('node:child_process', () => ({
execSync: jest.fn(),
// etc.
}));
const {execSync} = await import('node:child_process');
// etc.
Rimozione del mocking per i moduli in ESM
export default () => {
return 'default';
};
export const namedFn = () => {
return 'namedFn';
};
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'
});
Mocking di moduli CJS
Per il mocking dei moduli CJS, dovresti continuare a usare jest.mock. Vedi l'esempio qui sotto:
const {BrowserWindow, app} = require('electron');
// etc.
module.exports = {example};
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.