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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:12:21