Vitestを使ってテストをしたい

## 背景
テストについて学んでいる中で、Vitestを使いたいとなった時に環境構築で時間を溶かしたのでその備忘です。

## 事前の環境
Vite + React + TypeScript


## やりたいこと
```Home.tsx
function Home() {
  return <h1>Vitestを使いたい</h1>;
}

export default Home;
```
このようなコンポーネントに対して、以下のようなテストをしようとしました。(取ってきた要素が指定の文字列になっているか)
```Home.test.tsx
test("「Vitestを使いたい」の文字が表示されるか", () => {
  render(<Home />);
  const target = screen.getByRole("heading", { level: 1 });
  expect(target).toHaveTextContent("Vitestを使いたい");
});
```


## 最初の準備と出たエラー
まずはVitest, Testing Libraryのドキュメントを参考に必要なものをインストールしました。
```
npm install -D vitest
npm install --save-dev @testing-library/react
```

toHaveTextContentはjest-domの機能なのでjest-domをインストールしました。
```
npm install --save-dev @testing-library/jest-dom
```

今のHome.test.tsxの状態は以下のような感じです。
```Home.test.tsx
import { expect, test } from "vitest";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import Home from "./Home";

test("「Vitestを使いたい」の文字が表示されるか", () => {
  render(<Home />);
  const target = screen.getByRole("heading", { level: 1 });
  expect(target).toHaveTextContent("Vitestを使いたい");
});
```

Vitestのドキュメントにある設定を追加して、
```package.json
{
  "scripts": {
    "test": "vitest"
  }
}
```
これで`npm run test`したところ、
```
ReferenceError: expect is not defined
```
このようなエラーが出ました。
このエラーを解消するために以下のことをやっていきました。


## 解消するためにしたこと
### jest-domまわり
jest-domのドキュメントを見ると、環境ごとの設定が書いてあります。
Vitestを使ってる場合や、TypeScriptを使ってる場合の記述があるのでそれを実行していきます。

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

**Vitest用**
```vitest-setup.ts(ないと思うので作成します)
import "@testing-library/jest-dom/vitest";
```
上記でVitest用のjest-domをインポートしてるのでHome.test.tsxの方でimportしているjest-domの設定は削除しました。
```Home.test.tsx
import { expect, test } from "vitest";
import { render, screen } from "@testing-library/react";
import Home from "./Home";

test("「Vitestを使いたい」の文字が表示されるか", () => {
  render(<Home />);
  const target = screen.getByRole("heading", { level: 1 });
  expect(target).toHaveTextContent("Vitestを使いたい");
});
```

```vite.config.ts(設定を追加します)
/// <reference types="vitest" />
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  test: {
    setupFiles: ["./vitest-setup.ts"],
  },
});
```
jest-domのドキュメントを見ると「vitest.config.js」となっていますが、
Vitestのドキュメントを見ると一つにまとめるやり方を推奨していたので既にある「vite.config.ts」に設定を入れました。
また、その場合は一番上の行の「///〜〜」の内容を入れる必要があります。
(それとTypeScriptなので.jsではなく.tsに注意)

https://vitest.dev/guide/

**TypeScript用**
```tsconfig.json(設定を追加します)
"include": [
    ...
    "./vitest-setup.ts"
  ],
```

さらに、
「**With another Jest-compatible expect**」
とあるので、今回はJestではなくVitestを使っているのでこちらの設定も入れました。
```Home.test.tsx
import { expect, test } from "vitest";
import { render, screen } from "@testing-library/react";
import Home from "./Home";

import * as matchers from "@testing-library/jest-dom/matchers";

expect.extend(matchers);

test("「Vitestを使いたい」の文字が表示されるか", () => {
  render(<Home />);
  const target = screen.getByRole("heading", { level: 1 });
  expect(target).toHaveTextContent("Vitestを使いたい");
});
```

これで再度`npm run test`すると、
```
ReferenceError: expect is not defined
```
まだエラーが出てます。とほほ。。


### jsdomまわり
ドキュメントのセットアップ関連を見ると、Testing LibraryのドキュメントのReactのSetupページに、「**Using without Jest**」と書いている内容があります。
今回JestではなくVitestを使っているのでこれに該当するjsdomをインストールしました。
```
npm install --save-dev jsdom
```

https://testing-library.com/docs/react-testing-library/setup#using-without-jest

また、Vitestのドキュメントに、使う環境(jsdomを使うのか他のものを使うのか)を設定する内容が書いてあるのでそれを反映しました。
```Home.test.tsx(一番上の行を追加)
// @vitest-environment jsdom
import { expect, test } from "vitest";
import { render, screen } from "@testing-library/react";
import Home from "./Home";

import * as matchers from "@testing-library/jest-dom/matchers";

expect.extend(matchers);

test("「Vitestを使いたい」の文字が表示されるか", () => {
  render(<Home />);
  const target = screen.getByRole("heading", { level: 1 });
  expect(target).toHaveTextContent("Vitestを使いたい");
});
```

https://vitest.dev/config/

これで`npm run test`したところ、
```
Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  14:18:53
   Duration  423ms (transform 20ms, setup 51ms, collect 43ms, tests 20ms, environment 215ms, prepare 31ms)
```
無事テストが通りました👏

Home.tsxの内容を、
```Home.tsx
function Home() {
  return <h1>Vitest難しい</h1>;
}

export default Home;
```
と変更して再度テストすると、
```
Expected element to have text content:
  Vitestを使いたい
Received:
  Vitest難しい

Test Files  1 failed (1)
      Tests  1 failed (1)
   Start at  14:21:23
   Duration  437ms (transform 22ms, setup 56ms, collect 51ms, tests 23ms, environment 217ms, prepare 31ms)
```
きちんと失敗しています。


## 参考
https://vitest.dev/guide/

https://testing-library.com/docs/react-testing-library/intro

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