@emdash-cms/plugin-test はサンドボックスプラグインをビルドし、workerd 内でテストを実行します。テストは EmDash のプロダクション Cloudflare サンドボックスラッパーと PluginBridge を使用し、@cloudflare/vitest-plugin が提供するローカル D1 および Worker Loader バインディングを利用します。
emdash-plugin init で作成されたプロジェクトにはこのセットアップが含まれています。既存のプラグインプロジェクトは、テストホストを開発依存関係としてインストールできます:
pnpm add -D @emdash-cms/plugin-test vitest
プロジェクトが依存関係のビルドスクリプトを制限している場合、workerd がプラットフォームバイナリをインストールできるように許可します。生成された pnpm ポリシーにはこのエントリが含まれています:
allowBuilds:
workerd: true
Vitest の設定
プロジェクトの Vitest 設定に EmDash テストプラグインを追加します:
import { emdashPluginTest } from "@emdash-cms/plugin-test/config";
import { defineConfig } from "vitest/config";
export default defineConfig({
plugins: [emdashPluginTest()],
});
emdashPluginTest() は Vitest が開始する前にプラグインビルドを実行します。生成されたランタイムとマニフェストを読み取り、分離された D1 データベースと Worker Loader バインディングを作成し、Cloudflare デプロイメントで使用されるのと同じ PluginBridge をエクスポートします。Vitest 設定がプラグインディレクトリの外にある場合は { dir: "./packages/gallery" } を渡します。
ルートのテスト
各テスト内でホストを作成して破棄します。破棄するとプラグインが停止し、テストバインディングがリセットされます:
import { afterEach, describe, expect, it } from "vitest";
import { createPluginTestHost, type PluginTestHost } from "@emdash-cms/plugin-test";
let host: PluginTestHost | undefined;
afterEach(async () => {
await host?.dispose();
host = undefined;
});
describe("health route", () => {
it("identifies the plugin", async () => {
host = await createPluginTestHost();
await expect(host.invokeRoute("health")).resolves.toEqual({
ok: true,
plugin: "save-log",
});
});
});
invokeRoute() は入力値とオプションのリクエストプロパティを受け付けます。デフォルトのリクエストは空のヘッダーとリクエストメタデータを持つプラグインルートへの POST です。
フックとストレージのテスト
EmDash から受け取るイベント形式でフックを呼び出します。ストレージと KV リーダーはブリッジを通じて書き込まれた状態を検査します:
host = await createPluginTestHost();
await host.invokeHook("content:afterSave", {
collection: "posts",
content: { id: "post-1", title: "First post" },
});
const events = await host.storage("events").list();
expect(events).toHaveLength(1);
expect(events[0]?.data).toMatchObject({
collection: "posts",
contentId: "post-1",
});
ストレージ呼び出しは引き続き emdash-plugin.jsonc で宣言されたコレクションを強制します。コンテンツ、メディア、ユーザー、メール、ネットワーク呼び出しは引き続きプラグインの宣言された機能と許可されたホストを強制します。
コンテンツのシード
サイトコンテンツを読み取るルートまたはフックを呼び出す前に、コレクションを作成してエントリをシードします:
host = await createPluginTestHost();
await host.createCollection({
slug: "posts",
label: "Posts",
fields: [{ slug: "title", label: "Title", type: "string" }],
});
await host.seedContent("posts", [{ title: "First" }, { title: "Second" }]);
await expect(host.invokeRoute("post-count")).resolves.toEqual({ count: 2 });
コレクションとエントリは D1 に対する実際の EmDash スキーマレジストリとコンテンツリポジトリを使用します。
テストの境界
ホストはビルドされたプラグイン、分離境界、リモートプロシージャコールのシリアライゼーション、D1 の動作、機能チェック、フック、ルート、KV、宣言されたストレージをカバーします。EmDash 管理アプリケーションのレンダリングや、Cloudflare デプロイメントの CPU、メモリ、サブリクエスト制限の再現は行いません。ブラウザジャーニーには使い捨ての EmDash サイトを使用し、制限に敏感な動作は Cloudflare のプレビューまたはステージングデプロイメントで確認してください。
Block Kit ハンドラーの場合、プラグインの admin ルートを呼び出し、返されたブロックドキュメントを検証します。レンダリングされたレイアウトとインタラクションを確認するには、Block Playground またはブラウザジャーニーを使用します。