Skip to content

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

既知の問題

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

Workers Vitest プラグインには、次の既知の問題があります。

カバレッジ

V8 によるネイティブコードカバレッジはサポートされていません。Istanbul によるインストルメント済みコードカバレッジを使う必要があります。セットアップ手順は Vitest Coverage ドキュメント を参照してください。

フェイクタイマー

Vitest の フェイクタイマー は、KV、R2、キャッシュシミュレーターには適用されません。たとえば、フェイク時刻を進めて KV キーを期限切れにはできません。

exports と Durable Objects を使う動的 import()

exports.default.fetch() で結合テストを書くときの export default { ... } ハンドラー内、または Durable Object のイベントハンドラー内では、動的 import() 文は動きません。ハンドラーを直接 import して呼ぶか、グローバルスコープで静的 import 文を使ってください。

WebSockets

Durable Objects での WebSockets は、ファイル単位のストレージ分離ではサポートされません。回避策として、--max-workers=1 --no-isolate で共有ストレージを使ってテストを実行します。

ストレージ分離

ストレージ分離はテストファイル単位です。テストランナーは、各テストファイルの終了時にストレージへの書き込みを元に戻します。詳細は 分離と並行性のドキュメント を参照してください。よくある問題を避けるため、Cloudflare は次を推奨します。

すべてのストレージ操作を await する

ストレージサービスへ読み書きするすべての Promise を、必ず await してください。

// Example: Seed data
beforeAll(async () => {
	await env.KV.put("message", "test message");
	await env.R2.put("file", "hello-world");
});

リソース破棄を明示する

Service Worker または Durable Object の RPC メソッドを呼び、プリミティブ以外の値(オブジェクトや RpcTarget を拡張するクラスなど)を返す場合は、using キーワードでリソースを破棄できるタイミングを明示してください。このテスト例 と、詳細は explicit-resource-management を参照してください。

using result = await stub.getCounter();

レスポンス本文を消費する

fetch または R2.get() でリクエストするときは、内容をアサートしない場合でも、レスポンス本文全体を消費してください。例:

test("check if file exists", async () => {
	await env.R2.put("file", "hello-world");
	const response = await env.R2.get("file");

	expect(response).not.toBe(null);
	// Consume the response body even if you are not asserting it
	await response.text();
});

ctx.exports の欠落プロパティ

ctx.exports プロパティは、メイン Worker のエクスポートへアクセスします。Workers Vitest 連携は、esbuild で Worker ソースコードを静的解析し、これらのエクスポートを自動推定しようとします。ただし、仮想モジュールや、esbuild がたどれないワイルドカード再エクスポートなど、複雑なビルド構成では、ctx.exports オブジェクトのプロパティが欠けることがあります。

たとえば、ワイルドカードエクスポートで仮想モジュールからエントリポイントを再エクスポートする Worker を考えます。

// index.ts
export * from "@virtual-module";

この場合、@virtual-module からのエクスポート(MyEntrypoint など)は自動推定できず、ctx.exports から欠けます。

回避策として、Vitest 設定に additionalExports オプションを追加します。

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

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

additionalExports オプションは、キーがエクスポート名、値がエクスポートの種類("WorkerEntrypoint""DurableObject""WorkflowEntrypoint")のマップです。

モジュール解決

Error: Cannot use require() to import an ES ModuleError: No such module などのモジュール解決の問題が起きた場合は、deps.optimizer オプションでこれらの依存関係をバンドルできます。

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

export default defineConfig({
	plugins: [
		cloudflareTest({
			// ...
		}),
	],
	test: {
		deps: {
			optimizer: {
				ssr: {
					enabled: true,
					include: ["your-package-name"],
				},
			},
		},
	},
});

例は Recipes ページにあります。

グローバルセットアップファイルからのモジュール import

Vitest は workerd ランタイム向けにパッケージを解決するよう設定されていますが、グローバルセットアップファイルは Node.js 環境で実行します。そのため、Postgres.js のように workerd 向けに非 Node 版をエクスポートするパッケージを import すると問題が起きることがあります。 回避策として、Vite の SSR モジュールローダーを使い、正しい条件でグローバルセットアップファイルを import するラッパーを作れます。そのあと、Vitest 設定をこのラッパーを指すように変更します。例:

// File: global-setup-wrapper.ts
import { createServer } from "vite";

// Import the actual global setup file with the correct setup
const mod = await viteImport("./global-setup.ts");

export default mod.default;

// Helper to import the file with default node setup
async function viteImport(file: string) {
	const server = await createServer({
		root: import.meta.dirname,
		configFile: false,
		server: { middlewareMode: true, hmr: false, watch: null, ws: false },
		optimizeDeps: { noDiscovery: true },
		clearScreen: false,
	});
	const mod = await server.ssrLoadModule(file);
	await server.close();
	return mod;
}
// File: vitest.config.ts
import { cloudflareTest } from "@cloudflare/vitest-plugin";
import { defineConfig } from "vitest/config";

export default defineConfig({
	plugins: [
		cloudflareTest({
			// ...
		}),
	],
	test: {
		// Replace the globalSetup with the wrapper file
		globalSetup: ["./global-setup-wrapper.ts"],
	},
});

役に立ちましたか?