🧪

Vite + React + TypeScript に テスト環境 Vitest をステップbyステップで作る

2022/05/19に公開
2

Vitestのサイトを見ると、以前はトップページに記載があった
「免責事項:Vitestはまだ開発中であり、安定したものではありません。実運用での使用はお勧めしません。」が消えてました。

  • 過去のキャプチャ。Vitestのバージョンは v0.12.6
    「DISCLAIMER・・・」が表示されています。
  • 2022/05/18 現在「DISCLAIMER・・・」が消えてます。
    Vitestのバージョンは 上記と同じ v0.12.6 です。

使ってもいいのかな・・・?ということで Vite + React 環境に Vitest を導入してみました。

vitest

Vitest は Vite 環境で動作する高速なテストフレームワークです。
Vite で作成したアプリケーションであれば、vite.config.ts で設定を共有でき、環境構築が簡単です。
https://vitest.dev/

vitest のインストール

まずは vitest をインストールします。

npm install --save-dev vitest

vitest の設定

vitest の 設定は vite.config.ts で行います。
既存の vite.config.ts ファイルの先頭に 「/// <reference types="vitest" />」を追記し Vitest の型への参照を追加します。

vite.config.ts
+ /// <reference types="vitest" />
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
...

動作確認として関数テストを実行する

動作確認として簡単な関数テストを実行してみます。
src フォルダ内に add.ts と add.test.ts を作成します。

add.ts
export const add = (a: number, b: number): number => a + b
add.test.ts
import { describe, expect, it } from "vitest"
import { add } from "./add"

describe("add", () => {
  it("1 + 2 = 3", () => {
    const result = add(1, 2)

    expect(result).toBe(3)
  })
})

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

npx vitest

テスト成功です。

vitest はデフォルトで watch モードで実行されます。
watch モードではコードの変更を監視していて、コードに変更があった場合はテストが再実行されます。

watch モードなしで実行するには下記のコマンドでテストを実行します。

npx vitest run

npm run testでテスト実行できるようにする

npm run testでテスト実行できるように package.json に追記します。
watch モードなしで実行する 'testrun' も追記しておきました。

package.json
"scripts": {
    "dev": "vite",
    ・・・
+    "test": "vitest",
+    "testrun": "vitest run"
  }

vitest の API をグローバルAPI として使用できるようにする

デフォルトでは import { describe, expect, it } from "vitest"と明示的に import しないと vitest の APIが使えません。
jest のように import しなくても使用できるようにするには、vite.config.ts と tsconfig.json を以下のように変更します。

vite.config.ts
// vite.config.ts
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
+    globals: true,
  },
})
tsconfig.json
{
  "compilerOptions": {
+    "types": ["vitest/globals"]
  }
}

以上の設定で add.test.ts ファイルの import を削除してもコンパイルエラーにならず、npm run testでテスト実行できるようになります。

add.test.ts
- // import { describe, expect, it } from "vitest"
import { add } from "./add"

describe("add", () => {
  it("1 + 2 = 3", () => {
    const result = add(1, 2)

    expect(result).toBe(3)
  })
})

React コンポーネントのテスト

つづいて React コンポーネントのテストを実行してみます。
コンポーネントのテストを行うには、いくつか追加のライブラリのインストールが必要ですが、
先にコンポーネントとそのテストコードを提示しておきます。

Reactコンポーネント「MyComponent」

MyComponent.tsx
import React from 'react'

const title = 'Hello Test'

export function MyComponent() {
  return <div>{title}</div>
}

テストコード
「MyComponent」をレンダリングして、その出力内容から「Hello Test」があるかをテストしています。

MyComponent.test.tsx
import '@testing-library/jest-dom'
import { render, screen } from '@testing-library/react'
import { MyComponent } from './MyComponent'

test('「Hello Test」が描画されている', () => {
  render(<MyComponent />)
  screen.debug()
  expect(screen.getByText('Hello Test')).toBeInTheDocument()
})

上記のテストを実行するために、以下のライブラリをインストールする必要があります。

  1. jsdom または happy-dom
  2. @testing-library/react
  3. @testing-library/jest-dom

1. jsdom または happy-dom をインストール

jsdom とは DOM を JavaScript で実装したものです。
Jest では jsdom が内包されていますが、vitest では別途インストールする必要があります。
happy-dom は jsdom の代替として使用することができて、jsdom より高速に動作するようです。
https://github.com/capricorn86/happy-dom
jsdom と happy-dom のパフォーマンス比較

今回は happy-dom を使用したいと思います。

happy-dom をインストール

npm install --save-dev happy-dom

vite.config.ts

