Testing
Write unit and end-to-end tests for your app, run them against a live preview deploy, and (optionally) block merges to main until they pass. Tests run inside your deployed Worker with the same env bindings as your routes.
Write tests in api/test.js
api/test.js is a special file (not an HTTP route). Export a tests object mapping a test name to a function. Each function receives { fetch, assert, env } and fails by throwing (or by a failed assert):
// api/test.js
import { total } from "./cart.js"; // your own code, for unit tests
export const tests = {
// Unit test — call your app's functions directly.
"total() sums line items": ({ assert }) => {
assert(total([{ price: 200, qty: 2 }, { price: 50, qty: 1 }]) === 450);
},
// E2E test — hit your real routes over HTTP on the preview deploy.
"home page loads": async ({ fetch, assert }) => {
const res = await fetch("/");
assert(res.status === 200, `expected 200, got ${res.status}`);
},
"api/echo round-trips JSON": async ({ fetch, assert }) => {
const res = await fetch("/api/echo", {
method: "POST",
body: JSON.stringify({ hi: 1 }),
});
const json = await res.json();
assert(json.hi === 1, "echo mismatch");
},
};- Unit tests import and call your own modules directly — fast, no network.
- E2E tests use
fetch(path)to make real HTTP requests to your app’s own routes on the running preview. assert(condition, message?)throws when the condition is falsy; any thrown error marks the test failed and records its message.- Tests run with your app’s
env(e.g.env.DB,env.STORAGE) — on a preview deploy these point at the isolated preview database and bucket, never production data.
Run them
Tests run against a branch’s preview deploy, so deploy the branch first, then run:
- Deploy the branch to a preview (
deploy_app). - Run
run_tests(MCP) or the Run tests button on the app’s dashboard page. It returns{ status, total, passed, failed, results }.
The run is recorded against the exact commit that was on the preview, so a green result only counts for that commit — commit again and you re-run.
The merge-to-main gate
If your app has an api/test.js, a pull request into main will only merge when the source branch’s latest commit has a passing test run. So the loop is:
edit → deploy_app (preview) → run_tests (until green) → merge_pull_requestmerge_pull_request(force: true) — use it only when you knowingly accept failing or absent tests. Apps with no api/test.js merge exactly as before; testing is opt-in per app.Notes
- Test source in
api/test.jsis never served publicly — likeapi/cron.js, it’s a reserved module, not a route. - Testing is available on every plan, including Free. See Branches, PRs & AI merges for the surrounding workflow.