Testar plugins em sandbox

Nesta página

@emdash-cms/plugin-test constrói um plugin em sandbox e executa seus testes dentro do workerd. Os testes usam o wrapper do sandbox de produção Cloudflare do EmDash e PluginBridge, com bindings locais de D1 e Worker Loader fornecidos pelo @cloudflare/vitest-plugin.

Projetos criados com emdash-plugin init incluem essa configuração. Projetos de plugins existentes podem instalar o host de teste como dependência de desenvolvimento:

pnpm add -D @emdash-cms/plugin-test vitest

Se o projeto restringe scripts de build de dependências, permita que o workerd instale seu binário de plataforma. A política pnpm gerada inclui esta entrada:

allowBuilds:
  workerd: true

Configurar o Vitest

Adicione o plugin de teste do EmDash à configuração do Vitest do projeto:

import { emdashPluginTest } from "@emdash-cms/plugin-test/config";
import { defineConfig } from "vitest/config";

export default defineConfig({
	plugins: [emdashPluginTest()],
});

emdashPluginTest() executa o build do plugin antes do Vitest iniciar. Ele lê o runtime e o manifesto gerados, cria um banco de dados D1 isolado e um binding Worker Loader, e exporta o mesmo PluginBridge usado pelos deployments Cloudflare. Passe { dir: "./packages/gallery" } quando a configuração do Vitest estiver fora do diretório do plugin.

Testar uma rota

Crie e destrua um host em cada teste. A destruição para o plugin e reinicia seus bindings de teste:

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() aceita um valor de entrada e propriedades de requisição opcionais. A requisição padrão é um POST para a rota do plugin com cabeçalhos vazios e metadados de requisição.

Testar hooks e armazenamento

Invoque hooks com a forma de evento que eles recebem do EmDash. Os leitores de armazenamento e KV inspecionam o estado escrito através do bridge:

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",
});

As chamadas de armazenamento continuam aplicando as coleções declaradas em emdash-plugin.jsonc. Chamadas de conteúdo, mídia, usuário, e-mail e rede continuam aplicando as capacidades declaradas e os hosts permitidos do plugin.

Semear conteúdo

Crie uma coleção e semeie entradas antes de invocar uma rota ou hook que lê conteúdo do site:

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 });

A coleção e as entradas usam o registro de esquemas real do EmDash e o repositório de conteúdo contra o D1.

Limites dos testes

O host cobre o plugin construído, o limite de isolamento, a serialização de chamadas de procedimento remoto, o comportamento do D1, verificações de capacidades, hooks, rotas, KV e o armazenamento declarado. Ele não renderiza a aplicação de administração do EmDash e não reproduz os limites de CPU, memória e sub-requisições dos deployments Cloudflare. Use um site EmDash descartável para jornadas de navegador e verifique comportamento sensível a limites em um deployment de pré-visualização ou staging do Cloudflare.

Para handlers de Block Kit, invoque a rota admin do plugin e verifique o documento de blocos retornado. Use o Block Playground ou uma jornada de navegador para verificar o layout renderizado e as interações.