Jest を使用した ECMAScript Modules (ESM) のテスト

Jest を使用した ECMAScript Modules (ESM) のテスト

岩佐 孝浩
岩佐 孝浩
6 min read
Jest

はじめに

Jest を使用して ECMAScript Modules (ESM) をテストする際、次のエラーに遭遇するかもしれません。

SyntaxError: Cannot use import statement outside a module

この問題は、対象モジュールが import キーワードを使用することで発生します。幸いなことに、Jest はこれらのエラーを解決するための実験的サポートを提供しています。

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

この投稿では、Jest を設定し、例として ESM パッケージを用いてこれらのエラーを解決する方法を説明します。

プロジェクトのセットアップ

ESM パッケージの作成

まず、次のコマンドで新しい ESM パッケージを作成します。

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

必要な開発依存関係をインストールします。

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

package.json は次のようになります。

{
  "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"
  }
}

package.json"type": "module" を追加します。

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

TypeScript の設定

以下のコマンドで tsconfig.json ファイルを生成します。

npx tsc --init

tsconfig.json を次のように更新します。

@@ -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. */

Jest の設定

以下のコマンドで Jest の設定を行います。

npm init jest@latest

以下のオプションを選択します。

オプション
Use Jest for the “test” scriptYes
Use TypeScript for the configurationYes
Test environmentjsdom
Add coverage reportsNo
Provider for coveragev8
Automatically clear mock calls…No

生成された jest.config.ts を編集し、以下を追加します。

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

Jest での ESM サポート

Jest での ESM テストを有効にするには、次の手順に従います。

package.json の修正

package.jsontest スクリプトを Node の実験的 VM モジュールを有効にするよう更新します。

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

jest.config.ts の更新

Jest にどのファイルタイプを ESM として扱うべきかを示すために extensionsToTreatAsEsm を追加します。

+ extensionsToTreatAsEsm: ['.ts'],

ts-jest での ESM サポート

ts-jest で ESM を設定するには、公式ドキュメントをご参照ください。

設定の変更

.js 拡張子を処理するために moduleNameMapper を更新します。

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

ESM をサポートするように transform を設定します。

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

ESM の作成

依存関係のインストール

デモ用に hast-util-from-html パッケージをインストールします。

npm i hast-util-from-html

hast-util-from-html モジュールは ECMAScript Module (ESM) であり、エクスポートに export キーワードを使用しています。これは、node_modules/hast-util-from-html/index.js にあるファイルを確認することで検証できます。以下に、モジュールのエクスポート構造の一部を示します。

/**
 * @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';

モジュールの作成

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);
}

テストの作成

index.spec.ts を作成します。

import JestEsm from './index';

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

ESM のテスト

テストを実行します。

npm run test

エラーが表示された場合:

● 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.

不足しているパッケージをインストールします。

npm i -D jest-environment-jsdom

再度テストを実行します。

npm run test

期待される出力:

 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.

まとめ

Jest を使用した ESM のテストは、実験的サポートのため慎重な設定が必要です。この投稿に従うことで、インポートエラーを解決し、ESM パッケージを効果的にテストできます。

詳細については、Jest ESM ドキュメントをご参照ください。

Happy Coding! 🚀

岩佐 孝浩

岩佐 孝浩

Software Developer at KAKEHASHI Inc.
AWS を活用したクラウドネイティブ・アプリケーションの要件定義・設計・開発に従事。 株式会社カケハシで、処方箋データ収集の新たな基盤の構築に携わっています。 Japan AWS Top Engineers 2020-2023