Skip to content

Part 5: Testing

test/integ.test.ts
import { expect } from "bun:test";
import * as Boat from "@alchemy.run/boat";
import * as Cloudflare from "@alchemy.run/cloudflare";
import * as Test from "@alchemy.run/test/Bun";
import * as Alchemy from "alchemy";
import * as Effect from "effect/Effect";
import * as HttpClientRequest from "effect/http/HttpClientRequest";
import * as Layer from "effect/Layer";
import Stack from "../alchemy.run.ts";
const { test, beforeAll, afterAll, deploy, destroy } = Test.make({
providers: Layer.mergeAll(Cloudflare.providers(), Boat.providers()),
state: Alchemy.localState(),
});
const stack = beforeAll(deploy(Stack));
afterAll.skipIf(!!process.env.NO_DESTROY)(destroy(Stack));

The test deploys the Stack to a stage of its own, snapshot included, and destroys it afterwards.

test/integ.test.ts
test(
"starts each sandbox from the Golden snapshot",
Effect.gen(function* () {
const { url } = yield* stack;
const res = yield* Test.executeWhenReady(
HttpClientRequest.post(`${url}/run`).pipe(HttpClientRequest.bodyText("pnpm --version")),
);
const body = (yield* res.json) as { exitCode: number };
expect(body.exitCode).toBe(0);
}),
{ timeout: 180_000 },
);

pnpm is only there if the sandbox started from Golden. The Worker deletes the sandbox when the request ends, so none is left behind.

Terminal window
bun test

Set NO_DESTROY=1 to keep the deployment, and the snapshot, between runs while you iterate. Each run starts sandboxes, which count against your plan’s starts per minute and per hour.

Part 6 deploys more copies, from CI.