Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

pwa.test.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

pwa.test.tsBlame90 lines · 1 contributor
eae38d1Claude1/**
2 * Block G1 — PWA route smoke tests.
3 *
4 * Verifies manifest/icon/service-worker endpoints serve the right content
5 * types + the manifest parses as JSON with the required install-prompt fields.
6 */
7
8import { describe, it, expect } from "bun:test";
9import app from "../app";
10import { MANIFEST, SERVICE_WORKER_SRC, PWA_REGISTER_SNIPPET } from "../routes/pwa";
11
12describe("pwa — manifest", () => {
13 it("GET /manifest.webmanifest → 200 JSON", async () => {
14 const res = await app.request("/manifest.webmanifest");
15 expect(res.status).toBe(200);
16 const ct = res.headers.get("content-type") || "";
17 expect(ct).toContain("application/manifest+json");
18 const body = await res.json();
19 expect(body.name).toBe("Gluecron");
20 expect(body.start_url).toBe("/");
21 expect(body.display).toBe("standalone");
22 expect(Array.isArray(body.icons)).toBe(true);
23 expect(body.icons.length).toBeGreaterThan(0);
24 });
25
26 it("MANIFEST constant has required install-prompt fields", () => {
27 expect(MANIFEST.name).toBeDefined();
28 expect(MANIFEST.short_name).toBeDefined();
29 expect(MANIFEST.start_url).toBeDefined();
30 expect(MANIFEST.icons.length).toBeGreaterThan(0);
31 expect(MANIFEST.display).toBe("standalone");
32 });
33});
34
35describe("pwa — service worker", () => {
36 it("GET /sw.js → 200 JavaScript", async () => {
37 const res = await app.request("/sw.js");
38 expect(res.status).toBe(200);
39 expect(res.headers.get("content-type") || "").toContain(
40 "application/javascript"
41 );
42 expect(res.headers.get("service-worker-allowed")).toBe("/");
43 });
44
e1c7aa6Claude45 it("v4 self-nuke service worker installs + activates + unregisters", () => {
eae38d1Claude46 expect(SERVICE_WORKER_SRC).toContain("addEventListener('install'");
47 expect(SERVICE_WORKER_SRC).toContain("addEventListener('activate'");
e1c7aa6Claude48 expect(SERVICE_WORKER_SRC).toContain("self.registration.unregister");
49 expect(SERVICE_WORKER_SRC).toContain("caches.delete");
eae38d1Claude50 });
51
e1c7aa6Claude52 it("v4 service worker has no fetch handler — every request hits network", () => {
53 expect(SERVICE_WORKER_SRC).not.toContain("addEventListener('fetch'");
eae38d1Claude54 });
55});
56
57describe("pwa — icon", () => {
58 it("GET /icon.svg → 200 SVG", async () => {
59 const res = await app.request("/icon.svg");
60 expect(res.status).toBe(200);
61 expect(res.headers.get("content-type") || "").toContain("image/svg+xml");
62 const body = await res.text();
63 expect(body).toContain("<svg");
64 expect(body).toContain("</svg>");
65 });
66});
67
68describe("pwa — register snippet", () => {
69 it("registers a service worker when available", () => {
70 expect(PWA_REGISTER_SNIPPET).toContain("serviceWorker");
71 expect(PWA_REGISTER_SNIPPET).toContain("'/sw.js'");
72 });
73});
74
75describe("pwa — layout wiring", () => {
76 it("home page includes the manifest link", async () => {
77 const res = await app.request("/");
78 const body = await res.text();
79 expect(body).toContain('rel="manifest"');
80 expect(body).toContain("/manifest.webmanifest");
81 });
82
83 it("home page registers the service worker", async () => {
84 const res = await app.request("/");
85 const body = await res.text();
86 // JSX entity-escapes quotes inside <script>; just check the SW path is wired.
87 expect(body).toContain("serviceWorker.register");
88 expect(body).toContain("/sw.js");
89 });
90});