1import * as Alchemy from "alchemy";
2import * as Prisma from "alchemy/Prisma";
3import * as Test from "alchemy/Test/Bun";
4import { expect } from "bun:test";
5import * as Console from "effect/Console";
6import * as Effect from "effect/Effect";
7import * as HttpClient from "effect/http/HttpClient";
8import Stack from "../alchemy.run.ts";
9
10const { test, beforeAll, afterAll, deploy, destroy } = Test.make({
11 providers: Prisma.providers(),
12 state: Alchemy.localState(),
13 profile: process.env.ALCHEMY_PROFILE,
14});
15
16// Pre-deploy cleanup must not close the suite's shared runtime scope.
17const stack = beforeAll(
18 Effect.sync(Test.defaultStage).pipe(
19 Effect.flatMap((stage) => Alchemy.destroy({ stack: Stack, stage })),
20 Effect.andThen(deploy(Stack)),
21 Effect.tap(Console.log),
22 ),
23 {
24 timeout: 120_000,
25 },
26);
27afterAll.skipIf(!!process.env.NO_DESTROY)(destroy(Stack), { timeout: 120_000 });
28
29const base = Effect.map(stack, ({ url }) => {
30 if (!url) throw new Error("Expected a deployed website URL");
31 return String(url).replace(/\/+$/, "");
32});
33
34test(
35 "serves the rendered home page",
36 Effect.gen(function* () {
37 const url = yield* base;
38 const response = yield* Test.getWhenReady(url);
39 expect(response.status).toBe(200);
40 expect(yield* response.text).toContain("Hello from vinext on Prisma!");
41 }),
42 { timeout: 120_000 },
43);
44
45test(
46 "serves a static asset without falling back to HTML",
47 Effect.gen(function* () {
48 const url = yield* base;
49 const response = yield* Test.getWhenReady(`${url}/example.json`);
50 expect(response.status).toBe(200);
51 expect(yield* response.json).toEqual({
52 framework: "vinext",
53 greeting: "Hello from vinext on Prisma!",
54 });
55 }),
56 { timeout: 120_000 },
57);
58
59test(
60 "serves the ISR route and reports missing routes as 404",
61 Effect.gen(function* () {
62 const url = yield* base;
63 const isr = yield* Test.getWhenReady(`${url}/isr`);
64 expect(isr.status).toBe(200);
65 expect(yield* isr.text).toContain("revalidate 60s");
66 const missing = yield* HttpClient.get(`${url}/missing-route`);
67 expect(missing.status).toBe(404);
68 }),
69 { timeout: 120_000 },
70);
71
72test(
73 "serves a request-dependent endpoint with runtime environment",
74 Effect.gen(function* () {
75 const url = yield* base;
76 for (const name of ["Prisma", "Alchemy"]) {
77 const response = yield* Test.getWhenReady(
78 `${url}/api/hello?name=${name}`,
79 );
80 expect(response.status).toBe(200);
81 expect(yield* response.json).toEqual({
82 name,
83 greeting: "Hello from vinext on Prisma!",
84 });
85 }
86 }),
87 { timeout: 120_000 },
88);