- A library past the list's cap is searched and sorted on the server; the count says "the newest". - Each folder and each search opens on its first page (DataTable pageScope, useCardPager scope). - A file dropped where the page takes none never reaches the browser (which would unload the app). - The viewer's arrows wait while a layer opened from it is on top, and scroll a wide text line; a text shows its first 5000 lines and says where the rest is. - Confirms name the file (no more "your downloads"); the asking menu rows end in "…". - The tray names a running step beside its bar, shows a pause mark for paused work, polls slowly while only paused work waits, and forgets a finished file that was deleted. - An unchanged rename sends nothing; a paste opens the download dialog only with nothing on top; the link box never replaces what was typed. - Honest states: folders that failed to load, a file no longer there, the storage figure; the rail says "nothing downloaded" only when there is nothing. - Focus after deleting the open folder and when the format form opens; the format name's label. - ui/Meter (one danger line for both quota bars) and ui/RenameField in the platform layer. - Copy fixes, stale comments and the speculative hub key; a contract test for the list's parameters; e2e: the Files page and the paste intake.
53 lines
2.4 KiB
TypeScript
53 lines
2.4 KiB
TypeScript
import { test, expect } from "@playwright/test";
|
|
import { openApp } from "./helpers";
|
|
|
|
// Locks top-level navigation: each rail item activates its page (aria-current), and browser
|
|
// Back steps through the history the app pushes. The render ternary + prop-drilled page state
|
|
// this exercises is precisely what the module-registry refactor replaces.
|
|
test.describe("page switching", () => {
|
|
// Core + admin modules (the E2E account is an admin, matching the real primary user), so this
|
|
// also exercises the admin pages. They sit behind ONE rail row ("Administration",
|
|
// `nav-admin`) that opens a panel of them — the spec still listed them as rail rows of their own,
|
|
// and it failed on every run for a while without anyone seeing it, because e2e was in no
|
|
// required gate (it is now part of `release`).
|
|
const RAIL = ["channels", "playlists", "files", "stats", "settings", "feed"];
|
|
const ADMIN = ["scheduler", "config", "users", "audit"];
|
|
|
|
test("each rail item activates its page", async ({ page }) => {
|
|
await openApp(page);
|
|
for (const id of RAIL) {
|
|
await page.getByTestId(`nav-${id}`).click();
|
|
await expect(page.getByTestId(`nav-${id}`)).toHaveAttribute("aria-current", "page");
|
|
}
|
|
});
|
|
|
|
test("each admin page opens from the Administration panel and marks it current", async ({
|
|
page,
|
|
}) => {
|
|
await openApp(page);
|
|
for (const id of ADMIN) {
|
|
await page.getByTestId("nav-admin").click();
|
|
await page.getByTestId(`nav-admin-${id}`).click();
|
|
// The panel closes on a pick; the group row carries the current page…
|
|
await expect(page.getByTestId("nav-admin")).toHaveAttribute("aria-current", "page");
|
|
// …and, reopened, the panel marks which one.
|
|
await page.getByTestId("nav-admin").click();
|
|
await expect(page.getByTestId(`nav-admin-${id}`)).toHaveAttribute("aria-current", "page");
|
|
await page.keyboard.press("Escape");
|
|
}
|
|
});
|
|
|
|
test("browser Back steps through visited pages", async ({ page }) => {
|
|
await openApp(page);
|
|
|
|
await page.getByTestId("nav-channels").click();
|
|
await expect(page.getByTestId("nav-channels")).toHaveAttribute("aria-current", "page");
|
|
|
|
await page.getByTestId("nav-playlists").click();
|
|
await expect(page.getByTestId("nav-playlists")).toHaveAttribute("aria-current", "page");
|
|
|
|
await page.goBack();
|
|
await expect(page.getByTestId("nav-channels")).toHaveAttribute("aria-current", "page");
|
|
});
|
|
});
|