// @vitest-environment jsdom // // The Browse grid's toolbar, the feed's in Plex: the watch-state pill and Sort name their group by a // glyph (the word in the tooltip and the accessible name), and Sort ends the filters' row instead of // taking a row of its own. import { describe, it, expect, vi, beforeAll, beforeEach, afterEach } from "vitest"; import { render, screen, cleanup } from "@testing-library/react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; vi.mock("react-i18next", async (importOriginal) => ({ ...(await importOriginal()), useTranslation: () => ({ t: (key: string) => key, i18n: { language: "en" } }), })); vi.mock("./plexSavedViews", async (importOriginal) => ({ ...(await importOriginal()), usePlexSavedViews: () => ({ views: [], displayView: null, isDirty: false, activeViewId: null }), })); import PlexBrowse from "./PlexBrowse"; import { api } from "../../lib/api"; import { PageToolbarSlot } from "../../components/ui/pageToolbarSlot"; beforeAll(() => { class Stub { observe() {} unobserve() {} disconnect() {} takeRecords() { return []; } } globalThis.ResizeObserver ??= Stub as unknown as typeof ResizeObserver; globalThis.IntersectionObserver ??= Stub as unknown as typeof IntersectionObserver; }); beforeEach(() => window.history.replaceState({ _sub: { kind: "grid" }, _subOf: "v" }, "")); afterEach(() => { cleanup(); vi.restoreAllMocks(); }); const slot = document.body.appendChild(document.createElement("div")); async function mount() { vi.spyOn(api, "plexLibrary").mockResolvedValue({ items: [], total: 0, offset: 0 } as never); const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } }); render( , ); return screen.findByTestId("plex-show"); } // The group's glyph, not the trigger's own chevron: the glyph sits in its aria-hidden wrapper. const glyph = (el: HTMLElement) => el.querySelector('[aria-hidden="true"] > svg'); const sortTrigger = () => screen .getAllByRole("button") .find((b) => b.getAttribute("aria-label")?.startsWith("plex.filter.sort:"))!; describe("PlexBrowse toolbar", () => { it("the watch-state pill shows a glyph, not its group's word, and names itself", async () => { const pill = await mount(); // The key of a value ("plex.filter.showOpt.all") holds the group's key: test the visible text. expect(pill.textContent).toBe("plex.filter.showOpt.all"); expect(glyph(pill)).not.toBeNull(); expect(pill.getAttribute("title")).toBe("plex.filter.show"); expect(pill.getAttribute("aria-label")).toMatch(/^plex\.filter\.show: /); }); it("Sort shows a glyph, names itself, and ends the filters' row", async () => { const pill = await mount(); const sort = sortTrigger(); expect(sort.textContent).not.toContain("plex.filter.sort"); expect(glyph(sort)).not.toBeNull(); expect(sort.getAttribute("title")).toBe("plex.filter.sort"); expect(pill.parentElement!.contains(sort)).toBe(true); }); });