1import { Query } from "@distilled.cloud/core/query";
2import { Railway as RailwayApi } from "@distilled.cloud/railway";
3import * as Railway from "@/Railway";
4import { suitePartition } from "../suiteProject.ts";
5import * as Test from "@/Test/Alchemy";
6import { expect } from "alchemy-test";
7import * as Effect from "effect/Effect";
8import { MinimumLogLevel } from "effect/References";
9import * as Schedule from "effect/Schedule";
10import * as pathe from "pathe";
11import { cloneFixture } from "../../Cloudflare/Utils/Fixture.ts";
12import { expectUrlContains } from "../../Cloudflare/Utils/Http.ts";
13
14const { test } = Test.make({ providers: Railway.providers() });
15
16const logLevel = Effect.provideService(
17 MinimumLogLevel,
18 process.env.DEBUG ? "Debug" : "Info",
19);
20
21const fixtureDir = pathe.resolve(
22 import.meta.dirname,
23 "../../AWS/Website/fixtures/solidstart-app",
24);
25const tempRoot = pathe.resolve(import.meta.dirname, "../../../.tmp");
26const fixtureEntries = [
27 ".gitignore",
28 "package.json",
29 "vite.config.ts",
30 "src",
31 "public",
32];
33
34const readService = Query.fn((id: string) => ({
35 deletedAt: RailwayApi.service({ id }).deletedAt,
36}));
37
38const waitUntilGone = (serviceId: string) =>
39 readService(serviceId).pipe(
40 Effect.map((service) =>
41 service.deletedAt != null ? ("gone" as const) : ("found" as const),
42 ),
43 Effect.catchTag("RailwayNotFound", () => Effect.succeed("gone" as const)),
44 Effect.repeat({
45 schedule: Schedule.spaced("1 second"),
46 until: (status) => status === "gone",
47 times: 10,
48 }),
49 );
50
51test.provider(
52 "SolidStart: deploy, GET /, destroy, gone",
53 (stack) =>
54 Effect.gen(function* () {
55 yield* stack.destroy();
56
57 const rootDir = yield* cloneFixture(fixtureDir, {
58 prefix: "alchemy-solidstart-railway-",
59 tempRoot,
60 entries: fixtureEntries,
61 });
62
63 const deployed = yield* stack.deploy(
64 Effect.gen(function* () {
65 const { project, environment } = yield* suitePartition;
66 const site = yield* Railway.Website.SolidStart("Web", {
67 project,
68 environment,
69 rootDir,
70 memo: {
71 include: [
72 "src/**",
73 "public/**",
74 "package.json",
75 "vite.config.ts",
76 ],
77 },
78 });
79 return { site };
80 }),
81 );
82
83 const url = deployed.site.url;
84 expect(url).toBeDefined();
85 expect(url).toMatch(/^https:\/\//);
86 expect(deployed.site.service).toBeDefined();
87 expect(deployed.site.project).toBeDefined();
88
89 yield* expectUrlContains(`${url!}/health`, "ok", {
90 timeout: "60 seconds",
91 label: "health",
92 });
93 yield* expectUrlContains(`${url!}/`, "SOLIDSTART_AWS_PAGE_MARKER", {
94 timeout: "180 seconds",
95 label: "home page",
96 });
97 yield* expectUrlContains(
98 `${url!}/api/hello?echo=roundtrip`,
99 "SOLIDSTART_AWS_API_MARKER",
100 {
101 timeout: "30 seconds",
102 label: "api route",
103 },
104 );
105
106 const serviceId = deployed.site.service!.serviceId;
107 yield* stack.destroy();
108 const gone = yield* waitUntilGone(serviceId);
109 expect(gone).toEqual("gone");
110 }).pipe(logLevel),
111 {
112 tags: [
113 "provider:railway",
114 "provider:railway:project",
115 "provider:railway:projectenvironment",
116 "provider:railway:service",
117 "provider:railway:website",
118 "live",
119 ],
120 timeout: 120_000,
121 },
122);