Testing ECMAScript Modules Natively in Jest
In this tutorial, we’ll setup Jest to test a Node.js application that uses ECMAScript modules (ESM). Recent versions of Node.js have full support for ESM, which will eventually become the default mode in place of CommonJS. In the meantime, ESM mode can be easily enabled by setting "type": "module" in package.json.
Jest and ESM
Typically, Jest relies on Babel to transpile ESM code to CommonJS before running any tests, but Babel just adds another layer of complexity. Jest already has built-in support for ESM, though currently at an experimental stage.
There are a few key differences from testing CommonJS modules:
- We need to pass the
--experimental-vm-modulesflag to node when running Jest - Instead of
jest.mockwe have to usejest.unstable_mockModule - The
jestobject has to be imported from@jest/globals - We have to use dynamic imports to load our mocked modules in the right place
Testing a class
Let’s assume we are exporting the following class from myClass.js.
export class MyClass {
async get() {
return Promise.resolve("Hello World!");
}
}
In our test, myClass.test.js, we could create a mock of our MyClass class like so:
import { jest } from "@jest/globals";
const mockedGet = jest.fn().mockResolvedValue("Mocked");
jest.unstable_mockModule("./myClass.js", () => {
return {
MyClass: jest.fn(() => ({
get: mockedGet,
})),
};
});
// ESM import statements are evaluated first, so we need
// to use a dynamic import() to make sure our mocked module
// is loaded after jest.unstable_mockModule()
const { MyClass } = await import("./myClass.js");
const myInstance = new MyClass();
describe("MyClass", () => {
beforeEach(() => {
mockedGet.mockClear();
});
it("should work", async () => {
const result = await myInstance.get();
expect(result).toEqual("Mocked");
});
});
To run our test, we need to pass the --experimental-vm-modules flag to node. We can add the command to our package.json.
...
"type": "module",
"scripts": {
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
}
...
For more information on using Jest with ECMAScript modules, you can have a look at the official docs.
