Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SvelteKit Remote Functionsのアプリに、分離した並列E2Eテストを入れてみた

Avatar for Chun Nam Wong Chun Nam Wong
January 16, 2026
110

SvelteKit Remote Functionsのアプリに、分離した並列E2Eテストを入れてみた

Avatar for Chun Nam Wong

Chun Nam Wong

January 16, 2026

Transcript

  1. よくある2つのアプローチ 2) 共有環境のフル E2E メリット 信頼度は最大 テストのコードを独立で管理 デメリット 遅い フレークが多め

    テストが書き込んだ状態が他のテストに影響しやすい 並列化が難しい 途中で落ちると中途半端なデータが残る リトライしても前回の副作用が残って再現性が落ちる
  2. コアアイデア ワーカーごとに Postgres コンテナ 1つ ワーカーごとにアプリ(production build)1つ テスト単位では状態だけリセット ベースライン DB

    スナップショットを1回取る 各テスト後にスナップショットへ復元 Playwright ワーカー単位で環境を分離
  3. コアアイデア Playwright: Global SetupでアプリのDockerイメージをビルドする ↓ 各ワーカー: アプリとPostgresコンテナ起動(ローカルサーバー) → DB最初の準備 →

    DBスナップショット保存 ↓ Worker 0: App + Postgres ─┐ テスト#1を実行 → DBスナップショット復元 Worker 1: App + Postgres ─┼─ テスト#2を実行 → DBスナップショット復元 Worker 2: App + Postgres ─┘ テスト#3を実行 → DBスナップショット復元 ↓ ワーカーごとにローカルサーバーを停止して、コンテナを捨てる
  4. コアアイデア(詳しく) 予めDockerfileを用意 1回だけアプリのDockerfileでDockerイメージをビルド(global setup) ワーカー単位フィクスチャ: Testcontainers: Docker network、アプリとPostgresのコンテナを起動し、お互い接続する schema +

    seedをPostgresのコンテナに入れる ベースライン snapshot をとる DB に接続したアプリコンテナへのURLを取得 テスト単位フィクスチャ: protocol ヘッダ注入(後で説明します) テスト後に snapshot 復元 必要なもの:
  5. 落とし穴:protocol / origin チェック production build が HTTPS 前提で判定(または HTTP

    ヘッダから推論) E2E を plain HTTP で回すと、Remote Functions が origin/protocol チェックで落ちることがある 問題:
  6. 回避策 Playwright 側でリクエストごとに注入: [PROTOCOL_HEADERという環境変数に指定されたヘッダ名]: http https://github.com/sveltejs/kit/issues/14352#issuecomment-3705210391 テスト用の回避策: // .env PROTOCOL_HEADER=REQUEST-PROTOCOL

    // beforeEach や fixture など await page.route(`${appUrl}/**`, async (route) => { const request = route.request(); await route.continue({ headers: { ...request.headers(), 'REQUEST-PROTOCOL': 'http', }, }); });
  7. テストが “きれい” になる 画面操作 アサート だけになる フィクスチャが整うと、テストは: e2e('handles username conflicts',

    async ({ page, base: { appUrl } }) => { await page.goto(`${appUrl}/users/register`); // Try to pick the same username in the seed data await page.getByRole('textbox', { name: 'Username' }).fill('user'); await page.getByRole('textbox', { name: 'Password' }).fill('123456'); await page.getByRole('button', { name: 'Register' }).click(); await expect(page.getByText('Username has been taken.')).toBeVisible(); });
  8. CI(GitHub Actions) ubuntu runner で Docker build 可能 Bun +

    deps + Playwright ブラウザを入れる テスト実行 - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 - run: bun install - run: bunx playwright install --with-deps - run: bun run test
  9. デモアプリ(最小構成) Home: User Count: X を表示 Register: ユーザー登録フォーム E2E 3ケース:

    1. ユーザー数が表示される 2. ユーザー名重複でエラー表示 3. 登録後にユーザー数が増える
  10. トレードオフ & 注意点 モックより重い(Docker + CPU) “モックデータ”がゼロになるわけではない ベースラインの DB seed(最小)

    は必要 ただし API レスポンスのモックは不要 Remote Functions は experimental(仕様変更に備える)