Testing Locally
Plugin testing does not require a running VeloCMS instance. The @velocms/plugin-sdk/test-helpers package exports a mockVelocms factory that returns an in-memory context object with the same shape as the real PluginContext. You can pre-seed settings, inspect log calls, intercept fetch requests, and simulate KV store operations.
The mockVelocms factory
import { mockVelocms } from "@velocms/plugin-sdk/test-helpers";
const ctx = mockVelocms({
tenant: { id: "t1", slug: "test-blog", locale: "en-US" },
settings: { api_key: "test-key-us1", list_id: "abc123" },
fetchResponse: { ok: true, status: 200, data: { id: "member_id" } },
kvStore: { existing_key: "existing_value" },
});Asserting on log output
ctx.log.info("something happened", { detail: "data" });
// ctx._logs records every log call
assert.equal(ctx._logs.length, 1);
assert.equal(ctx._logs[0]?.level, "info");
assert.equal(ctx._logs[0]?.message, "something happened");Intercepting fetch calls
const ctx = mockVelocms({
fetchResponse: { ok: true, status: 200, data: { success: true } },
});
await myHandler(payload, ctx as never);
// ctx._fetchCalls records every fetch invocation
assert.equal(ctx._fetchCalls.length, 1);
assert.ok(ctx._fetchCalls[0]?.url.includes("api.example.com"));
assert.equal(ctx._fetchCalls[0]?.options?.method, "POST");Testing handler return values
For hooks like beforePostPublish where the return value modifies the publish action, assert that your handler mutates the payload correctly:
import { beforePostPublish } from "../src/index.js";
test("adds auto-tags from AI analysis", async () => {
const ctx = mockVelocms({ settings: { openai_key: "sk-test" } });
const payload = { post: { title: "Sourdough baking tips", tags: [], /* ... */ } };
const result = await beforePostPublish(payload as never, ctx as never);
assert.ok(Array.isArray(result.suggestedTags));
assert.ok(result.suggestedTags!.length > 0);
});Running tests
# Using velocms CLI (recommended)
velocms test
# Or directly with Vitest
npx vitest run
# Watch mode during development
velocms test --watchIntegration testing against a local VeloCMS
Unit tests cover the handler logic in isolation. For end-to-end testing — verifying that the hook actually fires when a post is published on a real tenant — you need a local VeloCMS dev server. Set VELOCMS_DEV_URL=http://localhost:3000 and run velocms dev from your plugin directory. VeloCMS hot-reloads your built dist/ on each compile cycle.