Testing
Alchemy tests run against real clouds by default — no mocks. A suite deploys a real Stack once, runs assertions against live resources, and tears it back down: deploy → assert → destroy. The same suite can also run entirely on your machine — see Local mode below.
One deploy per suite
Section titled “One deploy per suite”Deploy once in beforeAll, share the outputs handle across every test, destroy in afterAll:
const { test, beforeAll, afterAll, deploy, destroy } = Test.make({ providers: Cloudflare.providers(), state: Cloudflare.state(),});
const stack = beforeAll(deploy(Stack));afterAll(destroy(Stack));
test( "serves the deployed URL", Effect.gen(function* () { const { url } = yield* stack; const res = yield* HttpClient.get(url); expect(res.status).toBe(200); }),);For the full walkthrough, see Testing a Stack.
For every option, hook, and variant, see the Test harness reference.
Pick a runner
Section titled “Pick a runner”Test.make ships in @alchemy.run/test and runs on three test runners with the same API:
pnpm add -D https://pkg.alchemy.run/@alchemy.run/test/pr:2930:a10573ebun add -d https://pkg.alchemy.run/@alchemy.run/test/pr:2930:a10573enpm install -D https://pkg.alchemy.run/@alchemy.run/test/pr:2930:a10573eyarn add -D https://pkg.alchemy.run/@alchemy.run/test/pr:2930:a10573eImport it from the adapter for your runner:
import * as Test from "@alchemy.run/test/Alchemy"; // alchemy-testimport * as Test from "@alchemy.run/test/Bun"; // bun testimport * as Test from "@alchemy.run/test/Vitest"; // Vitestalchemy-test runs every file in one bun process with tests in flight concurrently, built for slow tests against real clouds. Install and run each one as shown in Test harness → Runners.
Stage isolation
Section titled “Stage isolation”Tests default to test_$USER (e.g. test_sam), matching how
alchemy deploy uses live_$USER and alchemy dev uses
dev_$USER — so they never touch your live or local-dev
deployments, and two people running the same suite don’t collide. A
unique stage per PR lets CI suites run in parallel against the same
account:
Test.make({ providers, stage: "ci-pr-42" });Or set it for the whole run from the command line:
pnpm alchemy-test --stage ci-pr-42ALCHEMY_TEST_STAGE=ci-pr-42 bun testbun alchemy-test --stage ci-pr-42ALCHEMY_TEST_STAGE=ci-pr-42 bun testnpx alchemy-test --stage ci-pr-42ALCHEMY_TEST_STAGE=ci-pr-42 bun testyarn alchemy-test --stage ci-pr-42ALCHEMY_TEST_STAGE=ci-pr-42 bun testRunning several git worktrees at once? See Worktrees. The per-call form is covered in Test harness → stage.
Local mode (dev: true)
Section titled “Local mode (dev: true)”The harness has the same local-dev mode as alchemy dev. It’s off by default; flip it on and the whole suite runs against local emulators — Cloudflare Workers, Durable Objects, KV, R2, D1, Queues, and Workflows in workerd, AWS Lambda/ECS and the emulated AWS surface in a local Docker emulator — with no cloud calls:
Test.make({ providers: Cloudflare.providers(), dev: true,});Nothing else changes: deploy(Stack) boots the stack locally and the tests drive http://localhost:<port> instead of the cloud. There’s no need for a separate testing setup (e.g. workerd + a vitest plugin) — the harness runs your real Stack in the same local runtimes alchemy dev uses. Omit the flag and set ALCHEMY_DEV=1 in your shell to keep one test file that runs locally on your laptop and live in CI.
Full option semantics: Test harness → dev.
Where next
Section titled “Where next”- Testing a Stack — deploy a Stack and drive it over HTTP, end to end.
- Testing Providers — exercise a provider’s create/update/replace/delete with
test.provider. - Test harness — every
Test.makeoption, hook, and variant. - Observability — wire exporters, monitors, and alarms into the same Stack.
- Tutorial Part 3 — your first integration test, walked through step by step.
- Tutorial Part 4 — running the same tests against local emulators with
dev: true.