@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나 브라우저 여정을 사용하세요.