31 lines
1.7 KiB
TypeScript
31 lines
1.7 KiB
TypeScript
import { fireEvent } from '@testing-library/react'
|
|
|
|
/** Exercise the visible menu while selecting the same value that the form will submit. */
|
|
export function selectOption(control: HTMLElement, value: string) {
|
|
const native = control.tagName === 'SELECT' ? control as HTMLSelectElement : control.parentElement?.querySelector('select')
|
|
if (!native) throw new Error('选择控件没有表单字段')
|
|
if (control.tagName === 'SELECT') return fireEvent.change(control, { target: { value } })
|
|
const options = Array.from(native.options).filter((option) => !option.hidden)
|
|
const index = options.findIndex((option) => option.value === value)
|
|
if (index < 0) throw new Error(`没有可选值:${value}`)
|
|
const menu = openSelect(control)
|
|
const option = menu?.querySelector<HTMLElement>(`[data-option-index="${index}"]`)
|
|
if (!option) throw new Error(`菜单没有可选值:${value}`)
|
|
fireEvent.click(option)
|
|
}
|
|
|
|
/** Text and file fields continue to use change; custom single selects use their real menu. */
|
|
export function changeField(element: Parameters<typeof fireEvent.change>[0], init: Parameters<typeof fireEvent.change>[1]) {
|
|
if (element instanceof HTMLElement && element.getAttribute('role') === 'combobox' && element.tagName === 'BUTTON') {
|
|
return selectOption(element, String((init as { target?: { value?: unknown } })?.target?.value ?? ''))
|
|
}
|
|
return fireEvent.change(element, init)
|
|
}
|
|
|
|
export function openSelect(control: HTMLElement) {
|
|
if (control.getAttribute('aria-expanded') !== 'true') { fireEvent.pointerDown(control); fireEvent.click(control) }
|
|
const menu = document.getElementById(control.getAttribute('aria-controls')!)
|
|
if (!menu) throw new Error('菜单未展开')
|
|
return menu
|
|
}
|