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-modules
flag to node when running Jest - Instead of
jest.mock
we have to usejest.unstable_mockModule
- The
jest
object 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.