UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

215 lines (166 loc) 6.52 kB
import { Alepha } from "alepha"; import { $head } from "alepha/react/head"; import { HttpClient, ServerProvider } from "alepha/server"; import { describe, it } from "vitest"; import { ssrManifestAtom } from "../atoms/ssrManifestAtom.ts"; import { $page } from "../index.ts"; describe("ReactServerTemplateProvider", () => { describe("streaming", () => { class App { head = $head({ htmlAttributes: { lang: "en" }, }); home = $page({ path: "/", head: { title: "Test Page", meta: [{ name: "description", content: "Test description" }], }, component: () => "Hello World", }); withLoader = $page({ path: "/with-loader", head: { title: "Loader Page" }, loader: async () => ({ data: "loaded" }), component: ({ data }) => `Data: ${data}`, }); } it("should stream complete HTML document with correct structure", async ({ expect, }) => { const alepha = Alepha.create({ env: { LOG_LEVEL: "error", SERVER_PORT: 0 }, }).with(App); await alepha.start(); const server = alepha.inject(ServerProvider); const http = alepha.inject(HttpClient); const response = await http.fetch(`${server.hostname}/`); // Verify HTML structure expect(response.data).toContain("<!DOCTYPE html>"); expect(response.data).toContain('<html lang="en">'); expect(response.data).toContain("<head>"); expect(response.data).toContain('<meta charset="UTF-8">'); expect(response.data).toContain('<meta name="viewport"'); expect(response.data).toContain("<title>Test Page</title>"); expect(response.data).toContain( '<meta name="description" content="Test description">', ); expect(response.data).toContain("</head>"); expect(response.data).toContain("<body>"); expect(response.data).toContain('<div id="root">'); expect(response.data).toContain("Hello World"); expect(response.data).toContain("</div>"); expect(response.data).toContain("</body>"); expect(response.data).toContain("</html>"); await alepha.stop(); }); it("should include hydration data when enabled", async ({ expect }) => { const alepha = Alepha.create({ env: { LOG_LEVEL: "error", SERVER_PORT: 0 }, }).with(App); await alepha.start(); const server = alepha.inject(ServerProvider); const http = alepha.inject(HttpClient); const response = await http.fetch(`${server.hostname}/with-loader`); // Verify hydration script is present expect(response.data).toContain( '<script id="__ssr" type="application/json">', ); expect(response.data).toContain("</script>"); // Verify hydration data structure expect(response.data).toMatch(/"alepha\.react\.router\.layers"/); await alepha.stop(); }); it("should include entry assets in head when manifest is available", async ({ expect, }) => { const alepha = Alepha.create({ env: { LOG_LEVEL: "error", SERVER_PORT: 0 }, }).with(App); // Set up mock SSR manifest alepha.store.set(ssrManifestAtom, { client: { "src/entry.tsx": { file: "assets/entry.abc123.js", isEntry: true, css: ["assets/style.def456.css"], }, }, }); await alepha.start(); const server = alepha.inject(ServerProvider); const http = alepha.inject(HttpClient); const response = await http.fetch(`${server.hostname}/`); // Verify entry assets are in the head // Note: CSS stylesheets do NOT include crossorigin="" to avoid credential mode mismatches // with Early Hints preloading (HTTP 103). JS modules still need crossorigin="". expect(response.data).toContain( '<link rel="stylesheet" href="/assets/style.def456.css">', ); expect(response.data).toContain( '<script type="module" crossorigin="" src="/assets/entry.abc123.js"></script>', ); await alepha.stop(); }); it("should handle pages with loaders correctly", async ({ expect }) => { const alepha = Alepha.create({ env: { LOG_LEVEL: "error", SERVER_PORT: 0 }, }).with(App); await alepha.start(); const server = alepha.inject(ServerProvider); const http = alepha.inject(HttpClient); const response = await http.fetch(`${server.hostname}/with-loader`); // Verify loader data is rendered expect(response.data).toContain("Data: loaded"); await alepha.stop(); }); it("should set correct content-type header", async ({ expect }) => { const alepha = Alepha.create({ env: { LOG_LEVEL: "error", SERVER_PORT: 0 }, }).with(App); await alepha.start(); const server = alepha.inject(ServerProvider); const http = alepha.inject(HttpClient); const response = await http.fetch(`${server.hostname}/`); expect(response.headers.get("content-type")).toBe("text/html"); await alepha.stop(); }); it("should set cache-control headers for SSR responses", async ({ expect, }) => { const alepha = Alepha.create({ env: { LOG_LEVEL: "error", SERVER_PORT: 0 }, }).with(App); await alepha.start(); const server = alepha.inject(ServerProvider); const http = alepha.inject(HttpClient); const response = await http.fetch(`${server.hostname}/`); expect(response.headers.get("cache-control")).toContain("no-store"); await alepha.stop(); }); }); describe("error handling", () => { class ErrorApp { errorPage = $page({ path: "/error", loader: async () => { throw new Error("Loader error"); }, component: () => "Should not render", }); } it("should render error when loader throws", async ({ expect }) => { const alepha = Alepha.create({ env: { LOG_LEVEL: "error", SERVER_PORT: 0 }, }).with(ErrorApp); await alepha.start(); const server = alepha.inject(ServerProvider); const http = alepha.inject(HttpClient); const response = await http.fetch(`${server.hostname}/error`); // Should still return a valid HTML response with error expect(response.data).toContain("<!DOCTYPE html>"); expect(response.data).toContain("Loader error"); await alepha.stop(); }); }); });