2 changed files with 22 additions and 5 deletions
Showing only changes of commit ba83ad6df0 - Show all commits
+17 -2
View File
@@ -1,7 +1,7 @@
import { QueryClientProvider } from '@tanstack/react-query'
import { act, fireEvent, render, screen, waitFor, within } from '@testing-library/react'
import { createMemoryRouter, RouterProvider, useParams } from 'react-router'
import { afterEach, beforeEach, describe, expect, it, vi, type Mock } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, onTestFinished, vi, type Mock } from 'vitest'
import { ApiProvider, createApiClient, createQueryClient, createVerifiedSession } from '../api/index.ts'
import { createNetworkStatus } from '../pwa/networkStatus.ts'
import { stubAnimate, type FakeAnimation } from '../test/animate.ts'
@@ -685,7 +685,22 @@ describe('DiscoverPage', () => {
expect(sent(server.fetchMock)).toEqual(['DELETE /api/v1/dinners/q1'])
})
it('keeps focus in the confirmation, off its disabled buttons, while a removal is under way', async () => {
it.each([
['keeps a disabled button focused', false],
['moves focus off a disabled button to the page', true],
])('keeps focus in the confirmation, off its disabled buttons, while a removal is under way when the browser %s', async (_, fixup) => {
// Some browsers move focus from a control to the page as it is disabled.
const setAttribute = Element.prototype.setAttribute
if (fixup) {
vi.spyOn(Element.prototype, 'setAttribute').mockImplementation(function (this: Element, name, value) {
// jsdom ignores blur() on a disabled control, so focus leaves just before.
if (name === 'disabled' && this === document.activeElement && this instanceof HTMLElement) this.blur()
setAttribute.call(this, name, value)
})
}
onTestFinished(() => {
vi.restoreAllMocks()
})
const archive = deferred()
const server = stubQuestLog([PAD_THAI, GUMBO], { 'DELETE /api/v1/dinners/q1': () => archive.promise })
await renderPage()
+5 -3
View File
@@ -59,12 +59,14 @@ export function Confirm({
}: ConfirmProps) {
const titleId = useId()
const sheetRef = useRef<HTMLDivElement>(null)
// A focused button that becomes disabled loses focus to the page, outside
// the dialog; the dialog takes it instead.
// A focused button that becomes disabled either keeps focus while disabled or
// loses it to the page, depending on the browser; the dialog takes it instead.
useLayoutEffect(() => {
const dialog = sheetRef.current?.closest<HTMLElement>('[role="dialog"]')
if (!dialog) return
const active = document.activeElement
if (dialog && active instanceof HTMLElement && active.matches(':disabled') && dialog.contains(active)) dialog.focus()
const lost = active === null || active === document.body || (dialog.contains(active) && active.matches(':disabled'))
if (lost) dialog.focus()
}, [busy, dismissible])
function dismiss() {
if (dismissible) onCancel()