react-testing-library for material ui Text input
Asked Answered
H

3

24

My Text Input is:

<TextField
  className={classes.textField}
  data-testid={name}
  variant="outlined"
  error={false}
  required
  onChange={(element) => {
    if (onTextChange) {
      onTextChange(name, element.target.value);
    }
  }}
  disabled={!editEnable}
  name={name}
  label={label}
  defaultValue={values}
  fullWidth
/>;

and UI:

Screenshot of HTML with an input field highlighted

How to change the value of this text element in the React testing library?

Heir answered 1/9, 2020 at 20:22 Comment(1)
same issue, did you find a way to do it directly with data-testid?Sixtieth
A
24

In my case it works like this

it('should render input ', () => {
    const field  = screen.getByTestId('search-text-field').querySelector('input')
    expect(field ).toBeInTheDocument()

    fireEvent.change(field , {target: { value: 'some text'}});
    expect(field.value).toBe('some text');
});
Adamo answered 7/10, 2021 at 4:21 Comment(2)
React-testing-library docs says that you shouldn't rely on DOM structure, so using querySelector is a bad practice. As @Richard Hpa mentioned in his answer: you can define id attribute for your TextField and then it will be possible to use screen.getByLabelText query to get your input element.Overtop
It is considered to be better to query by input or role="textbox" than query by testid of MUI instance, as per MUI document mui.com/material-ui/guides/testingKingery
C
11

I don't think getting the input by the display value is a good idea as if that changes the whole test will fail. Instead you should get the label of the input field.

screen.getByLabelText(/^label/i)

Update

Just realised that my way only works if you include an id to the TextField and the ID must match the name. This does seem to be the preferred way to get the input via Material UI as you don't need to include a test-id or by the value.

<TextField
    name={name}
    id={name}
    label={label}
    {...otherProps}
/>
Camarena answered 29/6, 2021 at 3:57 Comment(3)
Yes this is the recommended approach. To remember this: even if we are used to use the name to get the input value during submit, name is not a unique property at the page level. So it cannot be used safely for the htmlFor property that links the label to the input. Instead, id is unique through the page, so it's safe to use to uniquely identify the input. So no id == no link between the label and the input. Adding an id fixes it. Also, id can differ from the name (you might want something very unique, using a prefix for instance).Shattuck
Unfortunately, I have multiple <TextField>s with the same label on my testing render. And getting only the TextField with getByTestId isn't enough to test with userEvent.type() or userEvent.clear. It's required to get the real <input> element. :/Brottman
@FranciscoGomes Pop open another SO question and provide some code, I might be able to help you out there. But ideally each input should have something unique on it, could be the label or an aria tag. If you dont then screen readers will struggle to understand what each input is meant to do.Camarena
G
9

I often struggle to get Material UI and react-testing-library working. But if you know your "recipes" it's always the same.

Here is an example of an TextField

import * as React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { TextField } from '@material-ui/core';

const inputMock = jest.fn();

const Test = () => (
  <TextField
    data-testid={name}
    variant="outlined"
    error={false}
    required
    onChange={inputMock}
    name={name}
    label={'label'}
    defaultValue={'4711'}
    placeholder={'Enter Number'}
    fullWidth
  />
);

test('Input', () => {
  const container = render(<Test />);

  const input = container.getByDisplayValue('4711') as HTMLInputElement;

  fireEvent.change(input, { target: { value: '42' } });
  expect(input.value).toBe('42');
  expect(inputMock.mock.calls).toHaveLength(1);
});

Here are some advises which selectors to use. So you can try a "better" one. https://testing-library.com/docs/guide-which-query

Cheers Thomas

Graben answered 1/9, 2020 at 20:44 Comment(2)
Advises are on the linked page. Best is by accessibility (including display value, but there are also role, label ...).Graben
It works but do not really respect current best practices of testing what the user sees, answer below is more aligned.Shattuck

© 2022 - 2024 — McMap. All rights reserved.