SvelteKitにPlaywrightでE2Eテストを導入した話
PlaywrightはE2Eテスト(End-to-End)のツールです。実際のブラウザを動かしてユーザー操作をシミュレートします。Vitestのユニットテストと組み合わせることで、ロジックから画面全体まで幅広くテストできます。
VitestとPlaywrightの違い
Vitest(ユニットテスト)
→ 関数やコンポーネントを単体でテスト
→ ブラウザ不要・高速
→ 例:「formatDate('2026-05-19') が '2026年5月19日' を返すか」
Playwright(E2Eテスト)
→ 実際のブラウザでユーザー操作をシミュレート
→ サーバーも含めた全体の動作をテスト
→ 例:「ログインしてトップページに記事一覧が表示されるか」
| Vitest | Playwright | |
|---|---|---|
| テスト対象 | 関数・コンポーネント単体 | ブラウザ全体の動作 |
| 速度 | 高速 | 比較的遅い |
| 向いているケース | ロジックのテスト | ユーザー操作・画面遷移のテスト |
| DBやサーバー | 不要 | 実際のサーバーが必要 |
① インストール
npm install -D @playwright/test
npx playwright install chromium
chromium だけインストールするとダウンロードが速く済みます。
② playwright.config.ts を作成
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './e2e',
testMatch: '**/*.test.ts',
use: {
baseURL: 'http://localhost:8787', // wrangler dev のポート
},
webServer: {
command: 'npx wrangler dev',
url: 'http://localhost:8787',
reuseExistingServer: true, // 起動済みのサーバーを再利用
},
});
ポイント: wrangler dev のデフォルトポートは 8787 です。reuseExistingServer: true を設定しておくと、別ターミナルで起動済みのサーバーをそのまま使ってくれます。
推奨する実行手順:
# ターミナル1:サーバーを起動
npx wrangler dev
# ターミナル2:テストを実行
npx playwright test
③ テストを書く
// e2e/top.test.ts
import { test, expect } from '@playwright/test';
test('トップページに記事一覧が表示される', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { name: '記事一覧' })).toBeVisible();
const links = page.getByRole('link');
await expect(links.first()).toBeVisible();
});
test('記事をクリックすると詳細ページに遷移する', async ({ page }) => {
await page.goto('/');
await page.getByRole('link').first().click();
await expect(page).toHaveURL(/\/posts\/\d+/);
});
④ よく使う操作
// ページ遷移
await page.goto('/login');
// テキスト入力
await page.getByLabel('メールアドレス').fill('test@example.com');
// ボタンクリック
await page.getByRole('button', { name: 'ログイン' }).click();
// 表示確認
await expect(page.getByText('ようこそ')).toBeVisible();
// URL確認
await expect(page).toHaveURL('/dashboard');
// スクリーンショット(デバッグ用)
await page.screenshot({ path: 'screenshot.png' });
⑤ セレクターの使い分け(getByRole / getByText / getByLabel)
Playwrightには要素を探すセレクターが複数あります。基本は getByRole を優先して使い、それで取れない場合に他を使うのが推奨スタイルです。
getByRole — HTML の役割で探す(最も推奨)
page.getByRole('heading', { name: '記事一覧' }) // <h1>〜<h6>
page.getByRole('button', { name: 'ログイン' }) // <button>
page.getByRole('link', { name: 'トップ' }) // <a>
page.getByRole('textbox', { name: 'メール' }) // <input type="text">
page.getByRole('checkbox') // <input type="checkbox">
HTMLのセマンティクス(意味)で要素を探すため、CSSクラスが変わっても壊れにくいのが強みです。
getByText — 表示テキストで探す
page.getByText('ようこそ')
page.getByText('カウント: 0')
page.getByText(/エラー/) // 正規表現も使える
ボタンや見出し以外のテキストコンテンツを探すときに使います。
getByLabel — フォームのラベルで探す
page.getByLabel('メールアドレス') // <label>と紐づいた<input>を取得
page.getByLabel('パスワード')
<label> と <input> が正しく紐づいているフォームで使います。
<!-- この構造のとき getByLabel('メールアドレス') で input を取得できる -->
<label for="email">メールアドレス</label>
<input id="email" type="email" />
使い分けの基準
| セレクター | 向いているケース |
|---|---|
getByRole |
ボタン・リンク・見出しなど(基本これを使う) |
getByText |
段落・メッセージなどボタン以外のテキスト |
getByLabel |
フォームの入力欄 |
getByPlaceholder |
labelがないinputのplaceholderで探す |
getByTestId |
専用のテスト用属性(data-testid)で探す |
テストの実行コマンド
# テストを実行
npx playwright test
# ブラウザを表示しながら実行(デバッグ用)
npx playwright test --headed
# UIモードで実行(テスト結果を視覚的に確認)
npx playwright test --ui