😀

JestでESModulesをテストする

2023/04/23に公開

JestでESModulesをテストする方法を調べましたのでまとめます。

Jestのgetting-startedに載っている2つの数値を加算する関数を、mjs, mtsで記述し、テストします。
今回作成したファイルはGitHubで公開していますので、参考にしてもらえればと思います。

間違っていたり、おかしな点がありましたら、コメントいただけると幸いです。🙇‍♂️

対象読者

ESModulesとCommonJSをある程度理解している人向けに書いています。

前提

この記事ではPackage ManagerはYarnを使用します。
npm, pnpmを使用する場合は適宜読み替えてください。

以下検証で使用したツールとversionです。

  • Node.js(v18.16.0)
  • Yarn(v1.22.18)

事前準備

Node.jsでESModulesを使用する

Node.jsでESModulesを使用する場合、module systemをESModulesにする[1]必要があります。
package.jsonを以下のように設定します。

package.json
{
  ...
  "type": "module"
}

Jestをinstallする

yarn add --dev jest

JavaScript

まずはJavaScriptを使用したテストです。

Jestの設定

mjsファイルはJestのデフォルト設定[2]ではテストファイルから対象外になっています。そのため設定を以下のように変更します。

jest.config.mjs
export default {
  testMatch: [
    "**/__tests__/**/*.?(m)[jt]s?(x)",
    "**/?(*.)+(spec|test).?(m)[tj]s?(x)",
  ],
}

npm scripts追加

package.json
{
  "scripts": {
    "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
    # yarnの場合はこちらも可能
    "test": "yarn node --experimental-vm-modules $(yarn bin jest)"
  }
}

テスト対象を作成

sum.mjs
export function sum(a, b) {
  return a + b;
}

テストファイルを作成

sum.test.mjs
import { sum } from "./sum.mjs";

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

Test

以下のコマンドを実行し、テストします。

yarn test

結果

 PASS  ./sum.test.mjs
  ✓ adds 1 + 2 to equal 3 (1 ms)

TypeScript

次にTypeScriptを使用したコードをテストするケースです。

必要なパッケージをinstall

Jest以外に以下のパッケージをinstallします

yarn add -D @types/jest ts-jest typescript

Jestの設定

ESM Support | ts-jestを参考に設定します。

custom resolverを作成

mjs拡張子を解決するresolverを作成します。
ts-jestのドキュメントにシンプルな例[3]がリンクされていますので、こちらを参考にmjs-resolver.cjsを作成します。

mjs-resolver.cjs
const mjsResolver = (path, options) => {
  const mjsExtRegex = /\.mjs$/i;
  const resolver = options.defaultResolver;
  if (mjsExtRegex.test(path)) {
    try {
      return resolver(path.replace(mjsExtRegex, '.mts'), options)
    } catch {
      // use default resolver
    }
  }

  return resolver(path, options);
}

module.exports = mjsResolver;

jest.config.mjsを作成

次にjest.config.mjsを作成します。

jest.config.mjs
/** @type {import('ts-jest').JestConfigWithTsJest} */
export default {
  preset: 'ts-jest/presets/default-esm',
  moduleFileExtensions: ['js', 'mjs', 'cjs', 'jsx', 'ts', 'mts', 'tsx', 'json', 'node'],
  resolver: '<rootDir>/mjs-resolver.cjs',
  testMatch: [
    '**/__tests__/**/*.?(m)[jt]s?(x)',
    '**/?(*.)+(spec|test).?(m)[tj]s?(x)',
  ],
  transform: {
    '^.+\\.m?tsx?$': [
      'ts-jest',
      {
        useESM: true,
      },
    ],
  },
}

tsconfig作成

yarn run tsc --init

以下のようにtsconfig.jsonを書き換えます。

{
  "compilerOptions": {
    // ...
    "module": "Node16", // or "NodeNext"
    "target": "ESNext",
    "moduleResolution": "Node16", // or "NodeNext"
    "esModuleInterop": true
  }
}

npm scripts追加

package.json
{
  "scripts": {
    "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
    # yarnの場合はこちらも可能
    "test": "yarn node --experimental-vm-modules $(yarn bin jest)"
  }
}

テスト対象を作成

sum.mts
export function sum(a: number, b: number): number {
  return a + b;
}

テストファイルを作成

sum.test.mts
import { sum } from "./sum.mjs";

test('adds 1 + 2 to equal 3', () => {
    expect(sum(1, 2)).toBe(3);
});

Test

以下のコマンドを実行し、テストします。

yarn test

結果

 PASS  ./sum.test.mts
  ✓ adds 1 + 2 to equal 3 (1 ms)

以上です。

脚注
  1. https://nodejs.org/api/packages.html#determining-module-system ↩︎

  2. https://jestjs.io/ja/docs/configuration#testmatch-arraystring ↩︎

  3. ts-jest/mjs-resolver.ts at main · kulshekhar/ts-jest ↩︎

Discussion