@testing-library/user-event version: v12.0.11jest version: v24.9.0 @testing-library/jest-dom version: v5.11.0
node version: v13.8.0
What you did:
Writing test for DateRangePicker from Material-UI to assert the changes to the component which needs the date range information.
What happened:
The onChange of the DateRangePicker doesn't get triggered.
However, it works in the browser.
This simply does nothing:
await userEvent.type(screen.getByLabelText(/start date/i), '05082020');
However:
Using the delay option throws an unexpected error:
await userEvent.type(screen.getByLabelText(/start date/i), '05082020', {delay: 1});
TypeError: the current element is of type DIV and doesn't have a valid value
This error is not very clear, since when debugging the element returned by the query it returns the correct one.
screen.debug(screen.getByLabelText(/start date/i));
...
<input
aria-invalid="false"
class="MuiInputBase-input MuiInput-input"
id="startDate"
placeholder="dd/mm/yyyy"
type="tel"
value="06/08/2020"
/>
Reproduction repository:
I've created a reproduction in a sandbox, but couldn't get the tests feedback. Not sure why.
https://codesandbox.io/s/daterangepicker-onchange-not-triggering-022cl
Problem description:
The behaviour should be as expected when running tests or testing manually in a browser. Meaning, the onChange event should be triggered disregarding if the method of triggering it was userEvent.type() or manually via browser.
Suggested solution:
I'm actually not sure if this is a fault of the DateRangePicker library, or userEvents library, and because of that I've created a bug ticket there as well.
https://github.com/mui-org/material-ui-pickers/issues/2073
Hi @mnajdova thanks for opening the issue :).
I suggest you to use getByRole (https://testing-playground.com/gist/e5bf2f963c4be4ebe69e08e9563e08f9/b288e31dbfab91329ed0e6828dbaa59037780f3f).
The problem here is that clicking on the input field only this events are fired
1) pointerdown
2) mousedown
3) focus
4) focusin
while on user-event are fired
1) pointerdown
2) mousedown
3) focus
4) focusin
5) pointerup
6) mouseup
7) click
This is causing a change of the focus from the input to the calendar div. This is wired 馃
@marcosvega91, thanks for your feedback.
We are currently investigating the bug and will come back with more info soon, hopefully.
So the problem in our (i.e. @mnemanja and mine) tests was that the date range picker is rendered in mobile mode by default.
The picker library (@material-ui/pickers) uses media queries to determine if you are using a desktop environment. We were running our tests with jest and jsdom 16. It does not implement window.matchMedia. Defining matchMedia made our tests work:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
beforeEach(() => {
// 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: string): MediaQueryList => ({
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,
}),
});
});
afterEach(() => {
delete window.matchMedia;
});
it('should be possible to set a start and end date', async () => {
render(<MyComponent />);
const startDateInput = await screen.findByRole('textbox', { name: /start date/i });
const endDateInput = screen.getByRole('textbox', { name: /end date/i });
userEvent.clear(startDateInput);
// this has to be typed one number at a time for the formatting to work
await userEvent.type(startDateInput, '20200106', { delay: 1 });
userEvent.clear(endDateInput);
await userEvent.type(endDateInput, '20200109', { delay: 1 });
expect(screen.getByRole('textbox', { name: /start date/i })).toHaveValue('2020-01-06');
expect(screen.getByRole('textbox', { name: /end date/i })).toHaveValue('2020-01-09');
});
So this was more a documentation issue for @material-ui/pickers.
Glad you worked that out! I think we're safe to close this here.
Most helpful comment
Glad you worked that out! I think we're safe to close this here.