feat: consolidate shared UI and harden browser authority for release

This commit is contained in:
2026-09-08 01:35:05 +02:00
parent ac40774785
commit b75ca34295
143 changed files with 8664 additions and 752 deletions
@@ -0,0 +1,52 @@
import { expect, test, type Locator } from "@playwright/test";
async function expectDialogFits(dialog: Locator) {
await expect(dialog).toBeVisible();
const sizes = await dialog.evaluate((panel) => {
const body = panel.querySelector<HTMLElement>(".dialog-body")!;
const rect = panel.getBoundingClientRect();
const overflowControls = Array.from(panel.querySelectorAll("input,select,textarea,.dialog-close,.dialog-footer button")).filter((control) => {
const bounds = control.getBoundingClientRect();
return bounds.left < rect.left - 1 || bounds.right > rect.right + 1;
}).map((control) => control.tagName);
return { horizontalOverflow: body.scrollWidth - body.clientWidth, left: rect.left, right: rect.right, viewport: window.innerWidth, overflowControls };
});
expect(sizes.horizontalOverflow).toBeLessThanOrEqual(1);
expect(sizes.left).toBeGreaterThanOrEqual(0);
expect(sizes.right).toBeLessThanOrEqual(sizes.viewport);
expect(sizes.overflowControls).toEqual([]);
}
for (const width of [320, 390, 768, 1280]) {
test(`shared dialog keeps narrow form content and local table scrolling inside ${width}px`, async ({ page }) => {
await page.setViewportSize({ width, height: 900 });
await page.goto("/?dialog-layout");
const dialog = page.getByRole("dialog");
await expectDialogFits(dialog);
const tableScroll = page.getByTestId("dialog-local-scroll");
expect(await tableScroll.evaluate((element) => element.scrollWidth > element.clientWidth)).toBe(true);
await tableScroll.evaluate((element) => { element.scrollLeft = element.scrollWidth; });
expect(await tableScroll.evaluate((element) => element.scrollLeft)).toBeGreaterThan(0);
await expectDialogFits(dialog);
});
for (const language of ["en", "de"]) {
test(`actual Templates Add dialog fits ${width}px in ${language}`, async ({ page }) => {
const unexpectedWrites: string[] = [];
await page.route((url) => url.pathname.startsWith("/api/"), async (route) => {
const request = route.request();
if (request.method() !== "GET") unexpectedWrites.push(`${request.method()} ${request.url()}`);
await route.fulfill({ json: { items: [] } });
});
await page.setViewportSize({ width, height: 900 });
await page.goto(`/?dialog-layout&fixture=templates&language=${language}`);
await page.getByRole("button", { name: language === "de" ? "Vorlage hinzufügen" : "Add template", exact: true }).click();
const dialog = page.getByRole("dialog");
await expectDialogFits(dialog);
await dialog.locator("input").fill("Eine sehr lange Vorlagenbezeichnung ".repeat(8));
await expectDialogFits(dialog);
await expect(dialog.locator(".dialog-footer button").last()).toBeEnabled();
expect(unexpectedWrites).toEqual([]);
});
}
}