I want to change the value of material UI TextField
in react testing library.I already set up the data-testid. Then using getByTestId
i picked up the input element.
// the component<TextFielddata-testid="input-email"variant="outlined"margin="normal"requiredfullWidthid="email"label="Email Address"name="email"value={email}onChange={e => setEmail(e.target.value)}autoComplete="email"autoFocus/>// the test //...let userInput = getByTestId('input-email')fireEvent.change(userInput, { target: { value: 'correct@mail.com' } })
but this doesn't work as it's returning error: The given element does not have a value setter
. Isn't the element uses e.target.value
on it's onChange
attribute? What am I do wrong?
Best Answer
Problem here is TextField is an abstraction in MaterialUI. It consists of FormControl, Label and Input. Clean way of solving this problem is:
- First, add
InputProps
on your TextField, withdata-testid
attribute.
// YourComponent.js<TextFieldonChange={event => setContent(event.target.value)}id="content"inputProps={{ "data-testid": "content-input" }}value={content}label="Content"/>
- Then simply query using this ID.
// YourComponent.test.jsconst contentInput = getByTestId("content-input");fireEvent.change(contentInput, {target: { value: "new content" }});// and then assert stuff in here
When encountering the error message 'the given element does not have a value setter,' it means that the specific element being referenced does not have a method for setting its value. This can occur in programming languages like JavaScript or HTML, where certain elements have predefined properties and methods.
The absence of a value setter can have a significant impact on the functionality and behavior of the element. It means that you are unable to assign or modify the value of the element programmatically, limiting your ability to manipulate or interact with it dynamically.
It is crucial to understand the reasons behind this limitation. Some elements, such as read-only input fields or certain HTML elements like div or span, are not designed to have their values changed by code. They are intended for displaying content or providing static information.
In terms of SEO, the absence of a value setter may not directly impact search engine rankings. However, it can affect the user experience and functionality of your website or application. If you are trying to create interactive features or collect user input, not having a value setter can hinder your development process and limit the capabilities of your project.
the issue here is when we use Material UI, it renders the TextField component having one of the elements inside it as an input field.And only "input" has getter and setter on it. So after you got the TextField, you have to get the "input" element of your TextField using querySelector() of your DOM object.
const field = getByTestId('input-email').querySelector('input');// now fire your eventfireEvent.change(field, { target: { value: 'abcd@xyz.com' } });
You can use fireEvent.change
on an element that supports that event like <input>
. In your case, I'm not sure what you're selecting. You can try to debug(userInput)
to see what it returns.
I tested the answers and comments and the only solutions that works for me was userEvent.
First install the dependencynpm install --save-dev @testing-library/user-event
Then in your test file calls:
import { render, act } from '@testing-library/react';import userEvent from '@testing-library/user-event';...it('Awesome input test', async () => {await act(async () => {const inputMessage = getByTestId('input-send-message');userEvent.type(inputMessage, 'My awesome text...');})})//expect goes here
More here
In my case I had InputProps two times because I had an endAdornment. Just make sure that you put your data-testid attribute where it belongs. Example:
<TextFieldInputProps={{inputProps: {min: 0,'data-testid': 'value'},endAdornment: < InputAdornment position = "end" > % < /InputAdornment>,}}/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>