
Vitest 4 のブラウザモード - jsdom を卒業して実ブラウザでテストする
ユニットテストやコンポーネントテストを書くとき、長らく定番だったのは jsdom や happy-dom のような擬似的なDOM環境でした。Node.js 上で「ブラウザのフリ」をする仕組みです。手軽な一方、「テストは通るのに実ブラウザだと挙動が違う」という擬似DOM特有のズレに悩まされることもありました。
2025年10月22日にリリースされた Vitest 4 で、その答えになるブラウザモード(Browser Mode)が experimental(実験的)から安定版になりました。Playwright 経由で実際のブラウザを使ってテストを走らせる機能です。
この記事では、Vitest 4 のブラウザモードを、設定方法・移行のポイント・新しいアサーションとともに整理します。テスト環境構築の総論は Vitest × Playwright でのテスト環境記事を、Playwright の普段使いは Playwright CLI で普段の Chrome に attach する記事も合わせてどうぞ。
ブラウザモードとは何か
ブラウザモードは、Vitest のテストをNode.js ではなく本物のブラウザの中で実行する仕組みです。window や document といったブラウザのグローバルに、擬似実装ではなく実物としてアクセスできます。
| 方式 | DOM の正体 | 長所 | 短所 |
|---|---|---|---|
| jsdom / happy-dom | JS による擬似実装 | 軽い・速い・設定が楽 | 実ブラウザとの挙動差。一部API未実装 |
| ブラウザモード | 実ブラウザ(Playwright 等) | 実環境に忠実。レイアウト・可視性も測れる | 起動コストがやや高い |
「擬似DOMで十分なテスト」と「実ブラウザでしか正確に測れないテスト」は別物です。要素の可視性、スクロール、実際のCSS適用、IntersectionObserver の挙動などは、擬似DOMだと再現しきれません。ブラウザモードはここを埋めます。
プロバイダは3種類
ブラウザモードは、実ブラウザを操作する「プロバイダ」を選べます。
| プロバイダ | 対応ブラウザ | 備考 |
|---|---|---|
| Playwright | Chromium / Firefox / WebKit | 並列実行に対応。CI で推奨 |
| WebdriverIO | Chrome / Firefox / Edge / Safari | WebDriver ベース |
| Preview | (開発用の軽量オプション) | 手元の確認用。CI には Playwright/WebdriverIO 推奨 |
すでに E2E で Playwright を使っているプロジェクトなら、プロバイダも Playwright で揃えるのが自然です。
設定方法
最小構成はこうです。vitest.config.ts の test.browser を設定します。
import { defineConfig } from 'vitest/config'
import { playwright } from '@vitest/browser-playwright'
export default defineConfig({
test: {
browser: {
enabled: true,
provider: playwright(),
instances: [
{ browser: 'chromium' },
],
},
},
})IMPORTANT
Vitest 4 では、プロバイダが別パッケージに分離されました。Playwright を使うなら @vitest/browser-playwright を追加でインストールします(WebdriverIO は @vitest/browser-webdriverio、Preview は @vitest/browser-preview)。また、ブラウザ用ユーティリティの import 元は、旧来の @vitest/browser/context ではなく vitest/browser に変わりました。3系から上げる場合はここでつまずきやすい点です。
instances に複数のブラウザを並べれば、Chromium・Firefox・WebKit を横断してテストできます。
instances: [
{ browser: 'chromium' },
{ browser: 'firefox' },
{ browser: 'webkit' },
]Vitest 4 のブラウザ関連の新機能
ブラウザモードの安定化に加え、Vitest 4 ではブラウザテストが一段強化されました。
toMatchScreenshot: ビジュアルリグレッションテスト
スクリーンショット比較が組み込みになりました。toMatchScreenshot で、意図しない見た目の変化を検知できます。
import { page } from 'vitest/browser'
import { expect, test } from 'vitest'
test('ボタンの見た目が変わっていない', async () => {
// ... コンポーネントを描画 ...
await expect(page.getByRole('button')).toMatchScreenshot()
})これまで visual regression は専用ツールや Playwright 側で行うことが多かったのですが、コンポーネントテストの流れの中で書けるようになりました。
toBeInViewport: 可視性の判定
toBeInViewport マッチャは、IntersectionObserver API を使って要素がビューポート内に見えているかを判定します。「擬似DOMでは正確に測れない可視性」を、実ブラウザならではの精度でテストできます。
Playwright トレース対応
--browser.trace フラグや設定で Playwright のトレースを生成でき、テストレポートからトレースのリンクをたどって Playwright Trace Viewer で確認できます。失敗したブラウザテストの原因調査が格段に楽になります。
iframe 対応・ロケータ強化
page.frameLocator で iframe 内の要素を扱えるようになり(Playwright のみ)、すべてのロケータが length プロパティを持つようになって toHaveLength と組み合わせやすくなりました。
jsdom からの移行をどう考えるか
ここで現実的な話をします。本ブログ自身は、現時点で次の構成です。
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./vitest.setup.ts'],
include: ['**/__tests__/**/*.{test,spec}.{ts,tsx}'],
},
})Vitest は 4.0.18、Playwright も導入済みですが、ユニット・コンポーネントテストは今も environment: 'jsdom' で回しています。これは「悪い」わけではありません。全部をブラウザモードにする必要はないからです。
現実的な指針はこうです。
- 純粋なロジック・データ整形のテスト: jsdom すら不要。Node 環境で最速。ブラウザモードにする意味は薄い
- 一般的なコンポーネントの描画・イベント: jsdom で十分なことが多い。軽くて速い
- 可視性・レイアウト・スクロール・実CSS依存・見た目の回帰: ここはブラウザモードの出番。
toBeInViewportやtoMatchScreenshotが効く
つまり「jsdom を全廃」ではなく、擬似DOMでは正確に測れないテストだけブラウザモードに切り出すのが筋の良い使い分けです。Vitest は同一プロジェクト内でワークスペース的に環境を分けられるので、「ロジックは Node、コンポーネントは jsdom、可視性まわりはブラウザ」と段階的に併用できます。
1つの設定ファイルで完結する強み
Vitest のブラウザモードの利点は、既存の Vite/Vitest 設定をそのまま使えることです。vite.config のプラグインやエイリアスがテストにもそのまま効くので、本番ビルドとテストで設定が二重管理になりません。
E2E は引き続き Playwright(playwright test)で、コンポーネント〜ユニットは Vitest(必要な部分だけブラウザモード)で、と役割分担しつつ、Vitest 側はブラウザ実行でも単一設定で完結する——この一貫性が2026年のテスト体験を軽くしています。
まとめ
- Vitest 4(2025年10月22日)でブラウザモードが experimental から安定版に
- ブラウザモードは jsdom/happy-dom の擬似DOMではなく、Playwright 等で実ブラウザを使ってテストする方式
- 設定は
test.browserにenabled/provider/instances。Vitest 4 ではプロバイダが別パッケージ(@vitest/browser-playwright等)に分離、import 元はvitest/browserに変更 - 新機能:
toMatchScreenshot(ビジュアルリグレッション)、toBeInViewport(可視性)、Playwright トレース、frameLocator - 全廃ではなく使い分けが筋: ロジックは Node、一般コンポーネントは jsdom、可視性・レイアウト・見た目はブラウザモード
- 既存の Vite/Vitest 設定をそのまま使えるので、設定の二重管理が起きない
「テストは通るのに実ブラウザだと違う」を減らしたいなら、まずは可視性やレイアウトに絡む一部のテストだけブラウザモードに移してみるのが、コストを抑えた第一歩です。