LoginSignup
1
0

Vitest を導入する

Posted at

目次

はじめに
Vitest をインストールする
テストを書いてみる
Vitest の設定をする
その他の設定
import 文って省略できないの?
test に必要なライブラリを devDependencies に追加する
App.tsx のテストを書いてみる
eslint-plugin-testing-library と eslint-plugin-jest-dom を追加する
気になってた Warning が解決できた話
まとめ
次回のお知らせ
おまけ

はじめに

この記事は、TODO アプリを環境構築から作っていく様子を、少しずつ投稿していく、第4回目の記事になります。

前回までに、Vite プロジェクトを生成して、ESLint , Prettier の設定をしました。

今回は、TDD できる環境を整えていこうと思います。


👇 過去記事

Vitest をインストールする

Vitest

Viteネイティブな次世代テストフレームワーク
実行速度が速い

Vitest の公式ドキュメントは日本語に翻訳されてないのかー・・・。
英語読めるようになりたい。。。_| ̄|○

インストール

Vitest 1.0 には、Vite >= v5.0.0 と Node >= v18.00 が必要です。

package.json を確認したら、Vite も Node も上記の要件はクリアしてる!

npm i -D vitest

インストールコマンドを実行したら下記が表示された

added 54 packages, removed 7 packages, changed 19 packages, and audited 331 packages in 15s

128 packages are looking for funding
  run `npm fund` for details

1 moderate severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

なんで日本語じゃないのよ・・・。
必要そうなとこだけ翻訳すると、

  • 深刻度が中程度の脆弱性が1件あるよ。
  • すべての問題に対処するには npm audit fix を実行してね。
  • 詳細が知りたかったら npm audit を実行してね。

ってことらしい。。。
そういうことなら、 npm audit fix を実行して解決してもらいましょう!

npm audit fix
changed 7 packages, and audited 331 packages in 7s

128 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

脆弱性は0件になったみたい!

ところで npm audit fix って何?

プロジェクトの脆弱性をスキャンして、脆弱な依存関係に互換性のあるアップデートを自動的にインストールしてくれるもの

らしい。ふーん。

とりあえずここでコミットしておきましょう!
git commit -m "Vitest をインストール & 脆弱性を解決した"
GitHubリポジトリ 👉 https://github.com/b-yuko/todo-app-tdd

テストを書いてみる

公式ドキュメントにあるものをそのまま使ってテストできるかやってみる!
JS のところを TS で書いて・・・

sum.ts
export function sum(a: number, b: number) {
  return a + b
}
sum.test.ts
import { expect, test } from 'vitest'
import { sum } from './sum'

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

package.json の scripts に test を追加して・・・

package.json
  {
    "scripts": {
+     "test": "vitest"
    },
  }

ターミナルから

npm run test

おぉ〜〜〜テスト出来てる!!

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  15:50:19
   Duration  196ms (transform 0ms, setup 0ms, collect 10ms, tests 1ms, environment 0ms, prepare 73ms)

なんか満足😊

Vitest の設定をする

Vitest の公式ドキュメントの Configuring Vitest を読んでみると、英語で読むのが苦痛になるが😓Viteを使っているなら vite.config.ts に Vitest 用の設定を追加すれば OK らしい。vitest.config.ts を作成する話も書いてあるけど、ドキュメントの WARNING の最後に But we recommend to use the same file for both Vite and Vitest instead of creating two separate files. とあるように、ViteとVitestの両方で同じファイルを使用することを勧められているので、今回は既存の vite.config.ts に設定を追加する方針で行きたいと思います。

公式ドキュメントに書いてあるように追記してみました。

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

  // https://vitejs.dev/config/
  export default defineConfig({
    plugins: [react()],
+   test: {
+     // vitestの設定を書くところ
+   }
  })

その他の設定

公式ドキュメントの Getting Started をサラッと読んで必要そうなところを書いてみる。

Command Line Interface

上記で package.json の scripts に test を追加したけど
"test": "vitest" だと、コードが書き換わるのを監視しているっぽい。
必要なタイミングで npm run test を実行する場合は、"test": "vitest run" にするみたい。

へ〜。じゃあそうしよう!!

package.json
  {
    "scripts": {
-     "test": "vitest"
+     "test": "vitest run"
    },
  }

詳細はここを見ればよさそう👇

他には特筆したいところがなかったな〜。。。

