From ae7614cbf56850df52a6725ba0bf9504e806dd86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 1 Oct 2026 13:50:45 -0400 Subject: [PATCH] =?UTF-8?q?T48m=20Docs=20=C2=B7=20E2E:=20each=20guide's=20?= =?UTF-8?q?heading,=20rail=20name=20and=20browser=20title=20checked;=20a?= =?UTF-8?q?=20prose=20link=20routes=20in=20place?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/e2e/docs.spec.ts | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/frontend/e2e/docs.spec.ts b/frontend/e2e/docs.spec.ts index 36b1501..4b37530 100644 --- a/frontend/e2e/docs.spec.ts +++ b/frontend/e2e/docs.spec.ts @@ -1,8 +1,20 @@ import { readFileSync } from "node:fs"; import { expect, test, type Page } from "@playwright/test"; -/** The guides in reading order, as `src/docs/guides.ts` lists them. */ -const GUIDES = ["", "installation", "getting-started", "theme", "focus", "motion", "icons", "overlays", "i18n", "webassembly", "testing"]; +/** The guides in reading order, as `src/docs/guides.ts` lists them, with their titles. */ +const GUIDES: [string, string][] = [ + ["", "Introduction"], + ["installation", "Installation"], + ["getting-started", "Getting started"], + ["theme", "Theme"], + ["focus", "Focus and keyboard"], + ["motion", "Motion"], + ["icons", "Icons, fonts and assets"], + ["overlays", "Overlays"], + ["i18n", "Internationalization"], + ["webassembly", "WebAssembly"], + ["testing", "Testing"], +]; const path = (slug: string) => (slug ? `/docs/${slug}/` : "/docs/"); @@ -23,9 +35,10 @@ test("the header's Docs link opens the introduction", async ({ page }) => { test("every guide loads with its title, list and no errors", async ({ page }) => { const errors = watch(page); - for (const slug of GUIDES) { + for (const [slug, title] of GUIDES) { await page.goto(path(slug)); - await expect(page.locator(".doc h1")).not.toBeEmpty(); + await expect(page.locator(".doc h1")).toHaveText(title); + await expect(page).toHaveTitle(`${title} · Docs · Ely`); await expect(page.locator(".prose h2").first()).toBeVisible(); } expect(errors).toEqual([]); @@ -35,7 +48,10 @@ test("the rail lists the guides in order and marks the open one", async ({ page await page.goto("/docs/theme/"); const links = page.locator(".docs-rail a"); await expect(links).toHaveCount(GUIDES.length); - for (const [i, slug] of GUIDES.entries()) await expect(links.nth(i)).toHaveAttribute("href", path(slug)); + for (const [i, [slug, title]] of GUIDES.entries()) { + await expect(links.nth(i)).toHaveAttribute("href", path(slug)); + await expect(links.nth(i)).toHaveText(title); + } await expect(page.locator('.docs-rail a[aria-current="page"]')).toHaveText("Theme"); }); @@ -44,7 +60,7 @@ test("previous and next walk the guides", async ({ page }) => { await expect(page.locator(".pager a")).toHaveCount(1); await page.locator(".pager a.next").click(); await expect(page).toHaveURL("/docs/installation/"); - await page.goto(path(GUIDES[GUIDES.length - 1])); + await page.goto(path(GUIDES[GUIDES.length - 1][0])); await expect(page.locator(".pager a.next")).toHaveCount(0); }); @@ -56,6 +72,15 @@ test("an on-this-page link moves to its section", async ({ page, isMobile }) => await expect(page.locator("#when-it-fails")).toBeInViewport(); }); +test("a link in a guide routes in place to its section", async ({ page }) => { + await page.goto("/docs/installation/"); + await page.evaluate(() => ((window as unknown as { kept: boolean }).kept = true)); + await page.locator(".prose a", { hasText: "first window" }).click(); + await expect(page).toHaveURL("/docs/#a-first-window"); + await expect(page.locator("#a-first-window")).toBeInViewport(); + expect(await page.evaluate(() => (window as unknown as { kept?: boolean }).kept)).toBe(true); +}); + test("a code sample is the compiled example, and Copy copies it", async ({ page, context, browserName, isMobile }) => { test.skip(browserName !== "chromium" || isMobile, "clipboard reads need Chromium's permission"); await context.grantPermissions(["clipboard-read", "clipboard-write"]);