Adapt to two contract changes master introduced: - The generated Remote face now wraps every business result in RemoteResult, folding carrier failures into an ok:false branch instead of rejecting. The controller reads that envelope at its three call sites and maps a carrier failure onto the same settled shape the controls already render; three specs cover the new branch. - Client packages split their tsconfig into host and client halves, and the host aggregate now compiles any test not named *.client.spec.*. Rename this package's specs to the client convention and drop the ../connection project reference, which pointed at a solution file that no longer carries the client sources. Keep master's mount loop with its rollback-on-failure in api-remotes and add messageFeedbackRemote to it.
51 lines
2.0 KiB
TypeScript
51 lines
2.0 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
import { cleanup, fireEvent, render } from '@testing-library/react'
|
|
import { ImageLightbox } from '../src/ImageLightbox.tsx'
|
|
|
|
afterEach(cleanup)
|
|
|
|
const labels = { dialog: '原图预览', close: '关闭原图预览' }
|
|
|
|
describe('ImageLightbox', () => {
|
|
it('focuses its close control, closes by button and Escape, and restores focus', () => {
|
|
const opener = document.createElement('button')
|
|
document.body.appendChild(opener)
|
|
opener.focus()
|
|
const onClose = vi.fn()
|
|
const view = render(<ImageLightbox src="blob:original" alt="原图" labels={labels} onClose={onClose} />)
|
|
const close = view.getByRole('button', { name: '关闭原图预览' })
|
|
expect(document.activeElement).toBe(close)
|
|
fireEvent.keyDown(window, { key: 'a' })
|
|
expect(onClose).not.toHaveBeenCalled()
|
|
fireEvent.keyDown(window, { key: 'Escape' })
|
|
fireEvent.click(close)
|
|
expect(onClose).toHaveBeenCalledTimes(2)
|
|
view.unmount()
|
|
expect(document.activeElement).toBe(opener)
|
|
opener.remove()
|
|
})
|
|
|
|
it('tolerates a focus owner it cannot restore (no active element at mount)', () => {
|
|
// jsdom always reports body as the fallback active element; stub the
|
|
// element-less state a detached focus can leave.
|
|
Object.defineProperty(document, 'activeElement', { configurable: true, get: () => null })
|
|
try {
|
|
const view = render(<ImageLightbox src="blob:original" alt="原图" labels={labels} onClose={vi.fn()} />)
|
|
view.unmount()
|
|
} finally {
|
|
delete (document as { activeElement?: unknown }).activeElement
|
|
}
|
|
})
|
|
|
|
it('closes on a backdrop press but not on a press over the image', () => {
|
|
const onClose = vi.fn()
|
|
const view = render(<ImageLightbox src="blob:original" alt="原图" labels={labels} onClose={onClose} />)
|
|
fireEvent.mouseDown(view.getByRole('img'))
|
|
expect(onClose).not.toHaveBeenCalled()
|
|
fireEvent.mouseDown(view.getByRole('dialog', { name: '原图预览' }))
|
|
expect(onClose).toHaveBeenCalledTimes(1)
|
|
})
|
|
})
|