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.
93 lines
6.1 KiB
TypeScript
93 lines
6.1 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
test("collapsed rail keeps visible group separators; opening settings is clean", async ({ page }) => {
|
|
await page.goto("/?navigation-layout");
|
|
const rail = page.locator(".icon-rail");
|
|
await expect(rail).not.toHaveClass(/expanded/);
|
|
await expect(rail.getByRole("separator")).toHaveCount(2);
|
|
for (const separator of await rail.getByRole("separator").all()) {
|
|
await expect(separator).toBeVisible();
|
|
expect((await separator.boundingBox())!.width).toBeGreaterThan(20);
|
|
}
|
|
await expect(page.getByTestId("navigation-draft")).toHaveText("null");
|
|
await expect(page.locator('[data-navigation-layout-status="inherited"]')).toContainText("standard layout groups available modules by product area");
|
|
const spacing = await page.locator(".navigation-preference-list > li").first().evaluate((row) => {
|
|
const style = getComputedStyle(row);
|
|
return { padding: Number.parseFloat(style.paddingLeft), gap: Number.parseFloat(style.columnGap) };
|
|
});
|
|
expect(spacing.padding).toBeGreaterThanOrEqual(8);
|
|
expect(spacing.gap).toBeGreaterThanOrEqual(8);
|
|
await page.getByRole("button", { name: "Expand navigation", exact: true }).click();
|
|
await expect(rail.getByText("Documents", { exact: true })).toBeVisible();
|
|
await expect(rail.getByRole("separator")).toHaveCount(0);
|
|
await page.getByRole("button", { name: "Collapse navigation", exact: true }).click();
|
|
await expect(rail.getByRole("separator")).toHaveCount(2);
|
|
await expect(rail.getByText("Documents", { exact: true })).toBeHidden();
|
|
});
|
|
|
|
for (const scope of ["system", "tenant", "user", "view"]) {
|
|
test(`same editor supports add/remove, keyboard reorder and inheritance at ${scope} scope`, async ({ page }) => {
|
|
await page.goto(`/?navigation-layout&scope=${scope}`);
|
|
const list = page.getByRole("list", { name: "Navigation layout" });
|
|
const files = list.locator('[data-navigation-id="files"]');
|
|
await files.getByRole("button", { name: "Remove Files", exact: true }).click();
|
|
await expect(files).toHaveCount(0);
|
|
await page.getByRole("button", { name: "Add module", exact: true }).click();
|
|
await expect(list.locator("li").last()).toHaveAttribute("data-navigation-id", "files");
|
|
const handle = files.getByRole("button", { name: "Reorder Files", exact: true });
|
|
const before = await list.locator("li").evaluateAll((rows) => rows.map((row) => row.getAttribute("data-navigation-id")));
|
|
await handle.press("Space");
|
|
await handle.press("ArrowUp");
|
|
await expect(list.locator("li").last()).not.toHaveAttribute("data-navigation-id", "files");
|
|
await handle.press("Escape");
|
|
expect(await list.locator("li").evaluateAll((rows) => rows.map((row) => row.getAttribute("data-navigation-id")))).toEqual(before);
|
|
await handle.press("Space"); await handle.press("ArrowUp"); await handle.press("Enter");
|
|
await page.getByRole("button", { name: "Add separator", exact: true }).click();
|
|
const separator = list.locator("li").last();
|
|
await expect(separator).toHaveAttribute("data-navigation-kind", "separator");
|
|
await separator.getByRole("textbox").fill("Custom group");
|
|
const saved = JSON.parse(await page.getByTestId("navigation-draft").textContent() ?? "null");
|
|
expect(saved.separators.at(-1).label).toBe("Custom group");
|
|
await separator.getByRole("button", { name: "Remove Custom group", exact: true }).click();
|
|
if (scope !== "system") await expect(list.getByRole("button", { name: "Remove Dashboard", exact: true })).toBeDisabled();
|
|
await page.getByRole("button", { name: "Use inherited layout", exact: true }).click();
|
|
await expect(page.getByTestId("navigation-draft")).toHaveText("null");
|
|
});
|
|
}
|
|
|
|
test("native pointer drag reorders modules and separators", async ({ page }) => {
|
|
await page.goto("/?navigation-layout");
|
|
const list = page.getByRole("list", { name: "Navigation layout" });
|
|
const files = list.locator('[data-navigation-id="files"]');
|
|
await files.getByRole("button", { name: "Reorder Files", exact: true }).dragTo(list.locator("li").first(), { targetPosition: { x: 15, y: 3 } });
|
|
await expect(list.locator("li").first()).toHaveAttribute("data-navigation-id", "files");
|
|
const separator = list.locator('[data-navigation-kind="separator"]').first();
|
|
const separatorId = await separator.getAttribute("data-navigation-id");
|
|
await separator.getByRole("button", { name: /^Reorder / }).dragTo(list.locator("li").first(), { targetPosition: { x: 15, y: 3 } });
|
|
await expect(list.locator("li").first()).toHaveAttribute("data-navigation-id", separatorId!);
|
|
});
|
|
|
|
test("no-op reordering stays clean and optional module positions survive other edits", async ({ page }) => {
|
|
await page.goto("/?navigation-layout");
|
|
const handle = page.getByRole("button", { name: "Reorder Files", exact: true });
|
|
await handle.press("Space"); await handle.press("Enter");
|
|
await expect(page.getByTestId("navigation-draft")).toHaveText("null");
|
|
await page.goto("/?navigation-layout&unavailable");
|
|
await expect(page.locator('[data-navigation-layout-status="flat"]')).toContainText("without group headings or dividers");
|
|
await expect(page.locator(".icon-rail").getByRole("separator")).toHaveCount(0);
|
|
await page.getByRole("button", { name: "Move Mail up", exact: true }).click();
|
|
const draft = JSON.parse(await page.getByTestId("navigation-draft").textContent() ?? "null");
|
|
expect(draft.order).toContain("optional.navigation.absent");
|
|
await page.getByRole("button", { name: "Use inherited layout", exact: true }).click();
|
|
await expect(page.locator(".icon-rail").getByRole("separator")).toHaveCount(2);
|
|
await expect(page.getByTestId("navigation-draft")).toHaveText("null");
|
|
});
|
|
|
|
test("German narrow editor does not overflow and read-only controls cannot mutate", async ({ page }) => {
|
|
await page.setViewportSize({ width: 390, height: 900 });
|
|
await page.goto("/?navigation-layout&language=de&disabled");
|
|
await expect(page.getByRole("button", { name: "Trennlinie hinzufügen", exact: true })).toBeDisabled();
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
|
|
await expect(page.getByTestId("navigation-draft")).toHaveText("null");
|
|
});
|