fix(plex): the player's settings panel is a tab list with named, touch-sized rows
- Its section switch is `ui/Tabs` (new `tone="media"` paint for the dark chrome) with a wired tabpanel; the panel opens with the focus on the selected tab. - On/off rows are `CheckRow` (the whole row, 44 on touch), the "no background" checkbox too. - Every slider and the four colour wells carry the name their row shows. - The clock's date-style buttons reach the touch target.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
// @vitest-environment jsdom
|
||||
//
|
||||
// E28 review D5 + L5 + D6: the Plex player's settings panel. Its section switch was a row of
|
||||
// `aria-pressed` buttons (now an ARIA tab list on `ui/Tabs`), its rows sat under the 44 touch target,
|
||||
// its on/off rows were a hand-laid label (now `CheckRow`), and its sliders and colour wells had no
|
||||
// accessible name — the visible label beside them was not tied to them.
|
||||
import { useRef, useState } from "react";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
||||
|
||||
vi.mock("react-i18next", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("react-i18next")>()),
|
||||
useTranslation: () => ({ t: (k: string) => k }),
|
||||
}));
|
||||
|
||||
import { PlexPlayerSettings } from "./PlexPlayerSettings";
|
||||
import { DEFAULT_PREFS, type PlexPlayerPrefs } from "../lib/plexPlayerPrefs";
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
type Tab = "sync" | "playback" | "subtitle" | "clock";
|
||||
const TABS: { key: Tab; label: string }[] = [
|
||||
{ key: "sync", label: "Sync" },
|
||||
{ key: "playback", label: "Playback" },
|
||||
{ key: "subtitle", label: "Subtitles" },
|
||||
{ key: "clock", label: "Clock" },
|
||||
];
|
||||
|
||||
function Harness({ start = "sync" as Tab, prefs: initial = {} as Partial<PlexPlayerPrefs> }) {
|
||||
const [tab, setTab] = useState<Tab>(start);
|
||||
const [prefs, setPrefs] = useState<PlexPlayerPrefs>({ ...DEFAULT_PREFS, ...initial });
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
const back = useRef<HTMLElement>(null);
|
||||
return (
|
||||
<PlexPlayerSettings
|
||||
menuRef={menuRef}
|
||||
returnFocusTo={back}
|
||||
settingsTabs={TABS}
|
||||
activeTab={tab}
|
||||
setSettingsTab={setTab}
|
||||
prefs={prefs}
|
||||
patchPrefs={(p) => setPrefs((cur) => ({ ...cur, ...p }))}
|
||||
changeAudioOffset={() => {}}
|
||||
now={new Date(2026, 8, 27, 12, 0)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const tab = (name: string) => screen.getByRole("tab", { name });
|
||||
|
||||
describe("the Plex player's settings panel", () => {
|
||||
it("switches its sections as a tab list, the focus on the selected tab", () => {
|
||||
render(<Harness start="subtitle" />);
|
||||
expect(screen.getByRole("tablist")).toBeTruthy();
|
||||
expect(document.activeElement).toBe(tab("Subtitles"));
|
||||
fireEvent.keyDown(document.activeElement!, { key: "ArrowRight" });
|
||||
expect(tab("Clock").getAttribute("aria-selected")).toBe("true");
|
||||
expect(screen.getByRole("tabpanel", { name: "Clock" })).toBeTruthy();
|
||||
});
|
||||
|
||||
it("gives every slider and colour well the name its row shows", () => {
|
||||
render(<Harness start="subtitle" prefs={{ subBg: "#000000", subShadow: 2 }} />);
|
||||
for (const name of ["plex.player.subSize", "plex.player.subPos", "plex.player.subShadow"])
|
||||
expect(screen.getByRole("slider", { name })).toBeTruthy();
|
||||
for (const name of ["plex.player.subColor", "plex.player.subBg", "plex.player.subShadowColor"])
|
||||
expect(screen.getByLabelText(name).getAttribute("type")).toBe("color");
|
||||
fireEvent.click(tab("Clock"));
|
||||
expect(screen.getByLabelText("plex.player.clockColor").getAttribute("type")).toBe("color");
|
||||
});
|
||||
|
||||
it("lays its on/off rows on CheckRow and its buttons at the touch target", () => {
|
||||
render(<Harness start="clock" prefs={{ clockDate: true }} />);
|
||||
const row = screen.getByRole("checkbox", { name: "plex.player.clockShow" }).closest("label")!;
|
||||
expect(row.className).toContain("pointer-coarse:min-h-(--touch-target)");
|
||||
for (const b of screen.getAllByRole("button")) expect(b.className).toContain("touch-target");
|
||||
for (const t of screen.getAllByRole("tab")) expect(t.className).toContain("touch-target");
|
||||
fireEvent.click(tab("Subtitles"));
|
||||
const none = screen.getByRole("checkbox", { name: "plex.player.subBgNone" }).closest("label")!;
|
||||
expect(none.className).toContain("pointer-coarse:min-h-(--touch-target)");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user