`@cloudflare/vitest-pool-workers` を使用した service binding のテストを考える
Vitest で Cloudflare Workers の test を書くためのツール。
fetchMock や binding, RPC などのテストができる
ここにいろんなサンプルがある
service binding RPC を利用する場合
このサンプルでは wrangler.toml
で自分自身のを service binding で参照している。このやり方はローカルでは通るが Workers の初回デプロイが失敗する。一度 deploy してから wrangler.toml
を変える必要があるのは IaC の役割を持つファイルとして適切ではないので別のやり方を調べることにした。
こういうエラーが出ることから、個人的には自分自身を参照する service binding は利用するべきではないと考える。自己再帰してるインフラは危ないと思うし。
エラー内容
✘ [ERROR] Error on remote worker: APIError: A request to the Cloudflare API (/accounts/XXXXXXX/workers/scripts/worker-name/edge-preview) failed.
at throwFetchError
(/home/user/project/node_modules/wrangler/wrangler-dist/cli.js:155177:18)
at fetchResult
(/home/user/project/node_modules/wrangler/wrangler-dist/cli.js:155090:5)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async createPreviewToken
(/home/user/project/node_modules/wrangler/wrangler-dist/cli.js:203375:29)
at async createWorkerPreview
(/home/user/project/node_modules/wrangler/wrangler-dist/cli.js:203396:17)
at async start
(/home/user/project/node_modules/wrangler/wrangler-dist/cli.js:204118:34)
{
text: 'A request to the Cloudflare API
(/accounts/XXXXXXX/workers/scripts/worker-name/edge-preview)
failed.',
notes: [
{
text: 'workers.api.error.service_binding_error: could not resolve binding "COMMENT_SERVICE":
script "worker-name" not found [code: 10143]'
}
],
location: undefined,
kind: 'error',
code: 10143
}
簡単な Cloudflare Workers RPC を利用するプロジェクトを用意した。
この TestService
は Cloudflare Pages で使われることを想定するため、前述のことから自分自身では binding しない。ただ、定義元であるプロジェクトでテストケースを書きたい。そのやり方を模索する。
import { Hono } from "hono";
import { WorkerEntrypoint } from "cloudfalre:workers";
export clsas TestService extends WorkerEntrypoint {
add(a: number, b: number) {
return a + b;
}
}
const app = new Hono();
export default app;
name = "test-workers"
main = "src/index.ts"
compatibility_date = "2024-05-12"
compatibility_flags = ["nodejs_compat"]
workers_dev = false
binding なしで vitest から env を見てみる。当然何も出てこない。これでは test できっこないので wrangler.toml
に binding を追加してみる。
import { env } from "cloudflare:test";
it("test", () => {
console.log(env)
})
stdout | test/integration.test.ts > test
{}
name = "test-workers"
main = "src/index.ts"
compatibility_date = "2024-05-12"
compatibility_flags = ["nodejs_compat"]
workers_dev = false
でた。wrangler.toml
を見てるのは間違いなく、ここに書く必要がありそう。
しらべたら defineWorkersProject
の miniflare
property にもかけるっぽいけどできれば 設定値は toml に書きたい。(これはどっちがいいかな?)
stdout | test/integration.test.ts > test
{ TEST_SERVICE: Fetcher {} }
name = "test-workers"
main = "src/index.ts"
compatibility_date = "2024-05-12"
compatibility_flags = ["nodejs_compat"]
workers_dev = false
[[services]]
binding = "TEST_SERVICE"
service = "test-workers"
entrypoint = "TestService"
environment = "production"
それなら wrangler.toml
を test 用と分ければいい。
toml ファイルが tsconfig みたいな感じで extend できれば一番いいんだけど、それはないので二重管理をするしかなさそう。miniflare
property をいじる方法も模索していきたいが、そこそこ満足したのでいったんここでやめる。
import { defineWorkersProject } from "@cloudflare/vitest-pool-workers/config";
export default defineWorkersProject({
esbuild: {
// Required for `using` support
target: "ES2022",
},
test: {
globals: true,
poolOptions: {
workers: {
singleWorker: true,
miniflare: {
// Required to use `SELF.scheduled()`. This is an experimental
// compatibility flag, and cannot be enabled in production.
compatibilityFlags: ["service_binding_extra_handlers"],
},
wrangler: {
configPath: "./wrangler.test.toml",
},
},
},
},
});
name = "test-workers"
main = "src/index.ts"
compatibility_date = "2024-05-12"
compatibility_flags = ["nodejs_compat"]
workers_dev = false
[[services]]
binding = "TEST_SERVICE"
service = "test-workers"
entrypoint = "TestService"
environment = "production"
wrangler
property に environment があった。
同一 wrangler に [[env.test.services]] 作ったらいけそう。後で試す。