The code cited its plan instead of saying why: `E28 review J4`, `(R6 S3b)`, `S1 justified…`,
`deep-review round 5`. That plan lives in the private ops repo, so for every reader of this one the
citation was noise, and a sentence whose subject was the plan step ("round 2 showed…") hid its
lesson behind an id. Each one is gone and the "why" kept: a bare citation is deleted, a sentence
carrying a lesson is reworded around it ("a later attempt showed…").
Measured (`scripts/audit_metrics.py`, product code): 652 lines in 270 files carried an epic code by
the definition the next commit holds (507 / 241 by the old, two-digit-only one) -> 0. Across all
code, tests, scripts and configs: ~1100 epic-code lines plus ~320 sprint/round ids.
Behaviour unchanged, checked mechanically: every changed .py file has the same AST once docstrings
are blanked; css/sh/toml/yml/json files are identical once comments are stripped; the only
non-comment changes in TS/JS are test titles, one description string in a contract table, and five
ESLint messages, whose text is all the gates snapshot diff holds. Not touched: Markdown (docs and
the changelog keep their history), Alembic migrations, TV episode notation (`S2 · E5`), DESIGN.md
ids (`C1`, `B4`, `S3h`), tracker ids (`SEC-16`, `DX-17`).
One stale claim fixed on the way: test_hls_reaper's docstring said the player checkpoints "every
10 s whether or not it is playing", which plex/stream.py calls wrong; it now says what the code does.
71 lines
3.3 KiB
TypeScript
71 lines
3.3 KiB
TypeScript
import { expect, type Page } from "@playwright/test";
|
|
|
|
/** Open the app and wait for the authenticated shell (the nav rail) to be ready. */
|
|
export async function openApp(page: Page, path = "/"): Promise<void> {
|
|
await page.goto(path);
|
|
await expect(page.getByTestId("nav-feed")).toBeVisible();
|
|
}
|
|
|
|
/** Click a top-level module in the nav rail and confirm it becomes the active page. */
|
|
export async function gotoPage(page: Page, id: string): Promise<void> {
|
|
await page.getByTestId(`nav-${id}`).click();
|
|
await expect(page.getByTestId(`nav-${id}`)).toHaveAttribute("aria-current", "page");
|
|
}
|
|
|
|
/**
|
|
* Click a channel link a real user can actually SEE and hit. Never use `.first()` for this after
|
|
* scrolling: the first rendered card lives in the virtualizer's overscan ABOVE the viewport, so
|
|
* Playwright would scroll it into view to click it, moving the scroll position — fatal to any test
|
|
* that then asserts on where the feed was. Being inside the viewport is not enough either: a card
|
|
* can sit under the page chrome above the scroller (the update banner, the toolbar band), and the
|
|
* covered click makes Playwright scroll and retry — the same move (webkit failed 3 in 24).
|
|
* So the link must be the element hit at its own centre. Returns false if none found.
|
|
*/
|
|
export async function clickVisibleChannelLink(page: Page): Promise<boolean> {
|
|
const links = page.getByTestId("video-card-channel").filter({ visible: true });
|
|
const count = await links.count();
|
|
for (let i = 0; i < count; i++) {
|
|
const hittable = await links.nth(i).evaluate((el) => {
|
|
const r = el.getBoundingClientRect();
|
|
const hit = document.elementFromPoint(r.left + r.width / 2, r.top + r.height / 2);
|
|
return hit !== null && el.contains(hit);
|
|
});
|
|
if (hittable) {
|
|
await links.nth(i).click();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Assert a content-type (e.g. "includeLive") is on/off via the Content-types FilterSelect dropdown.
|
|
* The options only exist while the dropdown is open, so this opens it, checks the option's
|
|
* `aria-checked` (the multi FilterSelect renders its rows as menuitemcheckbox), then closes it
|
|
* (Escape) so the floating panel can't block a later click.
|
|
*/
|
|
export async function expectContentType(page: Page, value: string, on: boolean): Promise<void> {
|
|
await page.getByTestId("feed-content").click();
|
|
await expect(page.getByTestId(`feed-content-${value}`)).toHaveAttribute(
|
|
"aria-checked",
|
|
on ? "true" : "false",
|
|
);
|
|
await page.keyboard.press("Escape");
|
|
await expect(page.getByTestId(`feed-content-${value}`)).toHaveCount(0);
|
|
}
|
|
|
|
/** Toggle a content-type via the Content-types FilterSelect dropdown, then close it. */
|
|
export async function toggleContentType(page: Page, value: string): Promise<void> {
|
|
await page.getByTestId("feed-content").click();
|
|
await page.getByTestId(`feed-content-${value}`).click();
|
|
await page.keyboard.press("Escape");
|
|
await expect(page.getByTestId(`feed-content-${value}`)).toHaveCount(0);
|
|
}
|
|
|
|
/** Open the in-app player from the first feed card (clicks its thumbnail link). */
|
|
export async function openFirstVideo(page: Page): Promise<void> {
|
|
await expect(page.getByTestId("video-card").first()).toBeVisible();
|
|
await page.getByTestId("video-card").first().getByRole("link").first().click();
|
|
await expect(page.getByTestId("player-modal")).toBeVisible();
|
|
}
|