import { test, expect, type Browser, type Page } from "@playwright/test"; import { clickVisibleChannelLink, expectContentType, gotoPage, openApp, openFirstVideo, toggleContentType, } from "./helpers"; // The address is the view: a view set through the UI, its address opened as a bookmark — in a NEW // browser context, so nothing this tab remembered (its history entries, sessionStorage, the view // storage it wrote) can stand in for what the address says. One round trip per page, plus the // overlays the shell opens over any page (the channel page, the player) and the live search. const STORAGE_STATE = "e2e/.auth/state.json"; /** The page's address, opened as a bookmark in a fresh context of the same account. */ async function bookmarked(browser: Browser, page: Page, prepare?: (p: Page) => Promise) { const url = page.url(); const ctx = await browser.newContext({ storageState: STORAGE_STATE, locale: "en-US" }); const fresh = await ctx.newPage(); await prepare?.(fresh); await openApp(fresh, url); return fresh; } const tab = (p: Page, name: string) => p.getByRole("tab", { name, exact: true }); test.describe("a bookmark reopens the view it was taken of", () => { test("the feed's filters", async ({ page, browser }) => { await openApp(page, "/?page=feed"); await toggleContentType(page, "includeLive"); await expect(page).toHaveURL(/[?&]live=/); const fresh = await bookmarked(browser, page); await expectContentType(fresh, "includeLive", true); await fresh.context().close(); }); test("Home's time budget", async ({ page, browser }) => { await openApp(page, "/?page=home"); await page.getByRole("button", { name: "An evening", exact: true }).click(); await expect(page).toHaveURL(/[?&]hb=long/); const fresh = await bookmarked(browser, page); await expect(fresh.getByRole("button", { name: "An evening", exact: true })).toHaveAttribute( "aria-pressed", "true", ); await fresh.context().close(); }); test("a Settings tab", async ({ page, browser }) => { await openApp(page, "/?page=feed"); await gotoPage(page, "settings"); await tab(page, "Notifications").click(); const fresh = await bookmarked(browser, page); await expect(tab(fresh, "Notifications")).toHaveAttribute("aria-selected", "true"); await fresh.context().close(); }); test("an admin page's tab", async ({ page, browser }) => { await openApp(page, "/?page=feed"); await page.getByTestId("nav-admin").click(); await page.getByTestId("nav-admin-users").click(); await tab(page, "Access requests").click(); const fresh = await bookmarked(browser, page); await expect(tab(fresh, "Access requests")).toHaveAttribute("aria-selected", "true"); await fresh.context().close(); }); test("the Channels manager's tab and name search", async ({ page, browser }) => { await openApp(page, "/?page=feed"); await gotoPage(page, "channels"); await tab(page, "Hidden").click(); await page.getByPlaceholder("Search channels…").fill("zz"); await expect(page).toHaveURL(/zz/); // written once the typing settles const fresh = await bookmarked(browser, page); await expect(tab(fresh, "Hidden")).toHaveAttribute("aria-selected", "true"); await expect(fresh.getByPlaceholder("Search channels…")).toHaveValue("zz"); await fresh.context().close(); }); test("the Files search", async ({ page, browser }) => { await openApp(page, "/?page=feed"); await gotoPage(page, "files"); await page.getByPlaceholder("Search files…").fill("zz"); await expect(page).toHaveURL(/zz/); const fresh = await bookmarked(browser, page); await expect(fresh.getByPlaceholder("Search files…")).toHaveValue("zz"); await fresh.context().close(); }); test("a channel page's own tab, over the page it was opened from", async ({ page, browser }) => { await openApp(page, "/?page=feed"); await expect(page.getByTestId("video-card").first()).toBeVisible(); expect(await clickVisibleChannelLink(page)).toBe(true); const title = await page.getByTestId("channel-title").textContent(); await tab(page, "About").click(); const fresh = await bookmarked(browser, page); await expect(fresh.getByTestId("channel-title")).toHaveText(title ?? ""); await expect(tab(fresh, "About")).toHaveAttribute("aria-selected", "true"); await fresh.context().close(); }); test("the player and the video it plays", async ({ page, browser }) => { await openApp(page, "/?page=feed"); await openFirstVideo(page); await expect(page).toHaveURL(/[?&]watch=/); const watch = new URL(page.url()).searchParams.get("watch"); const fresh = await bookmarked(browser, page); await expect(fresh.getByTestId("player-modal")).toBeVisible(); expect(new URL(fresh.url()).searchParams.get("watch")).toBe(watch); await fresh.context().close(); }); // The search itself never reaches YouTube here: the answer is the server's shape, served by the // test, and the request it answers is what the address named. test("a live YouTube search, its term and its count", async ({ page, browser }) => { const answer = async (p: Page, seen: string[]) => { await p.route("**/api/search/youtube?**", (route) => { seen.push(route.request().url()); return route.fulfill({ json: { items: [], next_cursor: null, source: "scrape" } }); }); }; await answer(page, []); await openApp(page, "/?page=feed"); await page.getByPlaceholder("Search your subscriptions…").fill("lofi"); await page.getByRole("button", { name: "Search YouTube", exact: true }).click(); await expect(page.getByText("YouTube results for “lofi”")).toBeVisible(); await expect(page).toHaveURL(/[?&]yt=lofi/); // named as it opens, not only once the count is set await page.getByRole("button", { name: "40", exact: true }).click(); await expect(page).toHaveURL(/[?&]ytn=40/); const seen: string[] = []; const fresh = await bookmarked(browser, page, (p) => answer(p, seen)); await expect(fresh.getByText("YouTube results for “lofi”")).toBeVisible(); await expect(fresh.getByRole("button", { name: "40", exact: true })).toHaveAttribute( "aria-pressed", "true", ); await expect.poll(() => seen.length).toBeGreaterThan(0); const asked = new URL(seen[0]!).searchParams; expect([asked.get("q"), asked.get("limit")]).toEqual(["lofi", "40"]); await fresh.context().close(); }); });