diff --git a/frontend/src/__tests__/dashboard.test.ts b/frontend/src/__tests__/dashboard.test.ts index 6167608a8..9130d35f4 100644 --- a/frontend/src/__tests__/dashboard.test.ts +++ b/frontend/src/__tests__/dashboard.test.ts @@ -742,6 +742,13 @@ describe('Dashboard Module', () => { expect(document.activeElement).toBe(viewBtn); }); + // #1653: opening the dialog must not put focus on the destructive action. + test('initial focus lands on Close, not Cancel Purchase', async () => { + const { modal } = await openDetails(); + expect(modal.querySelector('#cancel-purchase-detail-btn')).not.toBeNull(); + expect(document.activeElement?.id).toBe('close-purchase-details-btn'); + }); + test('Cancel Purchase uses the card confirm copy and sends one DELETE while in flight', async () => { const { modal } = await openDetails(); let finishDelete: () => void = () => {}; diff --git a/frontend/src/dashboard.ts b/frontend/src/dashboard.ts index 12fe45c1d..b069ddaa3 100644 --- a/frontend/src/dashboard.ts +++ b/frontend/src/dashboard.ts @@ -688,7 +688,8 @@ function viewPurchaseDetails(executionId: string): void { document.body.appendChild(modal); // Focus moves into the dialog, Tab is trapped, Escape closes it and focus // returns to View Details (#731). Every close path removes the element. - openModal(modal, { onClose: () => modal.remove() }); + // Initial focus goes to Close, not the destructive Cancel Purchase (#1653). + openModal(modal, { initialFocus: '#close-purchase-details-btn', onClose: () => modal.remove() }); } // buildUpcomingDetailsModal constructs the dialog via DOM-API, not diff --git a/frontend/tests-e2e/dialog-focus.spec.ts b/frontend/tests-e2e/dialog-focus.spec.ts index a4265d504..845fec162 100644 --- a/frontend/tests-e2e/dialog-focus.spec.ts +++ b/frontend/tests-e2e/dialog-focus.spec.ts @@ -50,7 +50,9 @@ test('upcoming purchase details dialog takes focus, closes on Escape and restore const dialog = page.getByRole('dialog', { name: 'Upcoming Purchase Details' }); await expect(dialog).toBeVisible(); - expect(await page.evaluate(() => !!document.getElementById('purchase-details-modal')?.contains(document.activeElement))).toBe(true); + // #1653: the safe Close button takes focus, not the destructive Cancel Purchase. + await expect(dialog.locator('#cancel-purchase-detail-btn')).toBeVisible(); + await expect(dialog.locator('#close-purchase-details-btn')).toBeFocused(); expect(await tabStaysInside(page, '#purchase-details-modal', 5)).toBe(true); await page.keyboard.press('Escape');