fix(plex): the player's ⋯ and tracks lists are real menus, and every close returns the focus
They were hand-built divs: no menu roles, no arrow keys, and Escape left the focus on <body>. Both run on the popover engine now (media-tone rows), and the tuning panel is a labelled dialog that takes the focus and hands it back to ⋯.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
// the round-3 comment that handed the step prompt's trap to "the dialog below" assumed this one did
|
||||
// too. Its own file because `layerStack` is module state and these tests push into it.
|
||||
import { describe, it, expect, vi, beforeAll, afterEach } from "vitest";
|
||||
import { render, cleanup, waitFor, act } from "@testing-library/react";
|
||||
import { render, cleanup, waitFor, act, screen } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
|
||||
vi.mock("react-i18next", async (importOriginal) => ({
|
||||
@@ -116,6 +116,17 @@ const press = (key: string, shiftKey = false) =>
|
||||
);
|
||||
});
|
||||
|
||||
// A menu's rows are named by their text: the surface is `visibility: hidden` until floating-ui has
|
||||
// measured it (never, under jsdom), and a hidden element's accessible name is empty.
|
||||
const menuItem = (label: string) =>
|
||||
waitFor(() => {
|
||||
const row = screen
|
||||
.queryAllByRole("menuitem", { hidden: true })
|
||||
.find((b) => b.textContent === label);
|
||||
expect(row).toBeDefined();
|
||||
return row!;
|
||||
});
|
||||
|
||||
describe("PlexPlayer · Tab stays inside the player", () => {
|
||||
it("pulls the focus back in when it is on the page behind", async () => {
|
||||
await mount();
|
||||
@@ -160,9 +171,10 @@ describe("PlexPlayer · Tab stays inside the player", () => {
|
||||
const more = buttons().find((b) => b.getAttribute("aria-label") === "plex.player.more");
|
||||
expect(more).toBeDefined();
|
||||
act(() => more!.click());
|
||||
const settings = buttons().find((b) => b.textContent === "plex.player.settings");
|
||||
expect(settings).toBeDefined();
|
||||
act(() => settings!.click());
|
||||
// The ⋯ is a menu on the popover engine: it portals out of the player and traps for itself.
|
||||
const settings = await menuItem("plex.player.settings");
|
||||
act(() => settings.click());
|
||||
await screen.findByRole("dialog", { name: "plex.player.settings" });
|
||||
const items = buttons();
|
||||
// The panel really opened — the trap now has to span its controls too.
|
||||
expect(items.length).toBeGreaterThan(before + 3);
|
||||
|
||||
Reference in New Issue
Block a user