From d825aff30da7d63fa0e5588af5d0ceebbe5ef9dc Mon Sep 17 00:00:00 2001 From: npeter83 Date: Wed, 28 Oct 2026 22:04:06 +0100 Subject: [PATCH] fix(notifications): a row is named by what it is about, not its kind alone --- .../NotificationsPanel.order.dom.test.tsx | 23 ++++++++++++++++++- .../notifications/NotificationsPanel.tsx | 6 +++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/frontend/src/modules/notifications/NotificationsPanel.order.dom.test.tsx b/frontend/src/modules/notifications/NotificationsPanel.order.dom.test.tsx index 0f489b27..1e3ebc2c 100644 --- a/frontend/src/modules/notifications/NotificationsPanel.order.dom.test.tsx +++ b/frontend/src/modules/notifications/NotificationsPanel.order.dom.test.tsx @@ -223,7 +223,10 @@ describe("NotificationsPanel · order", () => { await act(async () => rerender()); expect(listUnder("inbox.sectionNeedsYou:1")).toEqual(["Activity 2"]); const button = screen.getByRole("button", { name: "inbox.markAllRead" }); - expect(button.hasAttribute("disabled")).toBe(false); + // Unavailable reads either way: natively while unfocused, aria-disabled while it holds the focus. + expect(button.hasAttribute("disabled") || button.getAttribute("aria-disabled") === "true").toBe( + false, + ); fireEvent.click(button); await act(async () => rerender()); expect(screen.queryByText(/inbox\.sectionNeedsYou/)).toBeNull(); @@ -266,4 +269,22 @@ describe("NotificationsPanel · order", () => { ); await waitFor(() => expect(listUnder("inbox.sectionNeedsYou:1")).toEqual(["Ready 1"])); }); + + it("names each row by what it is about, so two of one kind tell apart", async () => { + // A screen reader hears the name while the keyboard is on the row, and Back finds the row it + // left by it: "Download ready" alone was every download's name. + h.server = [server(1, 1 * H, true), server(2, 2 * H, true)]; + h.client = [client(3, 3 * H, { title: "Something broke", message: "Unexpected error." })]; + mount(); + await loaded(); + expect( + [...document.querySelectorAll("[data-nav-index]")].map((r) => + r.getAttribute("data-nav-name"), + ), + ).toEqual([ + "inbox.downloadDone.title: Ready 1", + "inbox.downloadDone.title: Ready 2", + "Something broke: Unexpected error.", + ]); + }); }); diff --git a/frontend/src/modules/notifications/NotificationsPanel.tsx b/frontend/src/modules/notifications/NotificationsPanel.tsx index a02c8b44..3ac8fae9 100644 --- a/frontend/src/modules/notifications/NotificationsPanel.tsx +++ b/frontend/src/modules/notifications/NotificationsPanel.tsx @@ -690,7 +690,9 @@ function NotificationRow({ } return (