clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

feat/prf-provision-custody
lofi / package / preact / PwaActions_test.tsx
PwaActions_test.tsx 3.9K
1import { render } from "npm:preact-render-to-string@6.7.0";2import type { PwaController, PwaState } from "../runtime/pwa.ts";3import { PwaActions, pwaFailureMessage } from "./PwaActions.tsx";45function controller(state: PwaState): PwaController {6 return {7 getState: () => state,8 subscribe(subscriber) {9 subscriber(state);10 return () => undefined;11 },12 requestInstall: () => Promise.resolve(state.install),13 checkForUpdate: () => Promise.resolve(false),14 applyUpdate: () => true,15 initialize: () => undefined,16 };17}1819function renderState(state: PwaState): string {20 return render(<PwaActions controller={controller(state)} />);21}2223Deno.test("PwaActions renders a Chromium action only while the prompt is available", () => {24 const available = renderState({ worker: "ready", install: "available", update: "idle" });25 const dismissed = renderState({ worker: "ready", install: "dismissed", update: "idle" });26 if (!available.includes("Install app")) throw new Error("install action was omitted");27 if (dismissed.includes("Install app")) throw new Error("install action outlived its prompt");28 if (!dismissed.includes("Installation dismissed")) {29 throw new Error("dismissed outcome was hidden");30 }31});3233Deno.test("PwaActions renders complete iOS Add to Home Screen guidance", () => {34 const html = renderState({ worker: "ready", install: "manual-ios", update: "idle" });35 for (const step of ["Open the Share menu.", "Choose Add to Home Screen.", "Confirm Add."]) {36 if (!html.includes(step)) throw new Error(`iOS guidance omitted: ${step}`);37 }38 if (/unavailable in (?:the )?EU/i.test(html)) throw new Error("obsolete EU guidance returned");39});4041Deno.test("PwaActions renders truthful generic manual-install guidance", () => {42 const html = renderState({ worker: "ready", install: "manual-browser", update: "idle" });43 if (!html.includes("No in-page install button is available right now")) {44 throw new Error("missing prompt limitation");45 }46 if (!html.includes("if offered")) throw new Error("manual guidance invented availability");47});4849Deno.test("PwaActions renders every active update phase", () => {50 const checking = renderState({ worker: "ready", install: "installed", update: "checking" });51 const installing = renderState({ worker: "ready", install: "installed", update: "installing" });52 const ready = renderState({ worker: "ready", install: "installed", update: "ready" });53 const applying = renderState({ worker: "ready", install: "installed", update: "applying" });54 if (!checking.includes("Checking for updates")) throw new Error("checking state was omitted");55 if (!installing.includes("Installing update")) throw new Error("installing state was omitted");56 if (!ready.includes("Update app")) throw new Error("waiting-worker action was omitted");57 if (!applying.includes("Applying update")) throw new Error("applying state was omitted");58});5960Deno.test("PwaActions distinguishes unsupported installation", () => {61 const html = renderState({ worker: "unsupported", install: "unsupported", update: "idle" });62 if (!html.includes("not supported in this browser or browsing context")) {63 throw new Error("unsupported environment was hidden");64 }65});6667Deno.test("actionable PWA failure messages are fixed, useful, and non-secret", () => {68 for (69 const code of [70 "registration",71 "installation",72 "install-prompt",73 "update-check",74 "precache",75 "runtime-cache",76 ] as const77 ) {78 const message = pwaFailureMessage(code);79 if (!/(Reload|Reconnect|browser menu)/i.test(message)) {80 throw new Error(`${code} lacks an action`);81 }82 const html = renderState({83 worker: "failed",84 install: "unsupported",85 update: code === "update-check" ? "failed" : "idle",86 failure: { code, message: "secret-value-must-not-render" },87 });88 if (!html.includes(message) || html.includes("secret-value")) {89 throw new Error(`${code} failure rendering is not safely actionable`);90 }91 }92});