Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

最初のテストを書く

最終更新 Markdown で表示Agent セットアップ

このガイドでは、@cloudflare/vitest-plugin パッケージの始め方を説明します。@cloudflare/vitest-plugin を使ったより複雑なテスト例は、レシピ を参照してください。

前提条件

まず、次を確認してください。

  • 互換性日付2022-10-31 以降であること。

  • Worker が ES modules 形式を使っていること(そうでない場合は、ES modules 形式へ移行する ガイドを参照してください)。

  • プロジェクトに Vitest と @cloudflare/vitest-plugin が開発用依存関係としてインストールされていること

    npm i -D vitest@^4.1.0 @cloudflare/vitest-plugin

Vitest の設定を定義する

vitest.config.ts で、cloudflareTest() プラグインを使い、Workers の Vitest 連携を設定します。

Wrangler 設定ファイル の Worker 設定を使うには、wrangler.configPath で指定します。

import { cloudflareTest } from "@cloudflare/vitest-plugin";
import { defineConfig } from "vitest/config";

export default defineConfig({
	plugins: [
		cloudflareTest({
			wrangler: { configPath: "./wrangler.jsonc" },
		}),
	],
});

miniflare キーで、追加の設定を定義したり、上書きしたりできます。こちらが、Wrangler 設定で指定した値より優先されます。

たとえば、次の設定は、テスト内でのみアクセス・変更される KV 名前空間 TEST_NAMESPACE を追加します。

export default defineConfig({
	plugins: [
		cloudflareTest({
			wrangler: { configPath: "./wrangler.jsonc" },
			miniflare: {
				kvNamespaces: ["TEST_NAMESPACE"],
			},
		}),
	],
});

利用できる Miniflare オプションの一覧は、Miniflare の WorkersOptions API ドキュメント を参照してください。

利用できる設定オプションの一覧は、設定 を参照してください。

型を定義する

TypeScript を使っていない場合は、このセクションを飛ばせます。

まず wrangler types を実行してください。これにより、Cloudflare Workers ランタイム向けの型 と、Worker のバインディングに基づく Env 型が生成されます。

次に、テスト用フォルダーに tsconfig.json を追加し、cloudflare:test の型を定義するために types 配列へ "@cloudflare/vitest-plugin" を追加します。 Cloudflare Workers ランタイムの型を使えるように、wrangler types の出力も include 配列に追加してください。

test/tsconfig.json の例

test/tsconfig.jsonjsonc
{
	"extends": "../tsconfig.json",
	"compilerOptions": {
		"moduleResolution": "bundler",
		"types": [
			"@cloudflare/vitest-plugin/types", // provides `cloudflare:test` and `cloudflare:workers` types
		],
	},
	"include": [
		"./**/*.ts",
		"../src/worker-configuration.d.ts", // output of `wrangler types`
	],
}

テストを書く

次のシンプルな Worker を例にします。/404 パスには 404 レスポンスを返し、それ以外のパスには "Hello World!" を返します。

src/index.jsjs
export default {
	async fetch(request, env, ctx) {
		if (pathname === "/404") {
			return new Response("Not found", { status: 404 });
		}
		return new Response("Hello World!");
	},
};
src/index.tsts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		if (pathname === "/404") {
			return new Response("Not found", { status: 404 });
		}
		return new Response("Hello World!");
	},
} satisfies ExportedHandler<Env>;

ユニットテスト

Worker をインポートすると、その fetch ハンドラーのユニットテストを書けます。

test/unit.spec.jsjs
import { env } from "cloudflare:workers";
import {
	createExecutionContext,
	waitOnExecutionContext,
} from "cloudflare:test";
import { describe, it, expect } from "vitest";
// Import your worker so you can unit test it
import worker from "../src";

// For now, you'll need to do something like this to get a correctly-typed
// `Request` to pass to `worker.fetch()`.
const IncomingRequest = Request;

describe("Hello World worker", () => {
	it("responds with Hello World!", async () => {
		const request = new IncomingRequest("http://example.com/404");
		// Create an empty context to pass to `worker.fetch()`
		const ctx = createExecutionContext();
		const response = await worker.fetch(request, env, ctx);
		// Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions
		await waitOnExecutionContext(ctx);
		expect(response.status).toBe(404);
		expect(await response.text()).toBe("Not found");
	});
});
test/unit.spec.tsts
import { env } from "cloudflare:workers";
import {
	createExecutionContext,
	waitOnExecutionContext,
} from "cloudflare:test";
import { describe, it, expect } from "vitest";
// Import your worker so you can unit test it
import worker from "../src";

// For now, you'll need to do something like this to get a correctly-typed
// `Request` to pass to `worker.fetch()`.
const IncomingRequest = Request<unknown, IncomingRequestCfProperties>;

describe("Hello World worker", () => {
	it("responds with Hello World!", async () => {
		const request = new IncomingRequest("http://example.com/404");
		// Create an empty context to pass to `worker.fetch()`
		const ctx = createExecutionContext();
		const response = await worker.fetch(request, env, ctx);
		// Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions
		await waitOnExecutionContext(ctx);
		expect(response.status).toBe(404);
		expect(await response.text()).toBe("Not found");
	});
});

統合テスト

cloudflare:workers が提供する exports オブジェクトを使い、統合テストを書けます。exports.default.fetch() は、main Worker で定義したデフォルトエクスポートのハンドラーを呼び出します。

test/integration.spec.jsjs
import { exports } from "cloudflare:workers";
import { describe, it, expect } from "vitest";

describe("Hello World worker", () => {
	it("responds with not found and proper status for /404", async () => {
		const response = await exports.default.fetch("http://example.com/404");
		expect(response.status).toBe(404);
		expect(await response.text()).toBe("Not found");
	});
});
test/integration.spec.tsts
import { exports } from "cloudflare:workers";
import { describe, it, expect } from "vitest";

describe("Hello World worker", () => {
	it("responds with not found and proper status for /404", async () => {
		const response = await exports.default.fetch("http://example.com/404");
		expect(response.status).toBe(404);
		expect(await response.text()).toBe("Not found");
	});
});

exports.default.fetch() で統合テストを書く場合、Worker のコードはテストランナーと同じコンテキストで走ります。そのため、グローバルなモックで Worker を制御できます。一方で、Worker は Vite が提供する、微妙に異なるモジュール解決の挙動を使います。 通常は問題になりません。本番にできるだけ近い、新しい環境で Worker を走らせたい場合は、補助 Worker を使えます。補助 Worker を使った統合テストのセットアップは、この例 を参照してください。ただし、補助 Worker には把握しておくべき 制限 があります。

関連リソース

役に立ちましたか?