// @vitest-environment jsdom // // The `list` key scope โ€” what puts j/k, the arrows and Enter on the cheat sheet โ€” is live only while a // registered list has an item to land on. An empty download queue, a list still loading or one that // failed mounts its container all the same, and the sheet listed the keys over nothing (deep-review // E11 round 2). Its own file: listNav keeps module state. import { useRef } from "react"; import { afterEach, describe, expect, it } from "vitest"; import { cleanup, render, screen, waitFor } from "@testing-library/react"; import { navItemAttrs, useListNav } from "./listNav"; import { useActiveScopes } from "./keymap"; afterEach(cleanup); function Scopes() { return {useActiveScopes().join(" ")}; } function Queue({ count, onDelete }: { count: number; onDelete?: (i: number) => void }) { const ref = useRef(null); useListNav(ref, { enabled: true, onDelete }); return (
{count === 0 ? (

Nothing queued

) : ( Array.from({ length: count }, (_, i) => (
item
)) )}
); } const page = (count: number, onDelete?: (i: number) => void) => ( <> ); const scopes = () => screen.getByTestId("scopes").textContent!.split(" "); describe("useListNav ยท the list key scope", () => { it("is not live over a list with nothing in it, and is while it has items", async () => { const { rerender } = render(page(0)); expect(scopes()).not.toContain("list"); rerender(page(2)); await waitFor(() => expect(scopes()).toContain("list")); rerender(page(0)); await waitFor(() => expect(scopes()).not.toContain("list")); }); // E28 S3e2: Delete is on the sheet only where a list can take an item out โ€” a playlist's rows, not // the feed or a Plex grid, where nothing answers it. it("puts Delete on the sheet only for a list that removes items", async () => { const { rerender } = render(page(2)); await waitFor(() => expect(scopes()).toContain("list")); expect(scopes()).not.toContain("listDelete"); rerender(page(2, () => {})); await waitFor(() => expect(scopes()).toContain("listDelete")); rerender(page(0, () => {})); await waitFor(() => expect(scopes()).not.toContain("listDelete")); }); });