6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vite で作った React プロジェクトに最小構成の Jest を導入する

Posted at

 はじめに

プログラミング言語をとわず設定ファイルは難しいですよね :thinking: ドキュメントを見ても何ができるのかわからず検索でたまたま見つけた設定ファイルをコピペしては試し...を繰り返していると思います。わたしは Webpack で痛い思いをしたので本記事では設定ファイルを少なく、ドキュメントを引用して再現性を高くすることを意識して Vite で作った React プロジェクトに最小構成の Jest を導入します。

環境構築

プロジェクト作成

TypeScript + React で作成してください。

npm create vite@latest

Jest

テストフレームワークは Jest を選択したのでインストールします。

npm install --save-dev jest

必要なパッケージは次の ts-jest から順にスクロールしながら進めると OK です。

ts-jest

Jest を TypeScript で動かすためのプリプロセッサです。このプリプロセッサでは TypeScript で書いた Jest テストを JavaScript に変換する役割があります。

npm install --save-dev ts-jest

インストールするだけでは有効にならず設定ファイル( jest.config.ts )が必要になります。コマンド実行時には jest.config.js が作成されるので TypeScript ファイルに変換しましょう(変換する必要はありませんが、統一したいので変換しています)

npx ts-jest config:init

jest.config.ts で考えること

  • .js を .ts に変換する
  • preset は "ts-jest" とする
    • transformer は preset の指定をすると内部で設定されるので省略
  • testEnvironment は DOM 環境をブラウザで動いてるかのようにみせるため jsdom に変換
jest.config.ts
import type {Config} from 'jest';

const config: Config = {
  preset: "ts-jest",
  testEnvironment: "jsdom",
};

export default config;

jest.config.js は次のような内容になっています。

jest.config.js
/** @type {import('ts-jest').JestConfigWithTsJest} **/
export default {
  testEnvironment: "node",
  transform: {
    "^.+.tsx?$": ["ts-jest",{}],
  },
};

npx jest --init も良いのですが TypeScript の項目を上書きすることになるので npx ts-jest config:init が楽です

URL: https://kulshekhar.github.io/ts-jest/docs/getting-started/installation/#jest-config-file:~:text=You%20can%20also,js%20file%20afterwards.

jest-environment-jsdom

testEnvironmentjsdom が指定してあります。jsdom はコンポーネントがブラウザで動いてるかのように DOM 環境を提供するパッケージです。

npm install --save-dev jest-environment-jsdom

@types/jest

TypeScript を選択すると型定義した Jest API( descripbeexpect )が必要になります。サードパーティのパッケージ @types/jest が必要になります。

npm install --save-dev @types/jest

@jest/globals も良いのですが必要な関数を import で取り込む必要があるので @types/jest が推奨されています

URL: https://jestjs.io/docs/getting-started#:~:text=Or%20you%20may%20choose%20to%20install%20the%20%40types/jest%20package.%20It%20provides%20types%20for%20Jest%20globals%20without%20a%20need%20to%20import%20them.

ts-node

Jest の実行に ts-node が必要です。

npm install --save-dev ts-node

もしインストールせず Jest を実行すると次のエラーになります。

Error: Jest: Failed to parse the TypeScript config file /Users/akira/Project/private/vite-ts/jest.config.ts
  Error: Jest: 'ts-node' is required for the TypeScript configuration files. Make sure it is installed

React Testing Library

Jest で React コンポーネントのテストを作成するのに必要です。

npm install --save-dev @testing-library/react @testing-library/dom @types/react @types/react-dom

jest-dom インストール

React コンポーネントのテストに必要なカスタムマッチャーを追加します。

npm install --save-dev @testing-library/jest-dom

jest-dom を有効にするにはテストファイルの中で import する必要がありますが都度、テストファイルに追加する必要がありとても手間です。Jest には setupFilesAfterEnv を使ってセットアップのスクリプトを指定することが出来るのでそれを利用します。また、公式ドキュメントによると tsconfig.json で include に指定する必要があります。

URL: https://github.com/testing-library/jest-dom?tab=readme-ov-file#with-typescript

jest.config.ts で考えること

  • vite で作った tsconfig.json は project references を使っている
  • Jest では project references で参照するファイルの内容までみない
  • Jest で必要な tsconfig を新しく作成して transform で指定する
    • tsconfig.jest.json として tsconfig.app.json からコピペ
  • setupFilesAfterEnv にセットアップスクリプトを指定する
    • jest.setup.ts として jest-dom を import で呼び出す
diff --git a/jest.config.ts b/jest.config.ts
index 95b57b9..c99ca4d 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -2,6 +2,12 @@ import type {Config} from 'jest';
 
 const config: Config = {
   preset: "ts-jest",
+  transform: {
+    "^.+.tsx?$": ["ts-jest", {
+      tsconfig: "tsconfig.jest.json"
+    }],
+  },
+  setupFilesAfterEnv: ['./jest.setup.ts'],
   testEnvironment: "jsdom",
 };

公式ドキュメントにある構造だと WARN になります。

// jest.config.js
module.exports = {
  // [...]
  globals: {
    'ts-jest': {
      tsConfig: 'tsconfig.test.json'
    }
  }
};

URL: https://huafu.github.io/ts-jest/user/config/tsConfig#path-to-a-tsconfig-file

WARN メッセージ

ts-jest[ts-jest-transformer] (WARN) Define `ts-jest` config under `globals` is deprecated. Please do
transform: {
    <transform_regex>: ['ts-jest', { /* ts-jest config goes here in Jest */ }],
},

jest.setup.ts で考えること

ここは jest-dom を import を使って呼び出すだけで OK です。

jest.setup.ts
import "@testing-library/jest-dom"

tsconfig.jest.json で考えること

  • tsconfig.app.json をコピペして include にセットアップスクリプトを指定する
  • テストだけなら不要な設定が多いかも(要ブラッシュアップ)
tsconfig.jest.json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src", "jest.setup.ts"]
}

パッケージの追加、設定はここまでです。

アセット

Jest は Webpack などバンドラといっしょに動くわけではないので svg / css を理解することができません。そのため、moduleNameMapper を使ってマッチした拡張子に対してスクリプトを実行することができます。

svg / css があったとしてもコンポーネントの振る舞いに影響がないので module.exports = {}; を実行するだけで OK です。

tests/__mocks__/fileMock.ts
module.exports = {};
tests/__mocks__/styleMock.ts
module.exports = {};
diff --git a/jest.config.ts b/jest.config.ts
index c99ca4d..624a38a 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -7,6 +7,10 @@ const config: Config = {
       tsconfig: "tsconfig.jest.json"
     }],
   },
+  moduleNameMapper: {
+    "\\.svg": "<rootDir>/tests/__mocks__/fileMock.ts",
+    "\\.css": "<rootDir>/tests/__mocks__/styleMock.ts",
+  },
   setupFilesAfterEnv: ['./jest.setup.ts'],
   testEnvironment: "jsdom",
 };

テストを動かしてみる

import { render, screen } from "@testing-library/react"
import App from "../src/App.tsx"

test("render App component", async () => {
  render(<App />)

  const h1 = screen.getByRole("heading")
  expect(h1).toHaveTextContent("Vite + React")
})

これを npm run test から実行してみてください。きっとパスするはずです。

気づき

TypeScript で動かそうと思うと Jest 以外のパッケージに依存して、かつ初期化の方法が複数あったりとかなりドキュメントを読み込まないと理解することができませんでした。

リポジトリ

JISOUのメンバー募集中!

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてください!
▼▼▼

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?