diff --git a/frontend/src/components/ui/Modal.dom.test.tsx b/frontend/src/components/ui/Modal.dom.test.tsx index 85facf5c..4169ed69 100644 --- a/frontend/src/components/ui/Modal.dom.test.tsx +++ b/frontend/src/components/ui/Modal.dom.test.tsx @@ -375,6 +375,36 @@ describe("Modal focus trap (offsetParent stubbed 'visible')", () => { document.body.removeChild(portal); }); + it("does not pull the focus out of a menu that stays open when it closes on its own", () => { + // The other side of counting a menu row as held: a menu that is NOT this dialog's — a page's + // "…" left open while a dialog finishes in the background — stays standing, and a dialog that + // closes on its own (a write's success) must not take the focus from it to its trigger. + const trigger = document.createElement("button"); + document.body.appendChild(trigger); + trigger.focus(); + const portal = document.createElement("div"); + portal.setAttribute("data-floating-ui-portal", ""); + const row = document.createElement("button"); + row.textContent = "page-menu-row"; + portal.appendChild(row); + document.body.appendChild(portal); + function SelfClosing() { + const [open, setOpen] = useState(true); + return open ? ( + {}}> + + + ) : null; + } + render(); + row.focus(); + act(() => void screen.getByText("finish").click()); // `.click()` moves no focus + expect(screen.queryByText("finish")).toBeNull(); + expect(document.activeElement).toBe(row); + document.body.removeChild(trigger); + document.body.removeChild(portal); + }); + it("leaves the focus alone when the user moved it out of the dialog themselves", () => { // The other half of the same rule, and the branch nothing drove: taking focus back from where // the user deliberately put it is the rudest thing a closing dialog can do.