1import * as Hetzner from "@/Hetzner";
2import * as Test from "@/Test/Alchemy";
3import { describe, expect } from "alchemy-test";
4import * as Effect from "effect/Effect";
5import * as pathe from "pathe";
6import { cloneFixture } from "../../Cloudflare/Utils/Fixture.ts";
7import { expectUrlContains } from "../../Cloudflare/Utils/Http.ts";
8
9const { test } = Test.make({ providers: Hetzner.providers(), dev: true });
10
11/**
12 * SolidStart 2's dev SSR does not run under Bun (`srvx/node` writes
13 * `[object Object]`). Body assertions stay gated; identity (localhost,
14 * no cloud rows) is asserted unconditionally. Set
15 * `ALCHEMY_TEST_SOLIDSTART_DEV_SSR=1` to run the body assertions on a
16 * Node-hosted sidecar.
17 */
18const runDevSsr = process.env.ALCHEMY_TEST_SOLIDSTART_DEV_SSR === "1";
19
20const fixtureDir = pathe.resolve(
21 import.meta.dirname,
22 "../../AWS/Website/fixtures/solidstart-app",
23);
24const tempRoot = pathe.resolve(import.meta.dirname, "../../../.tmp");
25const fixtureEntries = [
26 ".gitignore",
27 "package.json",
28 "vite.config.ts",
29 "src",
30 "public",
31];
32
33describe(
34 "Hetzner.Website.SolidStart local",
35 { tags: ["provider:hetzner", "provider:hetzner:website", "local"] },
36 () => {
37 test.provider(
38 "dev runs the framework server with no cloud resources",
39 (stack) =>
40 Effect.gen(function* () {
41 yield* stack.destroy();
42
43 const rootDir = yield* cloneFixture(fixtureDir, {
44 prefix: "alchemy-solidstart-hetzner-local-",
45 tempRoot,
46 entries: fixtureEntries,
47 });
48
49 const deployed = yield* stack.deploy(
50 Effect.gen(function* () {
51 const site = yield* Hetzner.Website.SolidStart("Web", {
52 rootDir,
53 });
54 return { site };
55 }),
56 );
57
58 const url = deployed.site.url;
59 expect(url).toMatch(/^http:\/\/(localhost|127\.0\.0\.1):\d+\/?$/);
60 expect(deployed.site.service).toBeUndefined();
61 expect(deployed.site.server).toBeUndefined();
62
63 yield* stack.destroy();
64 }),
65 { timeout: 120_000 },
66 );
67
68 test.provider.skipIf(!runDevSsr)(
69 "dev serves SSR home and API routes",
70 (stack) =>
71 Effect.gen(function* () {
72 yield* stack.destroy();
73
74 const rootDir = yield* cloneFixture(fixtureDir, {
75 prefix: "alchemy-solidstart-hetzner-local-ssr-",
76 tempRoot,
77 entries: fixtureEntries,
78 });
79
80 const deployed = yield* stack.deploy(
81 Effect.gen(function* () {
82 const site = yield* Hetzner.Website.SolidStart("Web", {
83 rootDir,
84 });
85 return { site };
86 }),
87 );
88
89 const url = deployed.site.url;
90 yield* expectUrlContains(`${url}/`, "SOLIDSTART_AWS_PAGE_MARKER", {
91 timeout: "90 seconds",
92 label: "dev home page",
93 });
94 yield* expectUrlContains(
95 `${url}/api/hello?echo=roundtrip`,
96 "SOLIDSTART_AWS_API_MARKER",
97 { label: "api route (dev)" },
98 );
99 yield* expectUrlContains(
100 `${url}/prerendered`,
101 "SOLIDSTART_AWS_PRERENDERED_MARKER",
102 { label: "extra route (dev)" },
103 );
104
105 yield* stack.destroy();
106 }),
107 { timeout: 120_000 },
108 );
109 },
110);