Testing ECMAScript Modules (ESM) with Jest: A Step-by-Step Guide

Testing ECMAScript Modules (ESM) with Jest: A Step-by-Step Guide

Takahiro Iwasa
Takahiro Iwasa
5 min read
Jest

Introduction

When testing ECMAScript Modules (ESM) using Jest, you might encounter the error:

SyntaxError: Cannot use import statement outside a module

This issue arises because the target modules use the import keyword. Fortunately, Jest provides experimental support for ESM to resolve such errors.

Jest ships with experimental support for ECMAScript Modules (ESM).

In this guide, you’ll learn how to configure Jest and resolve these errors using an example ESM package.

Setting Up the Project

Creating an ESM Package

First, create a new ESM package with the following commands:

mkdir jest-esm && cd jest-esm
npm init -y

Install the necessary development dependencies:

npm i -D typescript jest @types/jest ts-node ts-jest

Your package.json should look like this:

{
  "name": "jest-esm",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/jest": "^29.5.12",
    "jest": "^29.7.0",
    "ts-jest": "^29.1.2",
    "ts-node": "^10.9.2",
    "typescript": "^5.3.3"
  }
}

Add "type": "module" to the package.json.

@@ -3,6 +3,7 @@
   "version": "1.0.0",
   "description": "",
   "main": "index.js",
+  "type": "module",
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
   },

Configuring TypeScript

Generate a tsconfig.json file with the following command:

npx tsc --init

Update the tsconfig.json file:

@@ -14 +14 @@
-    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+    "target": "es6",                                     /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
@@ -28 +28 @@
-    "module": "commonjs",                                /* Specify what module code is generated. */
+    "module": "es6",                                     /* Specify what module code is generated. */
@@ -30 +30 @@
-    // "moduleResolution": "node10",                     /* Specify how TypeScript looks up a file from a given module specifier. */
+    "moduleResolution": "node",                          /* Specify how TypeScript looks up a file from a given module specifier. */

Configuring Jest

Run the following command to set up Jest configuration:

npm init jest@latest

Follow these options:

OptionValue
Use Jest for the “test” scriptYes
Use TypeScript for the configurationYes
Test environmentjsdom
Add coverage reportsNo
Provider for coveragev8
Automatically clear mock calls…No

Edit the generated jest.config.ts to include:

-  // preset: undefined,
+  preset: 'ts-jest',

Supporting ESM on Jest

To enable ESM testing in Jest, follow these steps.

Modifying package.json

Update the test script in package.json to enable Node’s experimental VM modules:

"scripts": {
-   "test": "jest"
+   "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
}

Updating jest.config.ts

Add the extensionsToTreatAsEsm configuration to indicate which file types Jest should treat as ESM:

+ extensionsToTreatAsEsm: ['.ts'],

Supporting ESM on ts-jest

To configure ESM in ts-jest, refer to the official documentation.

Configuration Changes

Update jest.config.ts with moduleNameMapper to handle .js extensions:

-  // moduleNameMapper: {},
+  moduleNameMapper: {
+    '^(\\.{1,2}/.*)\\.js$': '$1',
+  },

Update the transform setting to support ESM:

-  // transform: undefined,
+  transform: {
+    '^.+\\.tsx?$': [
+      'ts-jest',
+      {
+        useESM: true,
+      },
+    ],
+  },

Creating ESM

Installing Dependencies

For demonstration, install the hast-util-from-html package:

npm i hast-util-from-html

The module hast-util-from-html is an ECMAScript Module (ESM) and uses the export keyword for its exports. This can be confirmed by examining the file located at node_modules/hast-util-from-html/index.js. Here’s a snippet of the module’s export structure:

/**
 * @typedef {import('hast-util-from-parse5')} DoNotTouchItRegistersData
 *
 * @typedef {import('./lib/index.js').ErrorCode} ErrorCode
 * @typedef {import('./lib/index.js').ErrorSeverity} ErrorSeverity
 * @typedef {import('./lib/index.js').OnError} OnError
 * @typedef {import('./lib/index.js').Options} Options
 */

export { fromHtml } from './lib/index.js';

Creating the Module

Create index.ts:

import { fromHtml } from 'hast-util-from-html';

export default function JestEsm(): void {
  const root = fromHtml(
    '<span><a href="https://github.com">GitHub</a></span>',
    { fragment: true }
  );
  console.info(root);
}

Writing Tests

Create index.spec.ts:

import JestEsm from './index';

test('case1', () => {
  JestEsm();
});

Testing ESM

Run the tests:

npm run test

If you see the error:

● Validation Error:

  Test environment jest-environment-jsdom cannot be found. Make sure the testEnvironment configuration option points to an existing node module.

  Configuration Documentation:
  https://jestjs.io/docs/configuration


As of Jest 28 "jest-environment-jsdom" is no longer shipped by default, make sure to install it separately.

Install the missing package:

npm i -D jest-environment-jsdom

Run the tests again:

npm run test

Expected output:

 PASS  ./index.spec.ts
  ✓ case1 (20 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1 s
Ran all test suites.

Conclusion

Testing ESM with Jest requires careful configuration due to its experimental support. By following this guide, you can resolve import errors and effectively test ESM packages.

For additional details, refer to the Jest ESM Documentation.

Happy Coding! 🚀

Takahiro Iwasa

Takahiro Iwasa

Software Developer at KAKEHASHI Inc.
Involved in the requirements definition, design, and development of cloud-native applications using AWS. Now, building a new prescription data collection platform at KAKEHASHI Inc. Japan AWS Top Engineers 2020-2023.