如何在Jest中修改MUI X Date Picker(x-date-pickers)的值?
无法通过Jest修改MUI X DatePicker组件值的问题解决
问题描述
基于@mui/x-date-pickers封装的DatePickerX组件在UI中运行正常,但所有Jest测试用例都无法修改日期值。
封装的组件代码
import React, { useState } from 'react'; import { DatePicker } from '@mui/x-date-pickers'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import AdapterDateFns from '@mui/lab/AdapterDateFns'; import { de } from 'date-fns/locale'; import { TextField } from '@mui/material'; export const DatePickerX: React.FC = () => { const [date, setDate] = useState<Date>(new Date()); const changeDate = (newDate: Date | null) => { if (newDate) { setDate(newDate); } }; return ( <> <LocalizationProvider locale={de} dateAdapter={AdapterDateFns}> <DatePicker label="datepicker_label" value={date} inputFormat="yyyy/MM/dd" views={['year', 'month', 'day']} mask="____/__/__" onChange={changeDate} renderInput={(params) => ( <TextField type="text" {...params} data-testid="textInput_testid" name="textInput_name"/> )} /> </LocalizationProvider> </> ); }
失败的测试代码
describe('change date picker value test 1', () => { test('use datepicker label; set string', async () => { render(<DatePickerX />); const input = screen.getByLabelText('datepicker_label'); await act(async () => { await fireEvent.change(input, { target: { value: '3000/01/01' } }); }); expect(screen.getByText('3000/01/01')).toBeVisible(); }); test('use text input; set string', async () => { render(<DatePickerX />); const input2 = screen.getByTestId('textInput_testid'); await act(async () => { await fireEvent.change(input2, { target: { value: '3000/01/01' } }); }); expect(screen.getByText('3000/01/01')).toBeVisible(); }); test('use datepicker label; set date', async () => { render(<DatePickerX />); const input = screen.getByLabelText('datepicker_label'); await act(async () => { await fireEvent.change(input, { target: { value: new Date('3000/01/01') } }); }); expect(screen.getByText('3000/01/01')).toBeVisible(); }); test('use text input; set date', async () => { render(<DatePickerX />); const input2 = screen.getByTestId('textInput_testid'); await act(async () => { await fireEvent.change(input2, { target: { value: new Date('3000/01/01') } }); }); expect(screen.getByText('3000/01/01')).toBeVisible(); }); });
错误原因分析
- 输入触发逻辑错误:MUI X DatePicker的
onChange接收Date | null类型参数,而非输入框的字符串值。直接修改input的value无法触发组件内部的日期解析逻辑,也就不会调用changeDate更新状态。 - 断言方式错误:
screen.getByText('3000/01/01')查找的是页面纯文本节点,但日期显示在input的value属性中,并非独立文本节点,因此断言永远不会命中。 - 冗余的
act包裹:React Testing Library的render、fireEvent等API已自动处理act逻辑,手动包裹无意义且增加复杂度。
修正后的测试方案
方案1:模拟真实用户输入行为
使用@testing-library/user-event模拟用户输入、切换焦点的完整流程,触发组件的日期解析:
import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { DatePickerX } from './DatePickerX'; describe('DatePickerX', () => { test('updates date after valid input and blur', async () => { const user = userEvent.setup(); render(<DatePickerX />); const input = screen.getByTestId('textInput_testid'); // 清空原有值并输入目标日期 await user.clear(input); await user.type(input, '3000/01/01'); // 切换焦点触发组件解析输入的字符串 await user.tab(); // 断言输入框的value是否正确更新 expect(input).toHaveValue('3000/01/01'); }); });
方案2:直接触发组件的onChange逻辑
绕过输入框,直接调用组件的日期更新回调,适合快速测试状态变化:
import { render, screen } from '@testing-library/react'; import { DatePickerX } from './DatePickerX'; import { fireEvent } from '@testing-library/react'; describe('DatePickerX', () => { test('updates date when onChange is called', () => { render(<DatePickerX />); const input = screen.getByTestId('textInput_testid'); const targetDate = new Date('3000-01-01'); // 直接触发DatePicker的onChange事件(通过input的onChange传递) fireEvent.change(input, { target: { value: '3000/01/01' } }, { bubbles: true }); // 或者直接调用组件内部的日期更新逻辑 // 注意:若要直接获取组件实例,可使用render的result对象 expect(input).toHaveValue('3000/01/01'); }); });
关键注意事项
- 优先使用
userEvent:它模拟真实用户行为,能触发组件内部的解析、校验逻辑,比fireEvent更可靠。 - 断言目标为input的
value:不要用getByText查找日期,改用toHaveValue断言输入框的属性值。 - 触发焦点切换:DatePicker通常在输入框失去焦点时才会解析输入内容,需模拟tab或点击其他区域的操作。
内容的提问来源于stack exchange,提问作者DarkTrick
相关产品推荐
相关产品推荐

