sark

Testing

Two vitest projects, one command, and why the Slack-free path is the real path.

npm run typecheck
npm test
npm run smoke      # verify Box API access and template

Two projects, one vitest run

vitest.workspace.ts defines two projects, so only the tests that need a real runtime pay for one:

ProjectRunsWhere
nodetest/*.test.tsplain node
workerstest/do/**/*.test.tsreal workerd, real Durable Object storage, real alarms

The node include is deliberately non-recursive: test/do/** must not be picked up there.

The workers project loads wrangler.jsonc for its bindings and injects the three secrets (BOX_API_KEY, MCP_TOKEN_SECRET, API_TOKEN) as test values, since real deployments carry them as wrangler secrets rather than in the config file.

Isolated storage is off, on purpose

These sessions schedule real alarms. An alarm firing a moment after the test that armed it would touch storage the per-test teardown had already unwound. Isolation comes from every test addressing a fresh, uniquely-named thread instead.

If you add a Durable Object test, give it a unique thread id. Don't re-enable isolatedStorage.

What the Slack-free path covers

MemoryTransport implements the same Transport interface SlackTransport does, and the Durable Object only ever talks to that interface. So an /api-driven run exercises the same enqueue, box lifecycle, MCP bootstrap, prompt construction, watchdog, and idle-stop code that a Slack mention does. Only the trigger and the output sink differ.

That makes the whole pipeline scriptable with no Slack workspace at all, and it makes npm run drive a real integration test.

What's covered

test/auth.test.tstoken minting, signature verification, expiry, clock skew, constant-time compare
test/mcp.test.tsJSON-RPC handling, batches, notifications, limits, method dispatch
test/prompt.test.tsprompt shape, batched messages, delimiter neutralization, mention stripping
test/slack.test.tsevent interpretation: what's ignored, what runs, thread id derivation
test/api-auth.test.tsthe /api gate: 401 on a bad token, 503 when API_TOKEN is unset, and that neither reaches a handler
test/controls.test.tsemoji and button → action mapping, skin-tone stripping, contextual button sets, confirm dialogs on the destructive controls, effort levels
test/do/session.test.tsthe ThreadSession state machine against real DO storage and alarms

What the tests can't cover

The MCP callback needs the box to reach a publicly-routable PUBLIC_URL. That path only proves itself against a deployed Worker:

npm run drive -- --url https://<your-worker>.workers.dev --thread smoke "say hi"

Locally, the box can't call back, so a local run exercises the watchdog fallback instead, which is itself worth exercising.

Before sending a PR

npm run typecheck
npm test
npm run smoke

On this page