test(e4): lock accessible names on the Plex card buttons
Closes the re-review's test-coverage finding: a plexCards.dom.test asserting the
icon-only card controls (watched-toggle, Info, add-season/episode) each expose
their aria-label as an accessible name via getByRole({name}). A future edit that
drops a label now fails the gate instead of silently reopening the unnamed-button
gap the a11y sweep closed.
4 tests; full FE gate green (tsc/eslint/prettier/knip, 321 vitest).
This commit is contained in:
@@ -0,0 +1,82 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
//
|
||||||
|
// Plex card a11y: locks the accessible names on the icon-only card controls (the E4 a11y sweep). These
|
||||||
|
// buttons are icon-only (WatchedIcon / Info / ListPlus, no text), so their name comes solely from the
|
||||||
|
// aria-label — a dropped label silently reintroduces an unnamed button for screen-reader users. i18n is
|
||||||
|
// key-passthrough, so the asserted names are the i18n keys.
|
||||||
|
import { describe, it, expect, afterEach, vi } from "vitest";
|
||||||
|
import { render, screen, cleanup } from "@testing-library/react";
|
||||||
|
|
||||||
|
vi.mock("react-i18next", async (importOriginal) => {
|
||||||
|
const actual = await importOriginal<typeof import("react-i18next")>();
|
||||||
|
return { ...actual, useTranslation: () => ({ t: (key: string) => key }) };
|
||||||
|
});
|
||||||
|
|
||||||
|
import { PlexPosterCard, SeasonCard, EpisodeCard } from "./plexCards";
|
||||||
|
import type { PlexCard, PlexSeasonDetail } from "../lib/api";
|
||||||
|
|
||||||
|
const movie = (status?: string): PlexCard => ({
|
||||||
|
id: "1",
|
||||||
|
type: "movie",
|
||||||
|
title: "M",
|
||||||
|
thumb: "",
|
||||||
|
status,
|
||||||
|
});
|
||||||
|
const episode = (status?: string): PlexCard => ({
|
||||||
|
id: "e1",
|
||||||
|
type: "episode",
|
||||||
|
title: "E1",
|
||||||
|
thumb: "",
|
||||||
|
status,
|
||||||
|
});
|
||||||
|
const season = (status = "new"): PlexSeasonDetail => ({
|
||||||
|
id: "s1",
|
||||||
|
season_number: 1,
|
||||||
|
title: "S1",
|
||||||
|
thumb: "",
|
||||||
|
episode_count: 3,
|
||||||
|
status,
|
||||||
|
episodes: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(cleanup);
|
||||||
|
|
||||||
|
describe("PlexPosterCard a11y", () => {
|
||||||
|
it("names the watched-toggle (mark-watched when unwatched) and the info button", () => {
|
||||||
|
render(
|
||||||
|
<PlexPosterCard card={movie()} onOpen={vi.fn()} onInfo={vi.fn()} onToggleWatched={vi.fn()} />,
|
||||||
|
);
|
||||||
|
expect(screen.getByRole("button", { name: "plex.markWatched" })).toBeTruthy();
|
||||||
|
expect(screen.getByRole("button", { name: "plex.info.title" })).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("names the watched-toggle as mark-unwatched when the movie is watched", () => {
|
||||||
|
render(
|
||||||
|
<PlexPosterCard
|
||||||
|
card={movie("watched")}
|
||||||
|
onOpen={vi.fn()}
|
||||||
|
onInfo={vi.fn()}
|
||||||
|
onToggleWatched={vi.fn()}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
expect(screen.getByRole("button", { name: "plex.markUnwatched" })).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("SeasonCard a11y", () => {
|
||||||
|
it("names the watched-toggle and the add-season button", () => {
|
||||||
|
render(<SeasonCard se={season()} onOpen={vi.fn()} onToggleWatched={vi.fn()} onAdd={vi.fn()} />);
|
||||||
|
expect(screen.getByRole("button", { name: "plex.series.markSeasonWatched" })).toBeTruthy();
|
||||||
|
expect(screen.getByRole("button", { name: "plex.playlist.addSeason" })).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("EpisodeCard a11y", () => {
|
||||||
|
it("names the watched-toggle and the add-episode button", () => {
|
||||||
|
render(
|
||||||
|
<EpisodeCard ep={episode()} onPlay={vi.fn()} onToggleWatched={vi.fn()} onAdd={vi.fn()} />,
|
||||||
|
);
|
||||||
|
expect(screen.getByRole("button", { name: "plex.markWatched" })).toBeTruthy();
|
||||||
|
expect(screen.getByRole("button", { name: "plex.playlist.addEpisode" })).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user