使用Jest测试React中Ant Design DatePicker的onChange方法
问题描述
如何访问Ant Design提供的DatePicker组件的onChange函数?测试该onChange函数时始终无法获取到对应方法,是否可以对该onChange函数进行测试?
业务代码 Deadline.js
export default function DeadlineView() { const [zieltermin, setZieltermin] = useState(false); const [startDate, setStartDate] = useState(""); const [priority, setPrioioty] = useState(""); const format = "HH:mm"; const [deadline, setdeadline] = useRecoilState(deadline_state); let object = { start_date: startDate, target_date: null, reminder_time: null, priority: null, }; return ( <> {" "} <Space direction="vertical"> <Space direction="horizontal"> <Paragraph>Anfangsdatum wählen</Paragraph> <DatePicker data-testid="datePicker" onChange={(e) => { onChangeStartDate(e.$y, e.$M + 1, e.$d.getDate(), setStartDate); }} /> </Space> <Space direction="horizontal"> <Paragraph>Zieltermin</Paragraph> <Switch data-testid="switch-slider" onChange={() => onChangeZieltermin("", zieltermin, setZieltermin)} /> </Space> <Space direction="horizontal"> <Paragraph>Erinnerungszeit</Paragraph> <TimePicker defaultValue={moment("12:08", format)} format={format} /> </Space> <Space direction="horizontal"> <Paragraph>Priorität</Paragraph> <Select data-testid="prio" showSearch placeholder="Priority" optionFilterProp="children" onChange={() => onChangePriority(setPrioioty, "")} filterOption={(input, option) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 } > <Select.Option value="1">1</Select.Option> <Select.Option value="2">2</Select.Option> <Select.Option value="3">3</Select.Option> </Select> </Space> </Space> </> ); }
关联工具函数
export function onChangeStartDate(year, month, day, setStartDate) { console.log(year + "." + month + "." + day); setStartDate(year + "." + month + "." + day); }
原有测试代码 Deadline.spec.js
it("funct", async () => { // act(async () => { renderHook(() => useRecoilValue(deadline_state), { wrapper: RecoilRoot, }); render( <AllProviders> <RecoilRoot> <DeadlineView /> </RecoilRoot> </AllProviders> ); const { getByTestId } = render(<DatePicker onChange={() => jest.fn()} />); const getDatePicker = getByTestId("datePicker"); expect(getDatePicker).toBeTruthy(); userEvent.change(getDatePicker, { target: { value: "2022-06-22" } }); const text = await screen.findByText(/2022-06-22/i); expect(text).toBeInTheDocument; // }); });
问题排查与解决方案
现有测试代码有三个核心问题,导致无法触发DatePicker的onChange:
- 重复渲染组件:第一次已经渲染了完整的
DeadlineView,后面又单独渲染了一个没有绑定业务逻辑的空DatePicker,后续所有操作都是针对这个单独渲染的无效组件,和业务代码里的DatePicker没有关联。 - 事件触发方式错误:Ant Design的DatePicker是封装的复合组件,直接用
userEvent.change给内部input传原生值,不会触发组件内部封装的onChange回调逻辑。 - 测试思路偏差:组件测试不需要主动获取组件内部定义的函数引用,只需要模拟用户真实操作,断言操作带来的页面表现/状态变化符合预期即可。
正确测试写法
import { render, screen, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import moment from 'moment'; import { RecoilRoot } from 'recoil'; // 自行引入项目对应的AllProviders、DeadlineView依赖 it("选择日期后正确更新起始日期", async () => { const user = userEvent.setup(); // 仅渲染一次包裹了所有依赖的业务组件,不要额外单独渲染DatePicker render( <AllProviders> <RecoilRoot> <DeadlineView /> </RecoilRoot> </AllProviders> ); // 取业务组件内的DatePicker输入框 const datePickerInput = screen.getByTestId("datePicker").querySelector('input'); expect(datePickerInput).toBeInTheDocument(); // 方案1:模拟真实用户交互,点击输入框唤起日期面板后选择目标日期 await user.click(datePickerInput); // AntD日期面板的单元格会自带格式为YYYY-MM-DD的title属性,直接定位即可 const targetDateCell = screen.getByTitle("2022-06-22"); await user.click(targetDateCell); // 断言输入框展示的日期符合onChange里拼接的 年.月.日 格式 expect(datePickerInput).toHaveValue("2022.6.22"); /* // 方案2:快速测试场景下可直接触发组件change事件,传入moment格式的日期值 const datePickerWrapper = screen.getByTestId("datePicker"); fireEvent.change(datePickerWrapper, { target: { value: moment("2022-06-22") } }) expect(datePickerInput).toHaveValue("2022.6.22"); */ });
额外优化建议
业务代码里直接读取moment对象的内部属性$y/$M/$d存在兼容风险,建议换成moment公开API调用,版本升级时不会出现异常:
<DatePicker data-testid="datePicker" onChange={(e) => { // 用公开API替代内部属性读取 onChangeStartDate(e.year(), e.month() + 1, e.date(), setStartDate); }} />
内容的提问来源于stack exchange,提问作者Adis_B
相关产品推荐
相关产品推荐

