javascriptmaterial-uidatepickerreact-testing-libraryuser-event

What element should userEvent.type(...) target to be used with MUI's DesktopDatePicker TextField?


How can I type into the TextField input in the MUI datepicker with react-testing-library's user-event? I can see there is a mask being applied

I've tried userEvent.type(inputEl, '1') and userEvent.keyboard('1'). In both cases, the input remains empty.

My current assumption is that a rerender replaces my update with the empty state of a higher order component (which makes sense, based on the application the date format mask to the input).

The documentation example works as expected, so my issue is specific to the MUI datepicker.

A watered down version of the component (and test) can be found in this sandbox.

Below is a copy of the rendered HTML to prove I'm targeting the input element with a data-testid, which does not work:

screen.getByTestId('date-selector-text-field').outerHTML:
<input
  aria-invalid="false"
  placeholder="dd / mm / yyyy"
  readonly=""
  type="text"
  aria-readonly="true"
  aria-label="Choose date"
  data-testid="date-selector-text-field"
  class="MuiOutlinedInput-input MuiInputBase-input css-1t8l2tu-MuiInputBase-input-MuiOutlinedInput-input"
  value=""
  aria-describedby="mui-1-helper-text"
  id="mui-1"
>

Solution

  • I added the following, to make sure the DatePicker is rendered for a Desktop in the test. More info on that you can find here: https://github.com/mui/material-ui-pickers/issues/2073#issuecomment-671834179

    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: any) => ({
            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: () => null,
            addEventListener: () => null,
            removeEventListener: () => null,
            addListener: () => null,
            removeListener: () => null,
            dispatchEvent: () => false,
          }),
        });
      });
      afterAll(() => {
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        delete window.matchMedia;
      });
    

    In case you have a value already in the Datepicker, when calling userEvent.type(), add an await userEvent.clear() before the await userEvent.type(). The clear is needed, because we are simulating actual user behaviour, and you are not able to type in something, if you already have a value (which I do have in my test case).