import 文って省略できないの?

さっきお試しで書いた sum.test.ts に、expect と test をインポートする行があったんだよね〜。試しにコメントアウトしたら、expect と test が真っ赤になりました💦テストファイルだし、いちいちインポートしなくても済む方法ないのかな〜?

雑にググってみる。
import { expect, test } from 'vitest' 検索ポチっ

やば。ドンピシャな記事出てきた🎉

ありがたく拝読させてもらおう🙏

拝読させてもらった上で、こう変えた。

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

  // https://vitejs.dev/config/
  export default defineConfig({
    plugins: [react()],
    test: {
-     // vitestの設定を書くところ
+     globals: true
    }
  })
tsconfig.json
  {
    "compilerOptions": {
      "target": "ES2020",
      "useDefineForClassFields": true,
      "lib": ["ES2020", "DOM", "DOM.Iterable"],
      "module": "ESNext",
      "skipLibCheck": true,
+     "types": ["vitest/globals"],

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

      /* Linting */
      "strict": true,
      "noUnusedLocals": true,
      "noUnusedParameters": true,
      "noFallthroughCasesInSwitch": true
    },
    "include": ["src"],
    "references": [{ "path": "./tsconfig.node.json" }]
  }

おぉ〜〜〜。
インポート文をコメントアウトしても怒られなくなった!!

あ〜〜〜。ちゃんと公式ドキュメントに書いてあるんだ〜!!

いや・・・でもこの書き方は私には読み取れる自信ないわ・・・。
日本語で記事書いてくれてる人に感謝しかない<(_ _*)>感謝

ではここまでで一旦コミットしておきましょう。
git commit -m "Vitest の設定を追加した"
GitHubリポジトリ 👉 https://github.com/b-yuko/todo-app-tdd

test に必要なライブラリを devDependencies に追加する

React Testing Library

Reactコンポーネントをテストするためのライブラリ

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

React Testing Library の Setup を読み進めていくと、Jest を使わず、Nodeでテストする場合は jsdom 入れてねって話が書いてあるので、それも入れましょう。
ブラウザ API をシミュレートするためのグローバル環境をセットアップするために使用できる global-jsdom というパッケージもあるみたいだけど、実は DOM Testing Library の Setup を読むと、Vitest を使用している場合は jsdom に環境を設定するだけでよいらしいので、jsdom のみインストールします。

npm install --save-dev jsdom

jest-dom

Jest 用のカスタム DOM 要素マッチャを提供する Testing Library の付属ライブラリ
これを入れないと toBeInTheDocument などが使えないから入れます(Jest 使ってないのに?!)

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

Testing Library の公式ドキュメントにはあまり詳しく書かれていないけど、ページの下の方に

Check out jest-dom's documentation for a full list of available matchers.

と書いてあり、jest-dom のドキュメントが存在することを教えてくれている。
ドキュメントを開いて読み進めていくと、With Vitest の文字が!!!
Jest 用と言いつつ、Vitest を使う場合の設定方法が書いてある。
その下には、TypeScript を使う場合の設定方法も。
さらにその下には、Jest 互換の expect を使う場合の設定方法も。
Vitest と TypeScript を使っているので、この3項目は設定が必要みたいです。

ざっと通して読み、
まずは、 frontend の直下に vitest-setup.ts を作り、import 文を書きます。

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

次に、vite.config.ts に setupFiles を追加する。

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

  // https://vitejs.dev/config/
  export default defineConfig({
    plugins: [react()],
    test: {
      globals: true,
+     setupFiles: ['./vitest-setup.ts']
    }
  })

次に、セットアップファイルを tsconfig.json に含めます。

tsconfig.json
  {
    "compilerOptions": {...},
-   "include": ["src"],
+   "include": [
+     "src",
+     "./vitest-setup.ts"
+   ],
    "references": [{ "path": "./tsconfig.node.json" }]
  }

最後に、vitest-setup.ts に Vitest の expect が使える設定を足します。

vitest-setup.ts
  import '@testing-library/jest-dom/vitest'
+ import * as matchers from '@testing-library/jest-dom/matchers'
+ import { expect } from 'vitest'

+ expect.extend(matchers)

ドキュメントからコピペするときに、拡張子が js だったり、ファイル名が jest-setup だったり、多少の読み替えが必要なので注意が必要だな〜と感じました。

