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



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

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

我的React测试文件

import React from "react"
import { render, fireEvent } from "@testing-library/react"
import IndependentDateRangePicker, { formatDate } from "../components/IndependentDateRangePicker"
describe("<IndependentDateRangePicker />", () => {
let c, handleEndDateChangeMock, handleStartDateChangeMock
beforeEach(() => {
handleEndDateChangeMock = jest.fn()
handleStartDateChangeMock = jest.fn()
})


describe("When no dates are passed as props", () => {
beforeEach(() => {
c = render(
<IndependentDateRangePicker
handleStartDateChange={handleStartDateChangeMock}
handleEndDateChange={handleEndDateChangeMock}
startDateValue={""}
endDateValue={""}
/>
)
})
it("should not call handlers when dates are empty", () => {
fireEvent.change(c.getByTestId("start-date-picker").querySelector('input'), {
target: { value: "" }
})
fireEvent.change(c.getByTestId("end-date-picker").querySelector('input'), {
target: { value: "" }
})
expect(handleStartDateChangeMock).not.toHaveBeenCalled()
expect(handleEndDateChangeMock).not.toHaveBeenCalled()
})
it("should call handler when start date is updated", async () => {
fireEvent.change(c.getByTestId("start-date-picker").querySelector('input'), {
target: { value: "01/03/2000" }
})
expect(handleStartDateChangeMock).toHaveBeenCalledWith(expect.any(Date), "01/03/2000")
})
it("should call handler when end date is updated", () => {
fireEvent.change(c.getByTestId("end-date-picker").querySelector('input'), {
target: { value: "01/04/2000" }
})
expect(handleEndDateChangeMock).toHaveBeenCalledWith(expect.any(Date), "01/04/2000")
})
})
})

测试错误信息

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

你可以看到触发handleEndDateChangeMock函数有一些问题。

请帮我一下。TIA。

问题是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;
});

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

我正在努力解决类似的问题,使用@mui/x-date-pickers/DatePicker包的新版本的DatePicker,我使用该组件如下:

<DatePicker
label={'Date of birth'}
value={dateOfBirth}
openTo="year"
views={['year', 'month', 'day']}
onChange={setDateOfBirth}
disableFuture
desktopModeMediaQuery={theme.breakpoints.up('sm')}
renderInput={params => (
<TextField
{...params}
sx={{
width: '100%',
}}
/>
)}
name="dateOfBirth"
/>

所以我对之前的答案做了一点改变,并将此添加到我的测试中:

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 === '(min-width:600px)',
onchange: () => {},
addEventListener: () => {},
removeEventListener: () => {},
addListener: () => {},
removeListener: () => {},
dispatchEvent: () => false,
}),
})
})
afterAll(() => {
delete window.matchMedia
})

问题解决了。

您可以在这里查看完整的可复制示例https://codesandbox.io/s/datepicker-usjhlm?file=/src/index.test.js:1847-2634

最新更新