test: a list key waits for the list's registration, not only its rows
gate / frontend (push) Successful in 6m5s
gate / backend (push) Successful in 7m10s
gate / frontend (push) Successful in 6m5s
gate / backend (push) Successful in 7m10s
The server gate's frontend job went red on 0.96.0: PlexPlaylistView's j/Delete test pressed j after the rows painted but before useListNav's passive effect registered the list, so the key did nothing on the slower runner. Every test that presses a list key after an async load now waits for [data-nav-list] on its list first (PlexPlaylistView, Playlists, Home, PlexDiscover). Checked against a 30 ms delayed registration: the old tests fail, the new ones pass.
This commit is contained in:
@@ -424,6 +424,10 @@ describe("Playlists — removing a row, and undoing it", () => {
|
||||
.map((c) => c[0] as { message: string; action?: { label: string; onClick: () => void } })
|
||||
.filter((n) => n.message?.startsWith("playlists.removedToast"))
|
||||
.pop()!;
|
||||
// The list's keys are live once its effect has registered it (`data-nav-list`), a passive effect that
|
||||
// can run AFTER the rows are on screen: a key pressed on a slow machine in between did nothing (CI flake).
|
||||
const keysLiveOn = (el: Element) =>
|
||||
waitFor(() => expect(el.closest("[data-nav-list]")).not.toBeNull());
|
||||
const pressKey = (key: string) =>
|
||||
act(() => {
|
||||
(document.activeElement ?? document.body).dispatchEvent(
|
||||
@@ -497,7 +501,7 @@ describe("Playlists — removing a row, and undoing it", () => {
|
||||
const lists = { 1: [vid("A", 0), vid("B", 0), vid("C", 0)] };
|
||||
serverRemoves(lists);
|
||||
mount(lists);
|
||||
await screen.findByRole("button", { name: "card.play — Video C" });
|
||||
await keysLiveOn(await screen.findByRole("button", { name: "card.play — Video C" }));
|
||||
pressKey("j");
|
||||
pressKey("j");
|
||||
expect(document.activeElement?.textContent).toContain("Video B");
|
||||
@@ -511,7 +515,7 @@ describe("Playlists — removing a row, and undoing it", () => {
|
||||
vi.spyOn(api, "removeFromPlaylist").mockResolvedValue(undefined as never);
|
||||
h.selectedId = WATCH_LATER;
|
||||
mount({ [WATCH_LATER]: [vid("A", 0), vid("B", 0)] });
|
||||
await screen.findByRole("button", { name: "card.play — Video B" });
|
||||
await keysLiveOn(await screen.findByRole("button", { name: "card.play — Video B" }));
|
||||
pressKey("j");
|
||||
pressKey("Delete");
|
||||
await act(async () => void (await new Promise((r) => setTimeout(r, 20))));
|
||||
@@ -617,7 +621,9 @@ describe("Playlists · a narrow table", () => {
|
||||
describe("Playlists — the rows are a keyboard list", () => {
|
||||
it("walks the rows with j and plays the focused one on Enter", async () => {
|
||||
mount({ 1: [vid("A", 0), vid("B", 0)] });
|
||||
await screen.findByRole("button", { name: "card.play — Video B" });
|
||||
const row = await screen.findByRole("button", { name: "card.play — Video B" });
|
||||
// The keys are live once the list's effect registers it, which can land after the rows paint.
|
||||
await waitFor(() => expect(row.closest("[data-nav-list]")).not.toBeNull());
|
||||
const press = (key: string) =>
|
||||
act(() => {
|
||||
(document.activeElement ?? document.body).dispatchEvent(
|
||||
|
||||
Reference in New Issue
Block a user