vite.config.ts
  test: {
    globals: true,
+    environment: 'happy-dom'
  }

2. @testing-library/react のインストール

Reactコンポーネントをテストするためのライブラリです。
https://testing-library.com/docs/react-testing-library/intro/
テストコードの render メソッドや screen メソッドなどを提供してくれます。

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

3. @testing-library/jest-dom のインストール

DOM 要素のマッチャーを拡張するユーティリティライブラリーです。
https://testing-library.com/docs/ecosystem-jest-dom/
テストコードの toBeInTheDocument メソッドなどを提供してくれます。

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

動作確認

npm run test でテスト実行し、コンポーネントのテストが成功することを確認します。

テストコードのimport '@testing-library/jest-dom'を書かなくてもいいようにする

現状のままだと、テストファイルに毎回「import '@testing-library/jest-dom'」を書く必要があります。
この import を書かなくてもいいように設定します。

MyComponent.test.tsx
- import '@testing-library/jest-dom'
import { render, screen } from '@testing-library/react'
import { MyComponent } from './MyComponent'

test('「Hello Test」が描画されている', () => {
  render(<MyComponent />)
  screen.debug()
  expect(screen.getByText('Hello Test')).toBeInTheDocument()
})

設定ファイルを ルート直下に作成します。
ファイル名は何でもいいですが vitest.setup.ts という名前にしました。
vitest.setup.ts に下記コードを書きます。EsLint が怒ってきますが後で設定するので今は無視しておきます。

vitest.setup.ts
import '@testing-library/jest-dom'

vite.config.ts の setupFiles プロパティに先ほど作成した設定ファイルを指定します。
setupFiles プロパティは、各テストファイルが実行される直前に実行したいスクリプトファイルを指定するプロパティです。

vite.config.ts
・・・
export default defineConfig({
  ・・・
  test: {
    globals: true,
    environment: 'happy-dom',
+    setupFiles: './vitest.setup.ts'
  }
})

以上でテストファイルに「import '@testing-library/jest-dom'」を書かなくてもよくなります。

EsLintの設定

以下の EsLint プラグインをインストールします。

npm install eslint-plugin-jest-dom --save-dev
npm install eslint-plugin-testing-library --save-dev

.eslintrc.ymlに設定値を加えます。

.eslintrc.yml
env:
  browser: true
  es2021: true
parser: '@typescript-eslint/parser'
parserOptions:
  ecmaFeatures:
    jsx: true
  ecmaVersion: latest
  project: ./tsconfig.json
plugins:
  - react
  - react-hooks
  - '@typescript-eslint'
+  - jest-dom
+  - testing-library
extends:
  - plugin:react/recommended
  - plugin:react-hooks/recommended
  - airbnb
  - airbnb-typescript
  - prettier
+ overrides:
+   - files:
+       - '**/__tests__/**/*.+(ts|tsx|js)'
+       - '**/?(*.)+(spec|test).+(ts|tsx|js)'
+     extends:
+       - plugin:jest-dom/recommended
+       - plugin:testing-library/react
ignorePatterns:
  - vite.config.ts
+ - vitest.setup.ts 
・・・

plugins で、jest-dom、testing-library の設定を読み込みます。
overrides で、jest-dom、testing-library の適用範囲を files で指定したファイルに絞ります。
ignorePatterns で、vitest.setup.ts を eslint の適用外に指定します。

VsCode に拡張機能 Vitest をインストール

VsCode に Vitest 拡張機能をインストールすると、テストの実行やデバッグがマウスでポチポチっとできるようになり便利です。
https://marketplace.visualstudio.com/items?itemName=ZixuanChen.vitest-explorer

まとめ

他にもフックをテストするためのライブラリなどインストールする必要はありますが、とりあえず vitest の導入ができ簡単なテストができるようになりました。

jest と比べて設定が簡単になるかと思いましたが、少し設定項目が減ったくらいでそこまで大きくはかわりません。

処理速度は jest と比べてかなり速いです。
下記は既存のテストを jest で実行した結果です。

こちらは同じ内容を vitest で実行してみた結果です。

単純に画像の time で比較してはいけないのかもしれませんが、体感でもかなり速いです。

テストが快適になりました🥰

Discussion

rowaxlrowaxl

ありがとうございます、めちゃくちゃ助かりました!

1点共有ですが、注意で書かれていたhappy-domだとuser-eventがうまく動かない問題、以下バージョンでは正常にクリックできるようになってました。

happy-dom: 6.0.4
vite: ^3.0.7
vitest: ^0.22.1
piyokopiyoko

こちらこそ情報をいただきありごうございます!