MUI V5 React 单元测试未触发日期选择器处理程序

Man*_*han 4 unit-testing reactjs material-ui

我刚刚将我的 React 项目升级到 MUI V5,其中 KeyboardDatePicker 组件已根据 MUI 文档迁移到 DatePicker。由于某种原因,React 库测试无法触发日期选择器组件的模拟处理函数。

\n

我的组件

\n
import React from "react"\nimport AdapterDateFns from '@mui/lab/AdapterDateFns';\nimport moment from "moment"\nimport LocalizationProvider from '@mui/lab/LocalizationProvider';\nimport DatePicker from '@mui/lab/DatePicker';\nimport { TextField } from "@mui/material"\n// Required for Material UI datepicker since it is timezone sensitive\nexport const formatDate = date =>\n    date ? new Date(moment(date).year(), moment(date).month(), moment(date).date()) : null\n\nexport default function IndependentDateRangePicker({\n    handleStartDateChange,\n    handleEndDateChange,\n    startDateValue,\n    endDateValue,\n    disableDate\n}) {\n    return (\n        <LocalizationProvider dateAdapter={AdapterDateFns}>\n            <DatePicker\n                inputFormat="MM/dd/yyyy"\n                aria-label="change start date" \n                disabled={disableDate}\n                value={formatDate(startDateValue)}\n                onChange={handleStartDateChange}\n                maxDate={endDateValue ? formatDate(endDateValue) : ""}\n                InputProps={{ "data-testid": "start-date-picker" }}\n                renderInput={(props) => <TextField  {...props} label="Start Date" variant="standard"/>}\n            />\n            <DatePicker\n                style={{ marginTop: 5 }}\n                inputFormat="MM/dd/yyyy"\n                aria-label="change start date"\n                disabled={disableDate}\n                value={formatDate(endDateValue)}\n                onChange={handleEndDateChange}\n                minDate={startDateValue ? formatDate(startDateValue) : ""}\n                InputProps={{ "data-testid": "end-date-picker" }}\n                renderInput={(props) => <TextField {...props} variant="standard" label="End Date" />}\n            />\n        </LocalizationProvider>\n    )\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我的反应测试文件

\n
import React from "react"\nimport { render, fireEvent } from "@testing-library/react"\nimport IndependentDateRangePicker, { formatDate } from "../components/IndependentDateRangePicker"\n\ndescribe("<IndependentDateRangePicker />", () => {\n    let c, handleEndDateChangeMock, handleStartDateChangeMock\n\n    beforeEach(() => {\n        handleEndDateChangeMock = jest.fn()\n        handleStartDateChangeMock = jest.fn()\n    })\n    \n\n\n    describe("When no dates are passed as props", () => {\n        beforeEach(() => {\n            c = render(\n                <IndependentDateRangePicker\n                    handleStartDateChange={handleStartDateChangeMock}\n                    handleEndDateChange={handleEndDateChangeMock}\n                    startDateValue={""}\n                    endDateValue={""}\n                />\n            )\n        })\n\n        it("should not call handlers when dates are empty", () => {\n            fireEvent.change(c.getByTestId("start-date-picker").querySelector('input'), {\n                target: { value: "" }\n            })\n            fireEvent.change(c.getByTestId("end-date-picker").querySelector('input'), {\n                target: { value: "" }\n            })\n            expect(handleStartDateChangeMock).not.toHaveBeenCalled()\n            expect(handleEndDateChangeMock).not.toHaveBeenCalled()\n        })\n\n        it("should call handler when start date is updated", async () => {\n            fireEvent.change(c.getByTestId("start-date-picker").querySelector('input'), {\n                target: { value: "01/03/2000" }\n            })\n            expect(handleStartDateChangeMock).toHaveBeenCalledWith(expect.any(Date), "01/03/2000")\n        })\n\n        it("should call handler when end date is updated", () => {\n            fireEvent.change(c.getByTestId("end-date-picker").querySelector('input'), {\n                target: { value: "01/04/2000" }\n            })\n            expect(handleEndDateChangeMock).toHaveBeenCalledWith(expect.any(Date), "01/04/2000")\n        })\n    })\n\n})\n
Run Code Online (Sandbox Code Playgroud)\n

测试错误信息

\n
 \xe2\x97\x8f <IndependentDateRangePicker /> \xe2\x80\xba When no dates are passed as props \xe2\x80\xba should call handler when end date is updated\n\n    expect(jest.fn()).toHaveBeenCalledWith(...expected)\n\n    Expected: Any<Date>, "01/04/2000"\n\n    Number of calls: 0\n\n      55 |              target: { value: "01/04/2000" }\n      56 |          })\n    > 57 |          expect(handleEndDateChangeMock).toHaveBeenCalledWith(expect.any(Date), "01/04/2000")\n         |                                          ^\n      58 |      })\n      59 |  })\n      60 |\n\n      at Object.<anonymous> (src/__tests__/IndependentDateRangePicker.test.js:57:36)\n
Run Code Online (Sandbox Code Playgroud)\n

您可以看到触发handleEndDateChangeMock函数时存在一些问题。

\n

请在这件事上给予我帮助。TIA。

\n

小智 9

问题是 DatePicker 在测试中默认为移动模式,您应该在测试之前添加以下代码,它们就会通过:

beforeAll(() => {
  // add window.matchMedia
  // this is necessary for the date picker to be rendered in desktop mode.
  // if this is not provided, the mobile mode is rendered, which might lead to unexpected behavior
  Object.defineProperty(window, "matchMedia", {
    writable: true,
    value: (query) => ({
      media: query,
      // this is the media query that @material-ui/pickers uses to determine if a device is a desktop device
      matches: query === "(pointer: fine)",
      onchange: () => {},
      addEventListener: () => {},
      removeEventListener: () => {},
      addListener: () => {},
      removeListener: () => {},
      dispatchEvent: () => false,
    }),
  });
}

afterAll(() => {
  delete window.matchMedia;
});
Run Code Online (Sandbox Code Playgroud)

来源: https: //github.com/mui-org/material-ui-pickers/issues/2073