ここまでで必要なライブラリと付随する設定も入れれたと思うのでコミットします!
git commit -m "テストに必要なライブラリと付随する設定をした"
GitHubリポジトリ 👉 https://github.com/b-yuko/todo-app-tdd

App.tsx のテストを書いてみる

既存の App.tsx に対して、「Vite + React」って文字が表示されてるよね?ってテストを書いてみたいと思います。

frontend/src の直下に tests ディレクトリを作成して、その中に App.test.tsx を作成します。

App.test.tsx
import { describe, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import App from '../App.tsx';

describe('App を render したとき', () => {
  test('「Vite + React」 という文字が表示される', () => {
    // Given

    // When
    render(<App />);

    // Then
    expect(screen.getByText('Vite + React')).toBeInTheDocument();
  });
});

これでなんとなくテストは書けたと思うので、テストを実行してみる。

ち〜〜〜ん。なんかエラーでた。。。_| ̄|○

ReferenceError: document is not defined

ChatGPT 先生に、これ何?ってエラー文を雑に投げる。
DOM を扱うことができないからエラーになってるんじゃない?って感じのことを言われた・・・。

思い当たる節があるとすれば、jsdom の設定か何かが足りていないように思う。
Testing Library ではインポート文くらいしか書いてなかったしな〜・・・。

Vitest の公式ドキュメント内の検索で jsdom って入れたら何か見つかるかな??
あ〜・・・。あった。

テストファイルの一番上に

App.test.tsx
+ // @vitest-environment jsdom
  import ...

これを書けばよさそう。
上記を追加してテストを回すと、テストがパスすることを確認できた!

いや〜だけどさ、毎回テストファイルに書きたくないよね〜。
vitest の設定だし、vite.config.ts に書けるのかな??

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

// https://vitejs.dev/config/
  export default defineConfig({
    plugins: [react()],
    test: {
      globals: true,
      setupFiles: ['./vitest-setup.ts'],
+     environment: "jsdom"
    }
  })

適当に書いてみたら IntelliJ がサジェストしてくれて、いい感じに書けたっぽい。
// @vitest-environment jsdomを消して、テストを回してみるとパスすることが確認できた。
試しに App.tsx から「Vite + React」の文字がある部分をコメントアウトすると、テストが失敗するのでテストとしては大丈夫そう。
テストがパスしたら一度実装を壊してテストが失敗することを確認するようにって先輩エンジニアが言ってたときのメモを見つけた。メモしただけで終わってないよ!

そういえば、import { describe, expect } from 'vitest';って省略できるように設定したのに、IntelliJ が気を利かせて入れてくれたんだ・・・。いらないのに・・・。すでに設定したものについては import とかいらないんだけど、IntelliJ でここら辺の設定できるのかな?←知ってる人いたら教えて〜<(_ _*)>

あとは、さっき見てた Vitest の公式ドキュメントの TIP に、

Since Vitest 1.3.0 jsdom environment exposes jsdom global variable equal to the current JSDOM instance. If you want TypeScript to recognize it, you can add vitest/jsdom to your tsconfig.json when you use this environment:
(訳) Vitest 1.3.0以降のjsdom環境では、現在のJSDOMインスタンスと同じグローバル変数jsdomが公開される。TypeScriptにこの環境を認識させたい場合は、tsconfig.jsonにvitest/jsdomを追加してください:

って書いてあったから、これだけ追加しておこうかな。

tsconfig.json
  {
    "compilerOptions": {
      "target": "ES2020",
      "useDefineForClassFields": true,
      "lib": ["ES2020", "DOM", "DOM.Iterable"],
      "module": "ESNext",
      "skipLibCheck": true,
-     "types": ["vitest/globals"],
+     "types": [
+       "vitest/globals",
+       "vitest/jsdom"
+     ],

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

      /* Linting */
      "strict": true,
      "noUnusedLocals": true,
      "noUnusedParameters": true,
      "noFallthroughCasesInSwitch": true
    },
    "include": [
      "src",
      "./vitest-setup.ts"
    ],
    "references": [{ "path": "./tsconfig.node.json" }]
  }

きりがいいのでコミットしておきます。
git commit -m "Appのテストを試しに書いて、必要な設定を追加した"
GitHubリポジトリ 👉 https://github.com/b-yuko/todo-app-tdd

eslint-plugin-testing-library と eslint-plugin-jest-dom を追加する

Testing Library の公式ドキュメントにこの2つが載っていたので、入れておくか〜って感じです。

eslint-plugin-testing-library を追加する

GitHub ページに詳細が書いてあるので、それを見ながら入れてみます。

npm install --save-dev eslint-plugin-testing-library
.eslintrc.cjs
  module.exports = {
    ...,
    extends: [
      'eslint:recommended',
      'plugin:@typescript-eslint/recommended-type-checked',
      'plugin:react-hooks/recommended',
      'plugin:react/recommended',
      'plugin:react/jsx-runtime',
      'plugin:jsx-a11y/recommended',
+     'plugin:testing-library/react',
+     'plugin:testing-library/dom',
      'prettier'
    ],
    ...,
    plugins: [
        'react',
        'react-refresh',
        'jsx-a11y',
+       'testing-library'
    ],
    ...
  }

eslint-plugin-jest-dom を追加する

先ほどと同様に GitHub を見ながら入れていきます。

npm install --save-dev eslint-plugin-jest-dom
.eslintrc.cjs
  module.exports = {
    ...,
    extends: [
      'eslint:recommended',
      'plugin:@typescript-eslint/recommended-type-checked',
      'plugin:react-hooks/recommended',
      'plugin:react/recommended',
      'plugin:react/jsx-runtime',
      'plugin:jsx-a11y/recommended',
      'plugin:testing-library/react',
      'plugin:testing-library/dom',
+     'plugin:jest-dom/recommended',
      'prettier'
    ],
    ...,
    plugins: [
        'react',
        'react-refresh',
        'jsx-a11y',
        'testing-library',
+       'jest-dom'
    ],
    ...
  }

これでよさそう。

コミットします。
git commit -m "Testing Library の ESLint を導入した"
GitHubリポジトリ 👉 https://github.com/b-yuko/todo-app-tdd

気になってた Warning が解決できた話

ずっと前から気になってた Warning が2つほどあった。
ESLint の設定ファイルで、
module に対して Unresolved variable or type module
__dirname に対して Unresolved variable or type __dirname

積極的に解決しにいったわけではなくて、tsconfig.json の設定についてなんとなく色んなページをチラチラ見てたときに偶然見つけたの。
それがこのページ。

結論。
@types/node のインストールが必要なんだって。
Node.js の TypeScript 用 型定義ファイル らしい。

@types/node のバージョンは node のバージョンに対応しているらしいので、できるだけ近いバージョンを入れたほうがいいみたい。

node のバージョンが、20.11.0 だったので、下記ページの Current Tags の中から 20.11 を探すと 20.11.25 があったのでこれを入れようと思います。

npm i -D @types/node@20.11.25

おぉ〜〜〜!
Warning が消えました!!!!!
だったら最初から Vite のパッケージに入れておいてくれればいいのにっ!!!!!

忘れる前にコミットしよう。
git commit -m "@types/node をインストールした"
GitHubリポジトリ 👉 https://github.com/b-yuko/todo-app-tdd

まとめ

今回は、Vitest を入れて、テストで必要なライブラリを入れて、各種設定を行いました。
ひとまずこれで TDD ができる準備が整いました!

あ〜〜〜。長かった〜〜〜。
色んなところでつまずいて、たくさん時間を溶かしたけど、各種設定も公式ドキュメントに沿って書けたので納得感があってよきです。

これでようやく TDD しながら todo アプリが作れそうです!

次回のお知らせ

最初は、テキスト入力欄に文字を入れて、ボタンを押したら、バックエンドに情報が渡り、データベースに保存して、データベースに保存されたものを取り出して、フロントエンドに返して、画面に表示する。という一番シンプルなところをやってみたいと思います。
と言ってもまだバックエンドの準備してないし、結構ボリューミーなんです・・・。
細切れになるとは思うけど、ちょっとずつ進めていきます。

おまけ

久しぶりに ESLint の公式ドキュメントを眺めたんだけど、今使ってる設定ファイルはもう既に非推奨になってました。。。_| ̄|○
フロントエンド界隈は変わるのが早いってよく聞くけど、あぁ・・・こういうことなのか・・・。というのを感じた瞬間でした。
一瞬 ESLint 消して、入れ直そうかとも思ったけど、自己学習用だし、フォーカスしたいのそこじゃないし、今回は見て見ぬふりをしようと思います。





目次に戻る

1
0
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
1
0