62 lines
3.6 KiB
TypeScript
62 lines
3.6 KiB
TypeScript
import { useState } from 'react'
|
||
import { act, fireEvent, render, screen, within } from '@testing-library/react'
|
||
import userEvent from '@testing-library/user-event'
|
||
import Select from './Select'
|
||
|
||
test('选项标签与提交值不同,仍调用原生表单回调并提交正确值', async () => {
|
||
const changed = jest.fn()
|
||
function Form() {
|
||
const [value, setValue] = useState('')
|
||
return <form aria-label="上传"><label htmlFor="method">出图方式</label><Select id="method" name="method" required value={value} onChange={(event) => { changed(event.target.value); setValue(event.currentTarget.value) }}><option value="">请选择</option><option value="photo">实拍</option><option value="ai">AI</option></Select></form>
|
||
}
|
||
const user = userEvent.setup()
|
||
render(<Form />)
|
||
await user.click(screen.getByRole('combobox', { name: '出图方式' }))
|
||
await user.click(screen.getByRole('option', { name: '实拍' }))
|
||
expect(changed).toHaveBeenCalledWith('photo')
|
||
expect(new FormData(screen.getByRole('form') as HTMLFormElement).get('method')).toBe('photo')
|
||
expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
|
||
expect(screen.getByRole('combobox')).toHaveFocus()
|
||
})
|
||
|
||
test('键盘跳过禁用选项,Escape 只关闭菜单并恢复焦点', async () => {
|
||
const user = userEvent.setup(), changed = jest.fn(), parentKey = jest.fn()
|
||
render(<div onKeyDown={parentKey}><Select aria-label="方式" defaultValue="photo" onChange={changed}><option value="photo">实拍</option><option value="disabled" disabled>禁用项</option><option value="ai">AI</option></Select></div>)
|
||
screen.getByRole('combobox').focus()
|
||
await user.keyboard('{ArrowDown}{ArrowDown}{Enter}')
|
||
expect(changed).toHaveBeenCalledTimes(1)
|
||
expect(screen.getByRole('combobox')).toHaveTextContent('AI')
|
||
await user.click(screen.getByRole('combobox'))
|
||
parentKey.mockClear()
|
||
await user.keyboard('{Escape}')
|
||
expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
|
||
expect(screen.getByRole('combobox')).toHaveFocus()
|
||
expect(parentKey).not.toHaveBeenCalled()
|
||
})
|
||
|
||
test('保留必填校验,原生校验失败将焦点交给可见控件', () => {
|
||
render(<form aria-label="表单"><Select required name="method" aria-label="方式" value=""><option value="">请选择</option><option value="ai">AI</option></Select></form>)
|
||
act(() => { expect((screen.getByRole('form') as HTMLFormElement).checkValidity()).toBe(false) })
|
||
expect(screen.getByRole('combobox')).toHaveFocus()
|
||
expect(screen.getByRole('combobox')).toHaveAttribute('aria-invalid', 'true')
|
||
})
|
||
|
||
test('支持回调内重置非受控字段与表单 reset', async () => {
|
||
const user = userEvent.setup()
|
||
const { container } = render(<form><Select name="method" defaultValue="" onChange={(event) => { event.target.value = '' }}><option value="">请选择</option><option value="ai">AI</option></Select></form>)
|
||
await user.click(screen.getByRole('combobox'))
|
||
await user.click(screen.getByRole('option', { name: 'AI' }))
|
||
expect(screen.getByRole('combobox')).toHaveTextContent('请选择')
|
||
fireEvent.reset(container.querySelector('form')!)
|
||
})
|
||
|
||
test('禁用状态不打开菜单;长选项和空列表也可显示', async () => {
|
||
const user = userEvent.setup()
|
||
const { rerender } = render(<Select disabled aria-label="方式"><option>实拍</option></Select>)
|
||
await user.click(screen.getByRole('combobox'))
|
||
expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
|
||
rerender(<Select aria-label="方式" />)
|
||
await user.click(screen.getByRole('combobox'))
|
||
expect(within(screen.getByRole('listbox')).getByText('暂无可选项')).toBeInTheDocument()
|
||
})
|