如何使用Jest和React Testing Library为Kendo DropDownList编写单元测试?
Kendo React DropDownList 单元测试解决方案
错误原因
报错由三个核心问题导致:
- 组件本身存在语法错误,
DropDownList的defaultValue属性格式错误,会导致组件渲染异常 - Kendo React 下拉组件的选项列表默认通过Portal挂载到
document.body下,不在下拉触发元素的DOM子树内,你限定查询范围为下拉元素本身自然找不到选项元素,就会触发找不到DOM元素的报错 - 未处理异步渲染逻辑,下拉列表展开是异步行为,直接同步查询会找不到元素
第一步:修正组件代码
先修复DropDownList的属性错误,且受控组件不需要额外设置defaultValue,修正后的组件如下:
import React, {useState} from 'react' import {DropDownList} from "@progress/kendo-react-dropdowns" import '@progress/kendo-theme-default/dist/all.css' const Filter = () => { const [QS,setQS] = useState({id:0,name:"All"}) const options=[{id:0,name:"All"},{id:1,name:"red"},{id:2,name:"green"}] return ( <div className="filter"> <DropDownList title="QSDropdown" data={options} value={QS} dataItemKey="id" textField="name" onChange={(event)=>{ setQS(event.target.value) }} /> </div> ) } export default Filter
第二步:修正测试代码
使用RTL的全局screen查询适配Portal渲染,加上异步等待逻辑处理下拉加载:
版本1:使用fireEvent
import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import Filter from '../Components/Filter'; const options = [{id:0,name:"All"},{id:1,name:"red"},{id:2,name:"green"}]; it('can change the value of the dropdown', async () => { render(<Filter />); const dropdownInput = screen.getByTitle("QSDropdown"); // 触发下拉展开 fireEvent.click(dropdownInput); // 全局查询下拉选项,hidden:true匹配Kendo默认隐藏的选项元素 const dropdownOptions = await screen.findAllByRole('option', { hidden: true }); // 点击第二个选项 fireEvent.click(dropdownOptions[1]); // 验证值更新 await waitFor(() => { expect(dropdownInput).toHaveValue(options[1].name); }); });
版本2:使用userEvent(更贴近真实用户操作,更稳定)
需要先安装依赖:npm install @testing-library/user-event --save-dev
import { render, screen, waitFor } from "@testing-library/react"; import userEvent from '@testing-library/user-event'; import Filter from '../Components/Filter'; const options = [{id:0,name:"All"},{id:1,name:"red"},{id:2,name:"green"}]; it('can change the value of the dropdown', async () => { const user = userEvent.setup(); render(<Filter />); const dropdownInput = screen.getByTitle("QSDropdown"); await user.click(dropdownInput); const dropdownOptions = await screen.findAllByRole('option', { hidden: true }); await user.click(dropdownOptions[1]); await waitFor(() => { expect(dropdownInput).toHaveValue(options[1].name); }); });
内容的提问来源于stack exchange,提问作者Chaya
相关产品推荐
相关产品推荐

