第21章: Vitest Pool によるエッジ完全互換テスト(実践チュートリアル)
通常、JestやVitestをNode.js環境で動かすと、以下のような「エッジ特有の環境差異」によるトラブルが発生します。
windowや Node.js のfs/Bufferがエッジ本番で使えず落ちる- D1(SQLite)やKVのモックを書くのが大変で、テストが形骸化する
@cloudflare/vitest-pool-workers は、オープンソースの本物エッジランタイム(workerd)内でテストを実行するため、本番と100%同じ挙動でD1やKVのクエリを検証 できます。
本チュートリアルのゴール
@cloudflare/vitest-pool-workersとvitestの導入vitest.config.tsによるWorkers設定の読み込み- D1データベースのマイグレーション自動実行と、Hono APIの統合テスト作成
npx vitest runによる高速テスト実行
Step 1: 必要なパッケージのインストール
npm install --save-dev vitest @cloudflare/vitest-pool-workersStep 2: vitest.config.ts の作成
プロジェクトルートに vitest.config.ts を作成します。
import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config';
export default defineWorkersConfig({ test: { poolOptions: { workers: { // wrangler.jsonc(または wrangler.toml)のパスを指定 wrangler: { configPath: './wrangler.jsonc' }, }, }, },});tsconfig.json にテスト用の型定義を追加します。
{ "compilerOptions": { "types": [ "@cloudflare/workers-types/2023-07-01", "@cloudflare/vitest-pool-workers" ] }}Step 3: テスト対象のAPIコード(src/index.ts)
D1にアクセスするシンプルなHono APIです。
import { Hono } from 'hono';
type Bindings = { DB: D1Database;};
const app = new Hono<{ Bindings: Bindings }>();
// ヘルスチェックapp.get('/api/health', (c) => { return c.json({ status: 'ok' });});
// ユーザー作成(D1 INSERT)app.post('/api/users', async (c) => { const { name, email } = await c.req.json<{ name: string; email: string }>();
if (!name || !email) { return c.json({ error: 'Name and email are required' }, 400); }
const user = await c.env.DB.prepare( 'INSERT INTO users (name, email) VALUES (?, ?) RETURNING *' ) .bind(name, email) .first();
return c.json(user, 201);});
export default app;Step 4: 統合テストコードの作成(test/index.spec.ts)
cloudflare:test から env を直接インポートし、テスト用エッジランタイム内で実際のSQLを実行して検証します。
import { env, createExecutionContext, waitOnExecutionContext } from 'cloudflare:test';import { describe, it, expect, beforeAll } from 'vitest';import worker from '../src/index';
describe('エッジ統合テスト (workerd ランタイム)', () => { // テスト開始前にD1のテーブルを初期化 beforeAll(async () => { await env.DB.exec(` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL UNIQUE ); `); });
it('GET /api/health が 200 OK を返すこと', async () => { const request = new Request('http://localhost/api/health'); const ctx = createExecutionContext(); const response = await worker.fetch(request, env, ctx); await waitOnExecutionContext(ctx);
expect(response.status).toBe(200); const body: any = await response.json(); expect(body.status).toBe('ok'); });
it('POST /api/users でD1に実データが保存されること', async () => { const request = new Request('http://localhost/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: '山田太郎', email: 'yamada@example.com' }), });
const ctx = createExecutionContext(); const response = await worker.fetch(request, env, ctx); await waitOnExecutionContext(ctx);
expect(response.status).toBe(201); const createdUser: any = await response.json(); expect(createdUser.name).toBe('山田太郎');
// D1データベースから直接SELECTして書き込みを二重検証! const dbRecord = await env.DB.prepare('SELECT * FROM users WHERE email = ?') .bind('yamada@example.com') .first();
expect(dbRecord).toBeDefined(); expect(dbRecord?.name).toBe('山田太郎'); });
it('バリデーションエラー時に 400 を返すこと', async () => { const request = new Request('http://localhost/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: '' }), });
const ctx = createExecutionContext(); const response = await worker.fetch(request, env, ctx); await waitOnExecutionContext(ctx);
expect(response.status).toBe(400); });});Step 5: テストの実行
npx vitest run出力例:
✓ test/index.spec.ts (3 tests) 24ms ✓ エッジ統合テスト (workerd ランタイム) > GET /api/health が 200 OK を返すこと ✓ エッジ統合テスト (workerd ランタイム) > POST /api/users でD1に実データが保存されること ✓ エッジ統合テスト (workerd ランタイム) > バリデーションエラー時に 400 を返すこと
Test Files 1 passed (1) Tests 3 passed (3) Duration 185msわずか0.2秒以下で、本物エッジDBに対する統合テストが完了します。
まとめ
- モック不要: D1やKVを複雑にモックすることなく、
env.DBに対して本番同様にクエリ可能。 - CI/CD自動化: GitHub Actions に組み込むことで、バグを100%事前に検知可能。
💡 用語解説コラム
[!NOTE] workerd (ワーカーディー)
Cloudflare WorkersのコアとなっているオープンソースのJavaScript/Wasmランタイム。Node.jsではなくこの本物ランタイム上でテストを動かすことで環境差異のバグを根絶します。