Use and as the default runtime-shaped test harness
Start tests with so the same config, bindings, routes, and handler surfaces the app uses in real runtime flows are available in Bun tests.
Devflare’s recommended test story is not a pile of hand-built mocks. loads the nearest supported config, wires the local runtime surface, and gives you helpers that feel like the Worker entrypoints the app actually uses.
- Best for
- Runtime-shaped tests that should stay close to the real worker surface
- Default harness
- plus helpers
- Optional extra
- for custom class round-trips across local RPC-style bridge calls, especially Durable Object methods
Let the harness discover the normal worker shape first
When you omit the config path, walks upward from the calling test file and finds the nearest supported config filename. It then autodetects the conventional worker surfaces that belong to that package instead of making you wire each one by hand.
That is the main reason the built-in harness scales: the same config and file conventions keep working as the package gains routes, queues, scheduled handlers, inbound email, or tail handlers.
- Config path autodiscovery starts from the calling test file when you omit the argument.
- Conventional files such as , , , , , and are discovered automatically when present.
- Service bindings and other config-driven runtime surfaces are discovered from the same authored config instead of a separate test-only schema.
- If a local RPC-style bridge call under test later needs custom class round-trips, the harness can also discover automatically.
Know which helpers wait for background work and which do not
These helpers are runtime-shaped and context-accurate for handler logic, but they do not try to recreate every internal Cloudflare dispatch step byte for byte. Their timing rules are documented explicitly instead of being left to guesswork.
| Helper | Current behavior |
|---|---|
| Returns when the handler resolves and does not eagerly wait for all work. | |
| Waits for queued background work before it returns. | |
| Waits for scheduled background work before it returns. | |
| In tests, directly invokes the configured local email handler and waits for its queued work; otherwise it falls back to the local email endpoint. | |
| Works when exists, supports a default or named export, and waits for the handler plus its work before it returns. |
Do not assert the wrong timing contract
If a test depends on side effects being complete, a plain assertion may be too early. Either assert the side effect directly or move that check into a higher-fidelity path.
Tail handlers are testable even before they become a public config lane
Tail support is already a real helper surface in the harness even though it still sits outside the public config keys. When finds , it wires automatically and runs the handler with the same runtime helper access as the other test surfaces.
The handler can export a default function or a named function. The helper accepts either full trace items or smaller option objects through , then waits for the handler and any queued work before it returns.
- Keep as a conventional file for now; there is still no public config key.
- Use when the test only needs a few trace fields, and pass full trace items when the payload details are the point of the assertion.
- Reach for a higher-fidelity integration path when the question is Cloudflare ingress behavior rather than your own log or trace handling logic.
Supported helper, still a special-case surface
Tail support is real in the harness and runtime context model, but it is intentionally not documented like fetch, queue, scheduled, or email config yet because there is still no public key.
A tiny tail handler plus one honest harness test
Start with one small proof test before layering helpers on top
Keep the first test boring
If the harness is working, you should be able to prove one route or handler path quickly before you hide it behind bigger factory helpers or shared test setup.
A minimal runtime-shaped test
Add only when local RPC-style bridge calls in tests must preserve custom classes
Most tests do not need a transport file because strings, numbers, arrays, and plain JSON objects already cross the bridge naturally.
Reach for when a local RPC-style bridge call returns a real class instance and the caller needs that class again instead of a plain object. In practice that is most often a Durable Object method round-trip inside , not an ordinary HTTP response.
- Keep the encoded payload plain and JSON-friendly.
- Use one small transport entry per value type so decode rules stay reviewable.
- Set when you want to disable the convention explicitly for one package.
Know where to go when the harness is only part of the question
Testing
Testing overview
MapUse the overview page when you are not sure whether the next question belongs to starter tests, binding-specific guides, runtime helpers, or CI.
Testing
Binding testing guides
Binding indexJump straight to the binding-specific testing page when KV, D1, R2, Durable Objects, Queues, AI, or another binding needs a more specific test story.
Runtime
Runtime context
Runtime helpersRead this when getter failures, missing context, or proxy behavior are making the test harness harder to trace than it should be.
Ship & operate
Testing & automation
AutomationUse the CI-facing page when the question becomes preview validation, workflow structure, or what should happen in automation instead of local tests.
The harness is the center, not the whole map
is the default test loop, but binding-specific caveats, runtime-context rules, and automation concerns still belong on their own pages.
Previous
Testing overview
Devflare’s testing story is layered: start with one real unit test, use and for the runtime-shaped harness, then jump to binding-specific guides or CI-focused pages only when the question changes.
Next
Binding testing
Every binding overview page already links a hidden testing guide. This page collects those guides in one place so you can jump straight to the right harness, caveats, and escalation path for the binding that changed.