Skip to main content
@ekanos/sdk/testing gives you the same context production builds get, in memory: same schema validation, same egress allowlist, same secret tier rules, no network.

Create a mock context

Test tools

Test webhooks

invokeWebhook builds the context from the definition — its slug, storage schemas, and egress — so contextOptions cannot override those. It throws if the webhook id is not declared or the payload fails payloadSchema; the handler never runs. Signatures are never verified locally: for a signed webhook, the skip is recorded as one warn line on ctx.logs.

Test schedules

Pass context OR contextOptions, never both — passing both throws a TypeError. invokeSchedule throws if the schedule id is not declared.

Test activation hooks

Throws if onActivate is not declared, or if the handler itself throws. invokeActivate is a bare invoker, not the host — the non-fatal (log-and-continue) handling is applied by whatever calls the hook in production or in the harness, so a test of that behavior should catch the rejection itself.

Common patterns

Test with multiple assertions

Test error handling

Test egress denial

Test storage validation

Record fetch calls

Each call is { url, init?, denied: boolean }, in order, allowed and denied alike.

Record logs

Each log is { level: 'debug' | 'info' | 'warn' | 'error', context, message }.

Testing without the harness

You do not need @ekanos/cli or @ekanos/harness to test handlers, webhooks, schedules, or activation hooks. Everything in this section works with vitest and createMockContext() alone. For widget tests that call useIntegrationFetch(), createMockFetchProvider(handlers) returns a provider component that answers from the same MockFetchHandler fixtures (no egress check). Seeing widgets, tiles, and forms rendered in Ekanos chrome takes the harness.

Next steps