// @vitest-environment jsdom // // A side panel's groups in edit mode move without a drag too (WCAG 2.5.7): each carries an Up / Down // pair, named by its group, and a move lands in the stored order. import { describe, it, expect, vi, afterEach } from "vitest"; import { render, screen, fireEvent, cleanup, within } from "@testing-library/react"; vi.mock("react-i18next", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, useTranslation: () => ({ t: (key: string, o?: { name?: string }) => (o?.name ? `${key}:${o.name}` : key), }), }; }); import PanelGroups, { type PanelItem } from "./PanelGroups"; import type { PanelLayout } from "../../lib/panelLayout"; afterEach(cleanup); const items: PanelItem[] = ["a", "b", "c"].map((id) => ({ id, title: `Group ${id}`, body:

{id} body

, })); const layout = (order: string[]): PanelLayout => ({ order, collapsed: {}, hidden: {} }); function mount(order: string[], editing = true) { const setLayout = vi.fn(); render( , ); const pair = (title: string) => screen.getByRole("group", { name: new RegExp(title) }); const btn = (title: string, name: string) => within(pair(title)).getByRole("button", { name }) as HTMLButtonElement; return { setLayout, btn }; } describe("PanelGroups — reordering without a drag", () => { it("moves a group up or down, the ends held off", () => { const { setLayout, btn } = mount(["a", "b", "c"]); expect(btn("Group a", "common.order.up").disabled).toBe(true); expect(btn("Group c", "common.order.down").disabled).toBe(true); fireEvent.click(btn("Group a", "common.order.down")); expect(setLayout).toHaveBeenLastCalledWith(expect.objectContaining({ order: ["b", "a", "c"] })); fireEvent.click(btn("Group c", "common.order.up")); expect(setLayout).toHaveBeenLastCalledWith(expect.objectContaining({ order: ["a", "c", "b"] })); }); it("moves a group the stored order does not hold yet", () => { // "c" became available after the layout was saved: it renders last, and still moves. const { setLayout, btn } = mount(["a", "b"]); fireEvent.click(btn("Group c", "common.order.up")); expect(setLayout).toHaveBeenLastCalledWith(expect.objectContaining({ order: ["a", "c", "b"] })); }); it("offers no move outside edit mode", () => { mount(["a", "b", "c"], false); expect(screen.queryByRole("button", { name: "common.order.up" })).toBeNull(); }); }); // Every group's grip was "Drag to reorder" — a screen reader heard the same name five // times and could not tell which group it would lift. It names its group, as the playlist grips do. describe("PanelGroups — the drag grip", () => { it("is named by its group", () => { mount(["a", "b", "c"]); expect(screen.getByRole("button", { name: "common.order.dragNamed:Group b" })).toBeTruthy(); }); });