1import * as machines from "@distilled.cloud/fly-io/machines";
2import * as Fly from "@/Fly";
3import * as Test from "@/Test/Alchemy";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { MinimumLogLevel } from "effect/References";
7import * as Schedule from "effect/Schedule";
8import * as pathe from "pathe";
9import { cloneFixture } from "../../Cloudflare/Utils/Fixture.ts";
10import { expectUrlContains } from "../../Cloudflare/Utils/Http.ts";
11
12const { test } = Test.make({ providers: Fly.providers() });
13
14const logLevel = Effect.provideService(
15 MinimumLogLevel,
16 process.env.DEBUG ? "Debug" : "Info",
17);
18
19const fixtureDir = pathe.resolve(
20 import.meta.dirname,
21 "../../AWS/Website/fixtures/react-router-app",
22);
23const tempRoot = pathe.resolve(import.meta.dirname, "../../../.tmp");
24const fixtureEntries = [
25 ".gitignore",
26 "package.json",
27 "react-router.config.ts",
28 "vite.config.ts",
29 "app",
30 "public",
31];
32
33const waitUntilGone = (appName: string) =>
34 machines.getApp({ app_name: appName }).pipe(
35 Effect.as("found" as const),
36 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
37 Effect.repeat({
38 schedule: Schedule.spaced("1 second"),
39 until: (status) => status === "gone",
40 times: 10,
41 }),
42 );
43
44test.provider(
45 "ReactRouter: deploy, GET /, destroy, gone",
46 (stack) =>
47 Effect.gen(function* () {
48 yield* stack.destroy();
49
50 const rootDir = yield* cloneFixture(fixtureDir, {
51 prefix: "alchemy-react-router-fly-",
52 tempRoot,
53 entries: fixtureEntries,
54 });
55
56 const deployed = yield* stack.deploy(
57 Effect.gen(function* () {
58 const site = yield* Fly.Website.ReactRouter("Web", {
59 rootDir,
60 memo: {
61 include: [
62 "app/**",
63 "public/**",
64 "package.json",
65 "react-router.config.ts",
66 "vite.config.ts",
67 ],
68 },
69 });
70 return { site };
71 }),
72 );
73
74 const url = deployed.site.url;
75 expect(url).toBeDefined();
76 expect(url).toMatch(/^https:\/\//);
77 expect(deployed.site.service).toBeDefined();
78 expect(deployed.site.app).toBeDefined();
79
80 yield* expectUrlContains(`${url!}/`, "REACT_ROUTER_AWS_PAGE_MARKER", {
81 timeout: "90 seconds",
82 label: "home page",
83 });
84 yield* expectUrlContains(
85 `${url!}/api/hello?echo=roundtrip`,
86 "REACT_ROUTER_AWS_API_MARKER",
87 {
88 timeout: "30 seconds",
89 label: "api route",
90 },
91 );
92
93 const appName = deployed.site.app!.appName;
94 yield* stack.destroy();
95 const gone = yield* waitUntilGone(appName);
96 expect(gone).toEqual("gone");
97 }).pipe(logLevel),
98 {
99 tags: [
100 "provider:fly",
101 "provider:fly:machine",
102 "provider:fly:website",
103 "live",
104 ],
105 timeout: 180000,
106 },
107);