You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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');
  });
});

关键注意事项

  1. 优先使用userEvent:它模拟真实用户行为,能触发组件内部的解析、校验逻辑,比fireEvent更可靠。
  2. 断言目标为input的value:不要用getByText查找日期,改用toHaveValue断言输入框的属性值。
  3. 触发焦点切换:DatePicker通常在输入框失去焦点时才会解析输入内容,需模拟tab或点击其他区域的操作。

内容的提问来源于stack exchange,提问作者DarkTrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 12:51:17