mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
A spec that arms `page.route(...)` in a `beforeEach` and never drops the handler races its own teardown. The context closes, an async handler is still awaiting, its next call rejects with "Test ended.", and Playwright attributes that to the test that had just passed. With `retries: 2` plus `failOnFlakyTests`, which spec bites is a matter of timing. `e2e/setup/test.ts` re-exports Playwright's `test` extended with an auto fixture that unroutes every page and the context after each test, and clears the page event listeners a spec subscribes to; `expect` rides along so a spec needs one import. Auto means a spec author cannot forget it and does not have to know it exists. Every spec now takes `test` from there, and `e2e-route-cleanup-guard.test.ts` keeps the import boundary closed with an allowlist that carries its reason. The per-file `afterEach` on the cycle spec goes away — leaving both would read as not trusting the fixture. Not covered: a page inside a context a spec builds itself. Only `share-documents.spec.ts` does that, and it owns those contexts.
97 lines
3.6 KiB
TypeScript
97 lines
3.6 KiB
TypeScript
import { expect, test } from "./setup/test";
|
|
|
|
import { STORAGE_STATE_PATH } from "./setup/global-setup";
|
|
|
|
/**
|
|
* v1.4.16 A1 — Sidebar Admin entry must mirror the Settings entry
|
|
* exactly: a single link with no sub-item expansion in the global
|
|
* sidebar. The maintainer reported in v1.4.15 that the sidebar was auto-expanding
|
|
* admin sub-items on `/admin/*` and the gravatar dropdown felt linked to
|
|
* the sidebar — both unwanted UX. The in-shell `<AdminShell>` already
|
|
* renders its own per-section nav inside the page itself.
|
|
*
|
|
* This spec runs only on the desktop project (Pixel 5 hides the global
|
|
* sidebar entirely).
|
|
*/
|
|
test.describe("sidebar Admin entry no-expansion", () => {
|
|
test.use({ storageState: STORAGE_STATE_PATH });
|
|
|
|
test.beforeEach(({}, testInfo) => {
|
|
test.skip(
|
|
testInfo.project.name === "chromium-mobile",
|
|
"global sidebar is desktop-only (md+)",
|
|
);
|
|
});
|
|
|
|
test("on /admin/system-status the sidebar shows ONLY the single Admin link, no sub-list", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/admin/system-status", {
|
|
waitUntil: "domcontentloaded",
|
|
});
|
|
|
|
// The desktop sidebar is the <aside aria-label="Sidebar"> element.
|
|
// (See `src/components/layout/sidebar-nav.tsx`.) The Admin entry
|
|
// inside it must be the ONLY link starting with `/admin` — there
|
|
// must be no anchor pointing at a sub-route like `/admin/users`.
|
|
const sidebar = page.locator("aside[aria-label]").first();
|
|
await expect(sidebar).toBeVisible();
|
|
|
|
const adminLink = sidebar.locator("a[href='/admin']");
|
|
await expect(adminLink).toHaveCount(1);
|
|
|
|
// No sub-section anchors inside the sidebar — those belong to
|
|
// `<AdminShell>`'s in-page nav, not the global sidebar.
|
|
const subLinks = sidebar.locator("a[href^='/admin/']:not([href='/admin'])");
|
|
await expect(subLinks).toHaveCount(0);
|
|
});
|
|
|
|
test("clicking Admin from /dashboard navigates without flashing a sub-list", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/", { waitUntil: "domcontentloaded" });
|
|
|
|
const sidebar = page.locator("aside[aria-label]").first();
|
|
await expect(sidebar).toBeVisible();
|
|
|
|
// Pre-click sanity: only the single Admin link is present (no
|
|
// sub-items rendered eagerly).
|
|
await expect(sidebar.locator("a[href='/admin']")).toHaveCount(1);
|
|
await expect(
|
|
sidebar.locator("a[href^='/admin/']:not([href='/admin'])"),
|
|
).toHaveCount(0);
|
|
|
|
await sidebar.locator("a[href='/admin']").click();
|
|
await page.waitForURL(/\/admin(\/|$)/);
|
|
|
|
// After navigation the sidebar still shows only the single Admin
|
|
// link — no sub-list expansion.
|
|
await expect(sidebar.locator("a[href='/admin']")).toHaveCount(1);
|
|
await expect(
|
|
sidebar.locator("a[href^='/admin/']:not([href='/admin'])"),
|
|
).toHaveCount(0);
|
|
});
|
|
|
|
test("opening the gravatar user-menu does not expand sidebar admin sub-items", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/", { waitUntil: "domcontentloaded" });
|
|
|
|
const sidebar = page.locator("aside[aria-label]").first();
|
|
await expect(sidebar).toBeVisible();
|
|
|
|
// The user-menu trigger sits inside the sidebar's user section.
|
|
// It carries `aria-label="User menu"`. Open it and confirm the
|
|
// sidebar admin section is unaffected.
|
|
const userMenu = sidebar.getByRole("button", { name: /user menu/i });
|
|
await userMenu.click();
|
|
|
|
// Dropdown is open — but the sidebar's structure is still the
|
|
// single Admin entry, no sub-items.
|
|
await expect(sidebar.locator("a[href='/admin']")).toHaveCount(1);
|
|
await expect(
|
|
sidebar.locator("a[href^='/admin/']:not([href='/admin'])"),
|
|
).toHaveCount(0);
|
|
});
|
|
});
|