Files
govoplan-core/webui/conformance/tests/card-table-layout.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

80 lines
4.6 KiB
TypeScript
Executable File

import { expect, test, type Locator } from "@playwright/test";
const tableOnlyCards = ["direct-table", "collapsible-table", "loading-table", "admin-table", "loading-admin-table", "connection-table", "loading-connection-table", "explicit-table"];
async function expectFlush(card: Locator) {
const geometry = await card.evaluate((element) => {
const body = element.querySelector(".card-body")!;
const surface = element.querySelector(".data-grid-shell, .connection-tree")!;
const cardRect = element.getBoundingClientRect();
const bodyRect = body.getBoundingClientRect();
const rect = surface.getBoundingClientRect();
const grid = surface.querySelector(".data-grid");
const scrollRegion = surface.querySelector(".data-grid-scroll-region");
return {
left: rect.left - cardRect.left, right: cardRect.right - rect.right,
top: rect.top - bodyRect.top, bottom: cardRect.bottom - rect.bottom,
padding: getComputedStyle(body).padding, border: getComputedStyle(surface).borderWidth,
unfilledWidth: grid && scrollRegion ? scrollRegion.clientWidth - grid.getBoundingClientRect().width : 0
};
});
expect(geometry.padding).toBe("0px");
expect(geometry.border).toBe("0px");
expect(geometry.unfilledWidth).toBeLessThanOrEqual(1);
for (const edge of [geometry.left, geometry.right, geometry.top, geometry.bottom]) expect(Math.abs(edge)).toBeLessThanOrEqual(1);
}
for (const width of [1280, 390, 320]) {
test(`table-only cards use their full interior without negative margins at ${width}px`, async ({ page }) => {
const errors: string[] = [];
page.on("pageerror", (error) => errors.push(error.message));
await page.setViewportSize({ width, height: 900 });
await page.goto("/?data-grid-layout&table-cards&language=en&theme=light");
for (const id of tableOnlyCards) await expectFlush(page.getByTestId(id));
for (const id of ["mixed-content", "loading-mixed-content"]) {
const body = page.getByTestId(id).locator(".card-body");
await expect(body).toHaveCSS("padding", "22px 24px");
await expect(body.locator(".data-grid-shell")).toHaveCSS("border-width", "1px");
}
const context = page.getByTestId("table-with-context");
await expect(context.locator(".card-body")).toHaveCSS("padding", "0px");
await expect(context.locator(".content-section")).toHaveCSS("padding", "18px");
const contextBounds = await context.boundingBox();
const contextGrid = await context.locator(".data-grid-shell").boundingBox();
expect(contextGrid!.x - contextBounds!.x).toBeCloseTo(1, 0);
expect(contextBounds!.width - contextGrid!.width).toBeCloseTo(2, 0);
await expect(page.getByTestId("standalone-table").locator(".data-grid-shell")).toHaveCSS("border-width", "1px");
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1)).toBe(true);
expect(errors).toEqual([]);
});
}
test("loading overlays and collapse do not change table insets or lose row actions", async ({ page }) => {
await page.setViewportSize({ width: 390, height: 900 });
await page.goto("/?data-grid-layout&table-cards&language=en&theme=light");
const before = await page.getByTestId("loading-table").boundingBox();
await page.getByRole("button", { name: "Toggle loading", exact: true }).click();
for (const id of ["loading-table", "loading-admin-table", "loading-connection-table", "explicit-table"]) {
const card = page.getByTestId(id);
await expectFlush(card);
const frame = await card.locator(".loading-frame").boundingBox();
const overlay = await card.locator(".loading-frame-overlay").boundingBox();
expect(overlay).toEqual(frame);
await expect(card.locator(".loading-frame")).toHaveAttribute("aria-busy", "true");
}
expect(await page.getByTestId("loading-table").boundingBox()).toEqual(before);
await page.getByRole("button", { name: "Toggle loading", exact: true }).click();
const collapsible = page.getByTestId("collapsible-table");
await collapsible.locator(".card-collapse-toggle").click();
await expect(collapsible.locator(".data-grid-shell")).toHaveCount(0);
await collapsible.locator(".card-collapse-toggle").click();
await expectFlush(collapsible);
const direct = page.getByTestId("direct-table");
const scroller = direct.locator(".data-grid-scroll-region");
expect(await scroller.evaluate((element) => element.scrollWidth > element.clientWidth)).toBe(true);
await scroller.evaluate((element) => { element.scrollLeft = element.scrollWidth; });
const action = direct.getByRole("button", { name: "Inspect Alpha", exact: true });
await action.click();
await expect(page.getByTestId("card-table-inspected")).toHaveText("Alpha");
});