Locks the five flows the refactor must not break (feed, channel, player, settings, nav) so later sprints can prove they changed nothing. Adds a thin data-testid layer and a dedicated seeded non-demo account; the suite runs on the baked :8080 stack (authoritative) or :5173. No product-behaviour change.
51 lines
2.2 KiB
TypeScript
51 lines
2.2 KiB
TypeScript
import { test, expect } from "@playwright/test";
|
|
import { openApp } from "./helpers";
|
|
|
|
// Locks the feed's core contract: it renders cards, a filter re-queries it and surfaces a
|
|
// removable chip, and its virtualized list windows in fresh rows as you scroll.
|
|
test.describe("feed", () => {
|
|
test("a filter re-queries the feed and surfaces a removable chip", async ({ page }) => {
|
|
await openApp(page);
|
|
await expect(page.getByTestId("video-card").first()).toBeVisible();
|
|
|
|
const count = page.getByTestId("feed-result-count");
|
|
await expect(count).toHaveText(/\d/);
|
|
const baseline = await count.innerText();
|
|
|
|
// Clean baseline: default filters, so no chips and "unwatched" is the active show.
|
|
await expect(page.getByTestId("active-filter-chip")).toHaveCount(0);
|
|
await expect(page.getByTestId("feed-show-unwatched")).toHaveAttribute("aria-pressed", "true");
|
|
|
|
// Narrow to "watched" — the seed guarantees exactly one, a real deterministic change.
|
|
await page.getByTestId("feed-show-watched").click();
|
|
await expect(page.getByTestId("active-filter-chip")).toHaveCount(1);
|
|
await expect(count).not.toHaveText(baseline);
|
|
|
|
// Remove the chip → default show restored, chips gone.
|
|
await page.getByTestId("active-filter-chip").click();
|
|
await expect(page.getByTestId("active-filter-chip")).toHaveCount(0);
|
|
await expect(page.getByTestId("feed-show-unwatched")).toHaveAttribute("aria-pressed", "true");
|
|
});
|
|
|
|
test("scrolling virtualizes in fresh cards", async ({ page }) => {
|
|
await openApp(page);
|
|
await expect(page.getByTestId("video-card").first()).toBeVisible();
|
|
|
|
const renderedIds = () =>
|
|
page
|
|
.getByTestId("video-card")
|
|
.evaluateAll((els) => els.map((e) => e.getAttribute("data-video-id")));
|
|
|
|
const before = await renderedIds();
|
|
expect(before.length).toBeGreaterThan(0);
|
|
|
|
// The feed scrolls inside <main> (role="main"), not the window.
|
|
await page.getByRole("main").evaluate((el) => el.scrollBy(0, 5000));
|
|
|
|
// A windowed list renders different rows once scrolled.
|
|
await expect
|
|
.poll(async () => (await renderedIds()).some((id) => id && !before.includes(id)))
|
|
.toBe(true);
|
|
});
|
|
});
|