// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 // Route reachability and assistive navigation on the actual app, with simulated provider services. import { expect, test } from "@playwright/test" import { moduleSelected, OPTIONAL_MODULE_IDS } from "../modules/inclusion" import { modulePages } from "../modules/pages" import { makeOrganization, signIn, unique, violations } from "./support/app" test("selected module routes, settings links and unknown pages have deliberate accessible outcomes", async ({ page, }, info) => { test.setTimeout(120_000) const errors: string[] = [] let expectedRefusal = false await signIn(page, `${unique("route-review")}@example.test`) const scope = await makeOrganization(page) const base = `/${scope.org}/${scope.workspace}/${scope.project}` await page.goto(`/${scope.org}/settings`) await page.getByRole("button", { name: "Reject analytics and replay", exact: true }).click() // The next hard navigation must not abort the previous document's dynamic bootstrap. await expect(page.locator('[data-guide="frame.person"]')).toBeEnabled() page.on("pageerror", (error) => errors.push(error.message)) page.on("console", (message) => { if (!expectedRefusal && ["warning", "error"].includes(message.type())) errors.push(message.text()) }) const settings = await page .locator('[data-slot="settings-layout"] a[href]') .evaluateAll((nodes) => nodes.map((node) => node.getAttribute("href") ?? "")) const routes = [ ...new Set([ `/${scope.org}`, `/${scope.org}/${scope.workspace}`, base, `/${scope.org}/${scope.workspace}/modules/notes`, ...settings, ...Object.keys(modulePages).map((id) => `${base}/${id}`), ]), ] const outcomes: Array<{ path: string; status: number }> = [] for (const path of routes) { const response = await page.goto(path) outcomes.push({ path: path.replaceAll(scope.org, ""), status: response?.status() ?? 0 }) expect(response?.status(), path).toBe(200) await expect(page.locator("main h1").first()).toBeVisible() await expect(page.locator('[data-guide="frame.person"]')).toBeEnabled() expect(await violations(page), path).toEqual([]) } expectedRefusal = true for (const id of [ "missing-module", ...OPTIONAL_MODULE_IDS.filter((id) => !moduleSelected(id) && !["guides", "support"].includes(id)), ]) { const response = await page.goto(`${base}/${id}`) expect(response?.status(), id).toBe(404) await expect(page.getByRole("heading", { name: "Page not found", exact: true })).toBeVisible() expect(await violations(page), `refused ${id}`).toEqual([]) } await info.attach("route-outcomes", { body: Buffer.from(JSON.stringify(outcomes, null, 2)), contentType: "application/json", }) expect(errors).toEqual([]) }) test("keyboard skips the frame and client navigation focuses the new page in both themes", async ({ page, browserName, }, info) => { await signIn(page, `${unique("keyboard-review")}@example.test`) const scope = await makeOrganization(page) await page.goto(`/${scope.org}/${scope.workspace}`) await page.getByRole("button", { name: "Reject analytics and replay", exact: true }).click() for (const colorScheme of ["light", "dark"] as const) { await page.locator('[data-guide="frame.person"]').click() await page.getByRole("menuitemradio", { name: "System", exact: true }).click() await page.reload() await page.locator('[data-guide="frame.person"]').click() await page.getByRole("menuitemradio", { name: colorScheme === "light" ? "Light" : "Dark", exact: true }).click() // Explicit preference wins even when a hidden document control was initially following the device. await page.emulateMedia({ colorScheme: colorScheme === "light" ? "dark" : "light", reducedMotion: "reduce" }) if (colorScheme === "light") await expect(page.locator("html")).toHaveClass(/light/) else await expect(page.locator("html")).not.toHaveClass(/light/) await page.reload() await page.locator("body").press(browserName === "webkit" ? "Alt+Tab" : "Tab") await expect(page.getByRole("link", { name: "Skip to content", exact: true })).toBeFocused() await page.keyboard.press("Enter") await expect(page.locator("main")).toBeFocused() const settings = page.getByRole("link", { name: "Organization settings", exact: true }) if (colorScheme === "light") { let release = () => {} const paused = new Promise((resolve) => { release = resolve }) await page.route("**/*", async (route) => { if (route.request().resourceType() === "fetch" && route.request().method() === "GET") await paused await route.continue() }) try { await settings.press("Enter") const skeleton = page.locator('[data-slot="page-skeleton"]') await expect(skeleton).toBeVisible() await expect(skeleton.getByRole("status")).toBeVisible() const bar = skeleton.locator('[data-slot="skeleton"]').first() await expect(bar).toBeVisible() const painted = await bar.evaluate((el) => { const style = getComputedStyle(el) return { background: style.backgroundColor, animation: style.animationName } }) expect(painted.background).not.toBe("rgba(0, 0, 0, 0)") expect(painted.animation).toBe("none") await page.screenshot({ path: info.outputPath("settings-loading-reduced-motion.png") }) } finally { release() await page.unrouteAll({ behavior: "wait" }) } } else { await settings.press("Enter") } await expect(page.locator("main h1").first()).toBeFocused() for (const width of [360, 768, 1280]) { await page.setViewportSize({ width, height: 900 }) const geometry = await page.evaluate(() => ({ width: innerWidth, scroll: document.documentElement.scrollWidth, overflow: Array.from(document.querySelectorAll("*")) .map((el) => ({ tag: el.tagName, cls: String(el.className), right: el.getBoundingClientRect().right })) .filter((el) => el.right > innerWidth + 1) .slice(0, 12), })) expect(geometry.scroll, JSON.stringify(geometry)).toBeLessThanOrEqual(geometry.width) expect(await violations(page)).toEqual([]) await page.screenshot({ path: info.outputPath(`settings-${colorScheme}-${width}.png`) }) } await page.goto(`/${scope.org}/${scope.workspace}`) } })