Files
govoplan-core/webui/conformance/tests/heading-help.spec.ts
T
zemion 6d37aa527f fix(ui): unify heading help, table sizing and navigation contracts
Verified with the coordinated workspace changes by devkit full run
2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed).
This shared UI pass does not mark the individual module reviews complete.
2026-09-09 02:03:16 +02:00

103 lines
6.1 KiB
TypeScript
Executable File

import { expect, test, type Locator } from "@playwright/test";
async function expectHelpBesideHeading(anchor: Locator) {
const heading = anchor.locator(":scope > :is(h1,h2,h3)");
const link = anchor.getByRole("link");
await expect(heading).toBeVisible();
await expect(link).toBeVisible();
await expect(heading.locator("a,button,[role=status]")).toHaveCount(0);
const geometry = await anchor.evaluate(element => {
const heading = element.querySelector(":scope > :is(h1,h2,h3)")!.getBoundingClientRect();
const link = element.querySelector("a")!.getBoundingClientRect();
return { gap: link.left - heading.right, right: link.right, viewport: window.innerWidth };
});
expect(geometry.gap).toBeGreaterThanOrEqual(4);
expect(geometry.gap).toBeLessThanOrEqual(8);
expect(geometry.right).toBeLessThanOrEqual(geometry.viewport);
}
for (const width of [390, 3085]) {
for (const language of ["en", "de"]) {
test(`documentation remains beside headings during loading and long-title wrapping (${width}px, ${language})`, async ({ page }) => {
await page.setViewportSize({ width, height: 1100 });
await page.goto(`/?heading-help&language=${language}`);
const pageTitle = page.locator(".page-title-with-loader");
await expect(page.getByRole("heading", { level: 1, name: "Dashboard", exact: true })).toBeVisible();
await expect(pageTitle.getByRole("status")).toBeVisible();
await expect(pageTitle.getByRole("link")).toHaveAccessibleName(language === "de" ? "Benutzerdokumentation öffnen" : "Open user documentation");
for (const anchor of await page.locator(".text-with-help:has(> :is(h1,h2,h3))").all()) await expectHelpBesideHeading(anchor);
const rawLabel = page.getByTestId("raw-text-help");
const rawGeometry = await rawLabel.evaluate(element => ({ width: element.clientWidth, scrollWidth: element.scrollWidth, right: element.getBoundingClientRect().right, helpRight: element.querySelector("a")!.getBoundingClientRect().right }));
expect(rawGeometry.scrollWidth).toBeLessThanOrEqual(rawGeometry.width);
expect(rawGeometry.helpRight).toBeLessThanOrEqual(rawGeometry.right);
await page.getByRole("button", { name: "Toggle loading", exact: true }).click();
await expect(pageTitle.getByRole("status")).toHaveCount(0);
await expectHelpBesideHeading(pageTitle.locator(".text-with-help"));
await expect(page.locator('[data-page-action-slot="help"]')).toHaveCount(0);
expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBeLessThanOrEqual(1);
});
}
}
test("card help stays available when collapsed and opening it does not toggle content", async ({ page, context }) => {
await context.route("https://govoplan.add-ideas.de/**", route => route.fulfill({ body: "Documentation fixture" }));
await page.goto("/?heading-help&language=en");
const card = page.getByTestId("help-card");
const popupPromise = page.waitForEvent("popup");
await card.getByRole("link").click();
const popup = await popupPromise;
await popup.close();
await expect(page.getByTestId("help-card-content")).toBeVisible();
await card.getByRole("button", { name: "Show header only", exact: true }).click();
await expect(page.getByTestId("help-card-content")).toHaveCount(0);
await expectHelpBesideHeading(card.locator(".text-with-help"));
await card.getByRole("button", { name: "Show content", exact: true }).click();
await expect(page.getByTestId("help-card-content")).toBeVisible();
});
test("dialog help has its own name, remains in keyboard order, and does not dismiss the dialog", async ({ page, context }) => {
await context.route("https://govoplan.add-ideas.de/**", route => route.fulfill({ body: "Documentation fixture" }));
await page.setViewportSize({ width: 390, height: 1000 });
await page.goto("/?heading-help&language=en");
await page.getByTestId("open-help-dialog").click();
const dialog = page.getByRole("dialog");
await expect(dialog).toHaveAccessibleName(/^Dashboard DokumentationsüberschriftOhneLeerzeichen/);
await expectHelpBesideHeading(dialog.locator(".text-with-help"));
const help = dialog.getByRole("link");
await expect(help).toBeFocused();
await help.press("Shift+Tab");
await expect(page.getByTestId("dialog-last-action")).toBeFocused();
await page.getByTestId("dialog-last-action").press("Tab");
await expect(help).toBeFocused();
const popupPromise = page.waitForEvent("popup");
await help.click();
const popup = await popupPromise;
await popup.close();
await expect(dialog).toBeVisible();
await dialog.getByRole("button", { name: "Close", exact: true }).click();
await expect(dialog).toHaveCount(0);
await expect(page.getByTestId("open-help-dialog")).toBeFocused();
});
test("widget documentation stays beside its one existing title in display, configuration, and drag markup", async ({ page }) => {
await page.goto("/?heading-help&widgets&language=en");
const title = page.getByRole("heading", { name: "Scheduling requests", exact: true });
const anchor = page.locator(".card-title-with-help");
await expect(title).toHaveCount(1);
await expectHelpBesideHeading(anchor);
await expect(anchor.getByRole("link")).toHaveAttribute("href", "/docs?type=user&topic=scheduling.find-and-decide-meeting-time");
await page.getByRole("button", { name: "Toggle configuration", exact: true }).click();
await expect(title).toHaveCount(1);
await expectHelpBesideHeading(anchor);
await expect(page.locator(".card-actions .documentation-help-link")).toHaveCount(0);
await page.getByRole("button", { name: "Toggle drag preview", exact: true }).click();
// A drag placeholder retains hidden content only to preserve the widget height.
const preview = page.locator(".dashboard-widget-placeholder-content");
await expect(preview.locator("h2")).toHaveCount(1);
await expect(preview.locator(".card-title-with-help .documentation-help-link")).toHaveAttribute("href", "/docs?type=user&topic=scheduling.find-and-decide-meeting-time");
await expect(preview).toBeHidden();
await page.getByRole("button", { name: "Toggle drag preview", exact: true }).click();
await expect(title).toHaveCount(1);
await expectHelpBesideHeading(anchor);
});