// @vitest-environment jsdom // // The playlists module shows fewer lists than youtube.com, and said nothing about why, so it read as // a Siftlode bug (debt burn A3). One quiet line at the foot of the rail; "Why?" opens the three facts. import { describe, it, expect, vi, afterEach, beforeAll } from "vitest"; import { render, screen, fireEvent, cleanup } from "@testing-library/react"; import { FloatingTree } from "@floating-ui/react"; vi.mock("react-i18next", () => ({ useTranslation: () => ({ t: (k: string) => k }) })); import PlaylistLimitsHint from "./PlaylistLimitsHint"; // Same floating-ui recipe as ContextMenu.dom.test.tsx: stub the observers, and query with // `hidden: true` — floating-ui never positions in jsdom, so the surface stays visibility:hidden. beforeAll(() => { class Stub { observe() {} unobserve() {} disconnect() {} takeRecords() { return []; } } globalThis.ResizeObserver ??= Stub as unknown as typeof ResizeObserver; globalThis.IntersectionObserver ??= Stub as unknown as typeof IntersectionObserver; }); afterEach(cleanup); describe("PlaylistLimitsHint", () => { it("keeps the facts behind Why?, and opens them as a named dialog", async () => { render( , ); expect(screen.getByText("playlists.limits.hint")).toBeTruthy(); expect(screen.queryByRole("dialog", { hidden: true })).toBeNull(); fireEvent.click(screen.getByRole("button", { name: "playlists.limits.why" })); const dialog = await screen.findByRole("dialog", { hidden: true }); // Read off the attribute: jsdom computes no name for a visibility:hidden element. expect(dialog.getAttribute("aria-label")).toBe("playlists.limits.title"); for (const fact of ["closed", "ownOnly", "noChannel"]) expect(dialog.textContent).toContain(`playlists.limits.${fact}`); }); });