// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 // Read-only browser smoke for a built image or a live deployment. No account is needed. // pnpm exec playwright install chromium // node scripts/verify-shell.mjs https://your-app.example.test import { strict as assert } from "node:assert" import { mkdir, writeFile } from "node:fs/promises" import { join } from "node:path" import { chromium, expect } from "@playwright/test" const base = new URL(process.argv[2] ?? "http://127.0.0.1:3000") assert(["http:", "https:"].includes(base.protocol), "expected an HTTP(S) app URL") // Evidence is opt-in, local and bounded; never collect URLs, headers, cookies or bodies. const evidence = process.env.CONUSAI_BROWSER_EVIDENCE_DIR if (evidence) { process.umask(0o077) await mkdir(evidence, { mode: 0o700 }) } const errors = [] const consoleErrors = [] const network = [] let passed = false const browser = await chromium.launch() try { const context = await browser.newContext({ locale: "en-US" }) const page = await context.newPage() page.setDefaultTimeout(15_000) page.on("pageerror", (error) => errors.push(error.message.slice(0, 300))) page.on("console", (message) => { if (message.type() === "error" && consoleErrors.length < 100) consoleErrors.push(message.text().slice(0, 300)) }) page.on("response", (response) => { if (!evidence || network.length >= 1000) return const url = new URL(response.url()) network.push({ method: response.request().method(), sameOrigin: url.origin === base.origin, route: url.pathname.startsWith("/assets/") ? "asset" : url.pathname === "/" ? "shell" : "other", status: response.status(), }) }) const response = await page.goto(new URL("/", base).href, { waitUntil: "networkidle" }) assert.equal(response?.status(), 200) if (evidence) await page.screenshot({ path: join(evidence, "initial.png"), fullPage: true }) const root = page.locator("html") await page.getByRole("button", { name: "Switch to light theme", exact: true }).click() await expect(root).toHaveClass("light") await page.reload() await expect(root).toHaveClass("light") await page.getByRole("button", { name: "Lietuvių", exact: true }).click() await expect(root).toHaveAttribute("lang", "lt") await expect(page.getByRole("button", { name: "Perjungti į tamsią temą", exact: true })).toBeVisible() await page.reload() await expect(root).toHaveAttribute("lang", "lt") await expect(root).toHaveClass("light") if (evidence) await page.screenshot({ path: join(evidence, "lithuanian-light.png"), fullPage: true }) await page.getByRole("button", { name: "Perjungti į tamsią temą", exact: true }).click() await expect(root).not.toHaveClass("light") await page.getByRole("button", { name: "English", exact: true }).click() await expect(root).toHaveAttribute("lang", "en") await expect(page.getByRole("button", { name: "Switch to light theme", exact: true })).toBeVisible() if (evidence) await page.screenshot({ path: join(evidence, "english-dark.png"), fullPage: true }) assert.deepEqual(errors, [], "browser runtime errors") assert.deepEqual(consoleErrors, [], "browser console errors") passed = true console.log("verify-shell: theme and language switch both ways and persist across reloads") } finally { await browser.close() if (evidence) await writeFile( join(evidence, "result.json"), `${JSON.stringify({ passed, errors, consoleErrors, network }, null, 2)}\n`, { flag: "wx", mode: 0o600, }, ) }