---
title: "Vitestの使い方と書き方：読み方・設定からReact Testing Libraryのコンポーネントテストまで【Vitest 5対応】"
url: "https://www.issoh.co.jp/tech/details/2867/"
published: 2024-07-01
updated: 2026-10-18
categories: ["テスト"]
publisher: "株式会社一創"
---

# Vitestの使い方と書き方：読み方・設定からReact Testing Libraryのコンポーネントテストまで【Vitest 5対応】

Vitestの読み方は「ヴィーテスト」です。[公式ガイド](https://vitest.dev/guide/)が冒頭で「pronounced as “veetest”」と書いており、ビルドツールのVite（ヴィート）を土台にしたJavaScript／TypeScript向けのテストフレームワークです。2026年10月18日時点の最新は5.0.5（2026年10月15日公開）で、Node.js 22.12以上とVite 6.4以上で動きます。

この記事では、インストールと設定、`describe`・`it`・`expect` を使ったテストの書き方、実行コマンド、React Testing Libraryでのコンポーネントテスト、モックまでを順に扱います。コードはすべてVitest 5.0.5（jsdom 30.1.3・Node.js 26.5.0）で実行して確かめたもので、4.1.12と結果が変わった箇所は独自の章で並べました。

## まとめ：Vitestの使い方と書き方の要点

- **導入**：`npm install -D vitest` で入ります。Reactのコンポーネントを試すなら `jsdom` とTesting Libraryの4パッケージも入れ、設定で `environment: 'jsdom'` にします。
- **書き方**：`describe` でまとめ、`it`（`test` の別名）で1ケースを書き、`expect(値).toBe(期待値)` で確かめます。ファイル名は `.test.` か `.spec.` を含めます。
- **実行**：`npx vitest` はウォッチモード、`npx vitest run` は1回だけ実行します。環境変数 `CI` が立っていれば `vitest` でも1回で終わります。
- **コンポーネント**：`render` で描画、`screen.getByRole` で取得、`user-event` で操作、jest-domのマッチャーで表示を確かめます。あとから出る要素は `findBy*` で待ちます。
- **落とし穴**：`globals` を無効にしたまま手動cleanupも設定しないと、前のテストのDOMが残り、同じ要素を探す後続テストが「Found multiple elements」で失敗することがあります。Vitest 5では `await` し忘れた非同期アサーションとテスト内の `vi.mock` が失敗扱いになりました。

## Vitestとは：読み方・Jestとの違い・Vitest 5の動作要件

VitestはViteの設定・変換・モジュール解決をそのまま使うテストフレームワークです。APIはJestとほぼ同じ形なので、Jestで書いたことがあれば `describe`・`it`・`expect` の書き方はそのまま通じます。仕組みや採用判断を深く知りたい場合は[Vitestとは？Viteネイティブなテスト基盤の仕組みと採用判断を実装目線で解説](/tech/details/16023/)を、版ごとの変更点と最新バージョンの確認方法は[Vitest 4の新機能と移行ガイド｜最新バージョンは5.0・4.1系の保守と更新手順](/tech/details/9465/)を参照してください。

| 項目         | Vitest        | Jest              |
| ---------- | ------------- | ----------------- |
| 設定         | Viteの設定を共有    | jest.configを別に書く  |
| TypeScript | 変換を標準提供       | 変換設定が必要           |
| ESM        | 標準対応          | 実験的対応・設定が必要       |
| モック        | vi.fn／vi.mock | jest.fn／jest.mock |
| グローバルAPI   | 既定は無効（import） | 既定で有効             |
| モック履歴の消去   | 5.0から既定で毎テスト  | clearMocksで指定     |
| 起動時の既定     | ウォッチ          | 1回実行              |

### Vitest 5.0.5・jsdom 30が求めるNode.jsのバージョン

Vitest 5.0は2026年9月3日にnpmへ公開されました。[5.0.5のpackage.json](https://github.com/vitest-dev/vitest/blob/v5.0.5/packages/vitest/package.json)は対応するNode.jsを `^22.12.0 || ^24.0.0 || >=26.0.0`、Viteを `^6.4.0 || ^7.0.0 || ^8.0.0` と指定しています。テスト環境に使うjsdomはさらに厳しく、[jsdom 30.0.0](https://github.com/jsdom/jsdom/releases)でNode.jsの下限を `^22.22.2 || ^24.15.0 || >=26.0.0` に引き上げました。Node.js 22.12〜22.22.1の環境では、Vitestは動く範囲でもjsdom 30は対応範囲の外です。CIのイメージを含めて `node -v` を先に確かめ、22系なら22.22.2以上に揃えてください。

Node.js 20を外せない案件は4.1系に留まることになります。4.1から5へ上げるときに落ちるテストの直し方は[Vitest 5移行ガイド：4からの破壊的変更と落ちるテストの直し方【2026年10月時点】](/tech/details/18278/)にまとめています。

## Vitestのインストールと最初のテストの実行

ここではReact + Vite + TypeScriptのプロジェクトを前提にします。Viteでプロジェクトを作る手順は[Viteとは？Reactの環境構築手順とVite 8の変更点・create-react-appからの移行](/tech/details/3587/)で扱っています。関数だけをテストするならVitest本体だけで足ります。

```
npm install -D vitest
```

Reactのコンポーネントまで試すなら、次のパッケージを一緒に入れます。React Testing Library 16.0.0（2024年6月3日）から `@testing-library/dom` がpeerDependencyに移り、[公式のインストール手順](https://testing-library.com/docs/react-testing-library/intro/)も2つを並べて入れるよう案内しています。

```
npm install -D vitest jsdom @vitejs/plugin-react \
  @testing-library/react @testing-library/dom \
  @testing-library/user-event @testing-library/jest-dom
```

`package.json` の `scripts` に `"test": "vitest"` を足すと `npm test` で起動できます。Viteのテンプレートで作ったプロジェクトは `"type": "module"` が入っています。`npm init` で作った素のプロジェクトで `vitest.config.js` を置くと、実測では起動のたびに「ESM syntax in a file loaded as CommonJS」という警告が出ました。`"type": "module"` を足すか、設定ファイルを `vitest.config.ts`／`.mjs` にすれば消えます。

### vitest.configの設定：jsdom・globals・setupFiles

```
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
  },
})
```

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

3つの設定には役割があります。`environment: 'jsdom'` はNode上に仮想のDOMを用意します。`setupFiles` で読み込む `@testing-library/jest-dom/vitest` は、[jest-domのREADME](https://github.com/testing-library/jest-dom#with-vitest)が案内するVitest用の入口で、`toBeInTheDocument` などのマッチャーをVitestの `expect` に登録します。

見落としやすいのが `globals: true` です。[Vitestのglobals](https://vitest.dev/config/globals)は既定が `false` で、[Jestからの移行ガイド](https://vitest.dev/guide/migration/jest)は「globalsを無効のままにすると、testing-libraryなどのライブラリはDOMの自動cleanupを実行しない」と書いています。実際に `globals` を書かずにカウンターのテストを2本流すと、1本目で描画した要素が残ったまま2本目が描画し、`getByRole` が「Found multiple elements with the role “button” and name “増やす”」で失敗しました。`globals: true` にするか、setupファイルに `afterEach(() => cleanup())` を書けば2本とも通ります。TypeScriptで `describe` などの型を効かせるには、`tsconfig.json` の `compilerOptions.types` に `vitest/globals` を加えます。

## テストの書き方：describe・it・expectの基本形

まずはコンポーネントではなく、ただの関数で書き方の型をつかみます。テスト対象の隣に `.test.ts` を置くのが分かりやすい置き方です。

```
// src/utils/divide.ts
export function divide(a: number, b: number) {
  if (b === 0) throw new Error('0で割れません')
  return a / b
}
```

```
// src/utils/divide.test.ts
import { describe, it, expect } from 'vitest'
import { divide } from './divide'

describe('divide', () => {
  it('6を2で割ると3を返す', () => {
    expect(divide(6, 2)).toBe(3)
  })
  it('0で割ると例外を投げる', () => {
    expect(() => divide(1, 0)).toThrow('0で割れません')
  })
})
```

`describe` は関連するテストのまとまり、`it` は1つのケース、`expect` は検証です。`globals: true` にしていても、上のように `vitest` から `import` しておくとエディタの補完と型が素直に効きます。

### itとtestの違い：別名なのでどちらで書いても同じ

[VitestのAPIリファレンス](https://vitest.dev/api/test.html)は `it` を `test` の別名（Alias）としています。挙動の差はありません。「`describe` の中は `it`、トップレベルは `test`」という命名規約も選べます。プロジェクト内で使い分けや統一のルールを決めておけば十分です。

### toBe・toEqual・toThrowの使い分けと例外テストの書き方

`toBe` は `Object.is` による厳密な比較、`toEqual` はオブジェクトや配列の中身の比較です。`{ id: 1 }` 同士を `toBe` で比べると別のオブジェクトなので失敗し、`toEqual` なら通ります。

`toThrow` で例外を確かめるときは、[公式ドキュメント](https://vitest.dev/api/expect.html#tothrow)のとおり対象のコードを関数で包んで渡します。包まずに `expect(divide(1, 0)).toThrow()` と書くと、`expect` に値が届く前に例外が飛び、テストは「Error: 0で割れません」で失敗しました。引数には部分一致の文字列、正規表現（`/割れ/`）、エラークラス（`Error`）のどれでも渡せます。メッセージが違うときは「expected \[Function\] to throw error including ‘ゼロ’ but got ‘0で割れません’」と、期待と実際の両方が表示されます。Vitest 5では `toThrowError` が非推奨の別名になったので、新しく書くなら `toThrow` を使います。

### test.eachとbeforeEach・afterEachによるテスト処理の共通化

入力だけが違うケースは `test.each` に表として渡すと、1ケースずつ別のテストとして結果に並びます。テストの前後で毎回やる準備と後片付けは `beforeEach`／`afterEach` に寄せます。

```
import { describe, test, it, expect, beforeEach, afterEach, vi } from 'vitest'

const add = (a: number, b: number) => a + b

describe('add', () => {
  test.each([
    [1, 2, 3],
    [0, 0, 0],
    [-1, 1, 0],
  ])('add(%i, %i) は %i', (a, b, expected) => {
    expect(add(a, b)).toBe(expected)
  })
})

describe('日付に依存する処理', () => {
  beforeEach(() => {
    vi.useFakeTimers()
    vi.setSystemTime(new Date('2026-10-18T09:00:00+09:00'))
  })
  afterEach(() => {
    vi.useRealTimers()
  })
  it('現在時刻を固定できる', () => {
    expect(new Date().toISOString()).toBe('2026-10-18T00:00:00.000Z')
  })
})
```

実行結果には「add(1, 2) は 3」「add(0, 0) は 0」のように展開された名前で3件が並び、どの入力で落ちたかがすぐ分かります。

## テストの実行コマンド：npx vitest・vitest run・-tによる絞り込み

Vitestが拾うのは、ファイル名に `.test.` か `.spec.` を含むファイルです。実測でも `b.spec.js` は実行され、`a.tests.js` は無視されました。

```
npx vitest                       # ウォッチモードで起動（保存のたびに再実行）
npx vitest run                   # 1回だけ実行して終了
npx vitest run src/utils         # パスで絞る
npx vitest run -t "divide > 0で割る"  # テスト名で絞る
npx vitest run --coverage        # カバレッジ計測
```

環境変数 `CI` が立っている環境では、`run` を付けなくても1回で終わります。`CI=true npx vitest` は終了コード0で戻りました。GitHub ActionsなどはCIを自動で設定するので、`npm test` のままでもジョブが止まりません。

`-t` の照合規則はVitest 5で変わりました。[移行ガイド](https://vitest.dev/guide/migration/)によると、照合の対象は「describe名 > テスト名」と `>` でつないだ完全な名前です。実測では `-t "Counter > 初期値"` が1件を実行し、4系の書き方の `-t "Counter 初期値"` は2件ともスキップされました。テスト名の一部だけ（`-t "初期値"`）なら従来どおり一致します。

カバレッジは本体に含まれません。`--coverage` を付けると「MISSING DEPENDENCY Cannot find dependency ‘@vitest/coverage-v8’」で止まるので、`npm install -D @vitest/coverage-v8` を足します。既定設定での実測では、テストが1件でも落ちているとカバレッジの表は出力されませんでした。失敗時も出力するには `coverage.reportOnFailure: true` を設定します。

## React Testing LibraryとVitestによるコンポーネントテスト

Testing Libraryはテストランナーではありません。[公式ドキュメント](https://testing-library.com/docs/)は自らを「UIコンポーネントをユーザー中心の方法でテストするためのパッケージ群」と説明しています。テストの実行と `expect` はVitest、描画・要素の取得・操作はTesting Library、と役割を分けて考えます。

| パッケージ                       | 役割         | 2026-10-18時点 |
| --------------------------- | ---------- | ------------ |
| @testing-library/react      | 描画とcleanup | 16.3.3       |
| @testing-library/dom        | クエリの本体     | 10.4.2       |
| @testing-library/user-event | クリック・入力の再現 | 14.6.8       |
| @testing-library/jest-dom   | DOM向けマッチャー | 7.0.1        |

要素の探し方には順番があります。[クエリの公式解説](https://testing-library.com/docs/queries/about/)は、誰でも操作できる手がかり（`ByRole`・`ByLabelText`・`ByText` など）を優先し、`ByTestId` は最後の手段としています。RTL単体の考え方は[React Testing Libraryとは？使い方・クエリ・ベストプラクティスを実務目線で解説](/tech/details/3521/)で掘り下げています。

### renderとscreenでカウンターを描画する最初のテスト

```
// src/components/Counter.tsx
import { useState } from 'react'

export function Counter({ initialCount = 0 }: { initialCount?: number }) {
  const [count, setCount] = useState(initialCount)
  return (
    <div>
      <p>カウント: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>増やす</button>
    </div>
  )
}
```

```
// src/components/Counter.test.tsx
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Counter } from './Counter'

describe('Counter', () => {
  it('初期値を表示する', () => {
    render(<Counter initialCount={5} />)
    expect(screen.getByText('カウント: 5')).toBeInTheDocument()
  })
  it('ボタンを押すとカウントが増える', async () => {
    const user = userEvent.setup()
    render(<Counter />)
    await user.click(screen.getByRole('button', { name: '増やす' }))
    expect(screen.getByText('カウント: 1')).toBeInTheDocument()
  })
})
```

`screen` は `document.body` 全体を対象にしたクエリの集まりです。`render` の戻り値から取り出す書き方もありますが、`screen` に揃えるとテストが増えても書き方がぶれません。このテストは前の章の設定（`globals: true`）で2件とも通ります。

### getBy・queryBy・findByの違い：要素が無いときの挙動

| クエリ       | 見つからない時 | 使う場面     |
| --------- | ------- | -------- |
| getBy\*   | すぐ例外    | 今あるはずの要素 |
| queryBy\* | nullを返す | 無いことの確認  |
| findBy\*  | 待ってから例外 | あとから出る要素 |

100ミリ秒後に「読み込み完了」へ切り替わるコンポーネントで3つを比べると、`await screen.findByText('読み込み完了')` は137ミリ秒で通り、`getByText` は「Unable to find an element with the text: 読み込み完了」ですぐ失敗しました。描画直後に「まだ無い」ことを確かめる `expect(screen.queryByText('読み込み完了')).not.toBeInTheDocument()` は通ります。`findBy*` はPromiseを返すので、`await` を忘れると要素を待たずに次の行へ進みます。

### user-eventによるクリック・入力の再現

操作の再現は `@testing-library/user-event` が公式の推奨です。[user-eventの公式解説](https://testing-library.com/docs/user-event/intro/)によると、`fireEvent` が1つのDOMイベントを発火させるだけなのに対し、user-eventはクリック1回でもフォーカス移動などを含む一連のイベントをブラウザと同じ順で起こします。`userEvent.setup()` で準備し、`user.click()`・`user.type()` には必ず `await` を付けます。クエリと操作の実例は[React Testing Libraryのuser-eventとクエリ実践｜getByRole・findBy・fireEventの使い分け](/tech/details/4465/)に集めています。

### jest-domのマッチャー：toBeInTheDocumentとtoBeVisibleの違い

以下は各マッチャーの使用例です。対応する要素を描画したテストの中に記述します。上のCounterにはtextboxとstatusがないため、後半2行は入力欄や保存結果を表示する別のコンポーネントを前提にしています。

```
expect(screen.getByText('カウント: 1')).toBeInTheDocument()
expect(screen.getByRole('button', { name: '増やす' })).toBeVisible()
expect(screen.getByRole('textbox')).toHaveValue('入力値')
expect(screen.getByRole('status')).toHaveTextContent('保存しました')
```

`toBeInTheDocument` はDOMに存在するか、`toBeVisible` は `display: none` などで隠れていないかを見ます。モーダルの開閉のように「要素はあるが見えない」状態を確かめるときは `toBeVisible` を使います。[jest-dom 7.0.0](https://github.com/testing-library/jest-dom/releases)（2026年7月20日）は `@testing-library/dom` を必須のpeerDependencyにし、Node.jsの下限を22へ上げています。

## モックの書き方：vi.fn・vi.mock・vi.spyOn

外部APIのように毎回本物を呼べない依存は、モックに差し替えます。`vi.fn()` はモック関数、`vi.mock()` はモジュールごとの置き換えで、Jestの `jest.fn`／`jest.mock` に当たります。戻り値や実装の差し替え方は[Jest mockImplementationの使い方｜戻り値・非同期・実装差し替えを実務目線で解説](/tech/details/4065/)と同じ考え方です。

次の例では、テスト対象と依存モジュールを以下の2ファイルに分けます。テストは同じディレクトリの `greet.test.ts` に保存します。

```
// src/api.ts
export async function fetchName(): Promise<string> {
  throw new Error('テストではモックに差し替えます')
}
```

```
// src/greet.ts
import { fetchName } from './api'

export async function greet() {
  return `こんにちは、${await fetchName()}さん`
}
```

```
// src/greet.test.ts
import { describe, it, expect, vi } from 'vitest'
import { greet } from './greet'
import { fetchName } from './api'

vi.mock('./api', () => ({
  fetchName: vi.fn(),
}))

describe('greet', () => {
  it('APIをモックして挨拶文を組み立てる', async () => {
    vi.mocked(fetchName).mockResolvedValue('テスト太郎')
    expect(await greet()).toBe('こんにちは、テスト太郎さん')
    expect(fetchName).toHaveBeenCalledTimes(1)
  })
})
```

`vi.mock` はファイルの先頭へ巻き上げて実行されるので、`import` より後ろに書いても先に効きます。既存のオブジェクトのメソッドだけを監視したいときは `vi.spyOn` を使います。

```
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
console.error('x')
expect(spy).toHaveBeenCalledWith('x')
spy.mockRestore()
```

## Vitest 4.1.12と5.0.5で同じテストを流した実測差

同じテストファイルを4.1.12と5.0.5で実行すると、結果が変わる書き方が3つありました。どれも[Vitest 5の移行ガイド](https://vitest.dev/guide/migration/)に載っている変更ですが、4系では警告だけで通っていたため、古い記事のコードを写すと5系で初めて赤くなります。

| 書き方                | 4.1.12    | 5.0.5    |
| ------------------ | --------- | -------- |
| resolvesをawaitしない  | 警告のみで通過   | 失敗       |
| it内でvi.mock        | 警告のみで通過   | エラー・0件実行 |
| beforeAllで呼んで回数を検証 | 回数を持ち越し失敗 | 通過       |

1つ目は `expect(Promise.resolve(2)).resolves.toBe(2)` のように値が正しくても、`await` が無いだけで5.0.5は `was not awaited` というエラーで失敗させます。4.1.12は同じ文面に「次のメジャーで失敗にする」と添えて通していました。直し方は行頭に `await` を付けるだけです。

2つ目は `it` の中に書いた `vi.mock` です。5.0.5は「was defined outside of the module’s top level scope」でファイルごと止め、テストは1件も実行されません。テストごとにモジュールを差し替える場合は、`vi.doMock` の後で対象を動的に `import()` します。すでに読み込んだモジュールや静的importには適用されません。上の例のように戻り値だけを変えるなら、トップレベルの `vi.mock` を維持し、各テストで `mockResolvedValue` を設定します。

3つ目は逆向きの変化です。`beforeAll` でモック関数を1回呼び、各テストで `toHaveBeenCalledTimes` を見るテストを書くと、4.1.12は呼び出し回数が1→2→3と前のテストから積み上がり、3件とも落ちました。5.0.5では [clearMocks](https://vitest.dev/config/clearmocks) の既定が `true` になり、各テストの前に呼び出し履歴が消えます。`mockResolvedValue` で決めた実装は残るので、3件とも通りました。Jestで `clearMocks` を有効にしていなかったプロジェクトから移すと、回数の検証結果がここで変わります。

## Jestから移行するときの置き換え

VitestはJestに似たAPIを提供しますが、モックのfactory戻り値やmockReset、タイマーなどには挙動差があります。まず確認する設定・記法は次の4点です。

- **モックの接頭辞**：`jest.fn`→`vi.fn`、`jest.mock`→`vi.mock`、`jest.spyOn`→`vi.spyOn`。
- **グローバルAPI**：Jestの書き方のまま `import` 無しで動かすなら `globals: true`。Testing Libraryの自動cleanupもこれで動きます。
- **設定ファイル**：`jest.config` の内容を `vitest.config` の `test` へ移します。Vitest 5は親ディレクトリの設定ファイルを探さないので、モノレポではパッケージごとに置くか `--config` で指定します。
- **setupファイル**：`import '@testing-library/jest-dom'` を `@testing-library/jest-dom/vitest` へ書き換えます。

## jsdomで足りる場面・実ブラウザへ移す場面の判断基準

jsdom上のVitestとTesting Libraryは、フォームの入力検証、表示の出し分け、APIの応答に応じた描画のように「DOMの状態で合否が決まる」テストに向いています。合否がテキスト・属性・入力値・呼び出し回数で決まり、画面幅やスクロールに依存しないなら、この組み合わせで書きます。どの層に何本書くかは[Testing Trophy（テスティングトロフィー）とは？Kent C. Doddsの4層とテストピラミッドとの違い](/tech/details/8765/)が参考になり、本記事の書き方はその結合テストの層にあたります。

次の3つはjsdomで書かないと決めてください。1つ目はレイアウトの検証です。jsdomは描画エンジンを持たないため、要素が重なって押せない不具合は検出できません。2つ目は `IntersectionObserver`・`ResizeObserver`・Canvasに頼るUIで、モックだらけになった時点でテストの意味が薄れています。3つ目は認証のリダイレクトや複数ページをまたぐ導線で、[Vitest Browser Modeの使い方｜Playwrightでの導入・headless設定とjsdomとの使い分け【Vitest 5対応】](/tech/details/7394/)や[Playwright Component Testingの使い方｜1.62のstory方式と移行手順](/tech/details/7392/)のような実ブラウザのツールかE2Eの担当です。

保守の面では、`getByTestId` に偏ったテストは、ユーザーが認識する役割や名前の変更を検証できないことがあります。`getByRole` と表示文言を軸に書き、`data-testid` は役割や文言などのクエリで適切に取得できない場合に使います。同じ役割・同じ名前の要素が並ぶ場合は、まず `within` で対象領域を絞る方法を検討してください。テストをCIに組み込み、プルリクエストごとに自動で回す仕組みづくりから任せたい場合は、[DevOps・CI/CD導入支援](/service/system/devops/)で相談を受けています。

## よくある質問

### Vitestの読み方は？

「ヴィーテスト」です。公式ガイドが「pronounced as “veetest”」と発音を示しています。土台のVite（ヴィート）に「test」を付けた名前です。

### Vitestのitとtestに違いはありますか？

ありません。公式のAPIリファレンスで `it` は `test` の別名とされており、どちらで書いても同じように動きます。プロジェクト内でどちらかに揃えておけば十分です。

### VitestのtoThrowが通らないのはなぜですか？

多いのは、対象の関数を包まずに直接呼んでいるケースです。`expect(() => divide(1, 0)).toThrow()` のように関数で包んで渡します。非同期関数の例外は `await expect(promise).rejects.toThrow()` と書き、`await` を忘れるとVitest 5ではテストが失敗します。

### VitestとJestはどちらを使うべきですか？

Viteを使うプロジェクトや新規のプロジェクトでは、設定を共有できてTypeScriptも追加設定なしで動くVitestを選びます。Testing Libraryのテストはどちらでも同じ書き方です。Node.js 20の環境を外せない場合は、Vitest 5もjest-dom 7も動かないので、Vitest 4.1系かJestを選びます。

### VitestでReactのテストを実ブラウザで動かせますか？

Browser Modeを使えば動かせます。jsdomの代わりにPlaywrightなどで起動した実ブラウザでテストが走り、レイアウトや実ブラウザ固有のAPIも検証できます。導入手順はVitest Browser Modeの記事で扱っています。

## 関連記事

- [Vitest 4の新機能と移行ガイド｜最新バージョンは5.0・4.1系の保守と更新手順](/tech/details/9465/)
- [Vitest 5移行ガイド：4からの破壊的変更と落ちるテストの直し方【2026年10月時点】](/tech/details/18278/)
- [React Testing Libraryとは？使い方・クエリ・ベストプラクティスを実務目線で解説](/tech/details/3521/)
- [React Testing Libraryのuser-eventとクエリ実践｜getByRole・findBy・fireEventの使い分け](/tech/details/4465/)
- [Vitest Browser Modeの使い方｜Playwrightでの導入・headless設定とjsdomとの使い分け【Vitest 5対応】](/tech/details/7394/)

---

出典: [Vitestの使い方と書き方：読み方・設定からReact Testing Libraryのコンポーネントテストまで【Vitest 5対応】](<https://www.issoh.co.jp/tech/details/2867/>)（株式会社一創）
