このガイドでは、Miniflare を設定して Worker をテストする方法を説明します。Miniflare は低レベル API で、Worker の実行とテスト方法を細かく制御できます。
Miniflare を使うには、Miniflare v3 の最新版をインストールしてください。
npm i -D miniflare@latestyarn add -D miniflare@latestpnpm add -D miniflare@latestbun add -d miniflare@latest以降の説明では node:test ↗ テストフレームワークを使いますが、任意のテストフレームワークを使えます。
Miniflare は低レベル API で、Worker 実行用の設定オプションが多数あります。テストで使うのは一部だけで十分な場合がほとんどです。Miniflare でできることの全体は API リファレンス を参照してください。
テストを書く前に、Worker を作成します。Miniflare は Cloudflare プラットフォームのプリミティブをエミュレートする低レベル API です。Worker は JavaScript で書くか、テスト環境に 独自のビルドパイプライン を組み込む必要があります。JavaScript のみの Worker の例は次のとおりです。
export default {
async fetch(request) {
return new Response(`Hello World`);
},
};次に、最初のテストファイルを作成します。
import assert from "node:assert";
import test, { after, before, describe } from "node:test";
import { Miniflare } from "miniflare";
describe("worker", () => {
/**
* @type {Miniflare}
*/
let worker;
before(async () => {
worker = new Miniflare({
modules: [
{
type: "ESModule",
path: "src/index.js",
},
],
});
await worker.ready;
});
test("hello world", async () => {
assert.strictEqual(
await (await worker.dispatchFetch("http://example.com")).text(),
"Hello World",
);
});
after(async () => {
await worker.dispose();
});
});上のテストは node --test で実行できます。
テストファイルのハイライト行は、JavaScript Worker を Miniflare で動かす設定です。Miniflare の準備ができたら、各テストは実行中の Worker へリクエストを送り、レスポンスを検証できます。これが Vitest 連携 と比べたときの、Miniflare で Worker をテストする主な制約です。Worker へのアクセスはすべて Miniflare の dispatchFetch() API 経由になり、Worker 内の個別関数を単体テストできません。
テストはどのランタイムで動きますか?
Vitest 連携 を使う場合、テストスイート全体が
workerd ↗ 上で動きます。そのため、個別関数の単体テストが可能です。
一方、別のテストフレームワークで Miniflare 経由でテストする場合、workerd ↗
上で動くのは Worker 自体だけです。テストファイルは Node.js で動きます。そのため、Worker から関数をテストファイルへインポートすると、その関数が workerd 固有の挙動に依存している場合、実行時と異なる動きをすることがあります。
Miniflare の dispatchFetch() API では、Worker へリクエストを送り、正しいレスポンスが返ることを検証できます。一方、テストからバインディングを直接操作したい場合もあります。そのような用途には、Miniflare の getBindings() API があります。たとえば、テストで環境変数にアクセスするには、テストファイル src/index.test.js を次のように変更します。
...
describe("worker", () => {
...
before(async () => {
worker = new Miniflare({
...
+ bindings: {
+ FOO: "Hello Bindings",
+ },
});
...
});
test("text binding", async () => {
const bindings = await worker.getBindings();
assert.strictEqual(bindings.FOO, "Hello Bindings");
});
...
});KV や R2 などのローカルリソースも、Worker から使うのと同じ API で操作できます。KV 名前空間を操作する例は次のとおりです。
...
describe("worker", () => {
...
before(async () => {
worker = new Miniflare({
...
+ kvNamespaces: ["KV"],
});
...
});
test("kv binding", async () => {
const bindings = await worker.getBindings();
await bindings.KV.put("key", "value");
assert.strictEqual(await bindings.KV.get("key"), "value");
});
...
});上の例は、単一の JavaScript ファイルからなる簡単な Worker のテスト方法です。実際の Worker は、それより複雑なことがほとんどです。Miniflare は、Worker を構成するすべてのファイルを API で直接渡せます。
new Miniflare({
modules: [
{
type: "ESModule",
path: "src/index.js",
},
{
type: "ESModule",
path: "src/imported.js",
},
],
});Worker が大きくなると、これは煩雑になります。そこで Miniflare は、モジュールグラフをたどって含めるモジュールを自動特定することもできます。
new Miniflare({
scriptPath: "src/index-with-imports.js",
modules: true,
modulesRules: [{ type: "ESModule", include: ["**/*.js"] }],
});実際のケースでは、Worker をプレーンな JavaScript で書くことは少なく、npm パッケージなどの依存をインポートする複数の TypeScript ファイルからなり、ビルドツールでバンドルします。Miniflare で直接テストする場合は、テストの前にこのビルドツールを実行する必要があります。実行方法は使うテストフレームワークによりますが、node:test では setup() フックが一般的です。たとえば Wrangler で Worker をビルドおよびデプロイしている場合は、次のように wrangler build コマンドを spawn できます。
before(() => {
spawnSync("npx wrangler build -c wrangler-build.json", {
shell: true,
stdio: "pipe",
});
});