If you’re looking to test a React text input by typing into it with userEvent, you are in the right place. I’ll show you how to test that text has been typed into a text input. This post will walk you through how to update to userEvent 14, and how to write a simple unit test that will simulate a user’s text input interaction.
userEvent vs fireEvent for Text Inputs:
If you’re unable to upgrade to userEvent 14 in your codebase, check out our how to test a text input with fireEvent here. This post tells you how to simulate a user event in a unit test (ie. type into a text input). That post will show you how to test a stateful React text input with fireEvent.
Estimated reading time: 5 minutes
Upgrade to userEvent 14.4.3 (or the latest version)
To take advantage of the user event package and its simple to use setup() function, you’ll want to update to userEvent version 14 or up. To see what the latest version of userEvent is, go to their Releases page here. In your package.json file, update the version to the latest (at the time of this post the latest version is 14.4.3).
"@testing-library/user-event": "^14.4.3"
Next run npm install to ensure you have the updated package.
npm install
A simple React Text Input from Material UI
Let’s say you have a simple text input from Material UI. Or if you want to create one, you would first install your Material UI dependencies:
npm install @mui/material @emotion/react @emotion/styled
Create a components folder in your src directory. Create a MyTextField.jsx file and throw this code in the file.
import { TextField } from '@mui/material'
const MyTextField = (props) => {
const { placeholder } = props
return <TextField placeholder={placeholder} />
}
export default MyTextField
Notice how the above code is not using React useState? If you are looking to test a text input that uses useState, check out our Test text input in Jest with fireEvent post here. Without a value prop or state, we can test the user interaction here with userEvent here easily.
Create your Unit Test file
To test a React text input with userEvent, first create a file called MyTextField.unit.test.jsx.
Inside this file I am importing render and screen from react testing library, and then I am importing userEvent from the user-event package. Finally, I am importing my text field component.
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import MyTextField from './MyTextField'
Next I’ll write a simple test. Note that userEvent is an asynchronous function. Be sure to use the async keyword before the arrow function.
test('enter text', async () => {
})
To test a React text input with userEvent, we need to utilize the setup() function from user-event v14^. To do that, inside the test function, create a variable that calls the setup function like so:
test('enter text', async () => {
const user = userEvent.setup()
})
If this isn’t working for you, you probably need to ensure you have updated your user-event version in your package.json file and that you’ve run npm install. You can find how to do that in the beginning of this post.
Next up in our test we need to render the text field component:
test('enter text', async () => {
const user = userEvent.setup()
render(<MyTextField placeholder="enter text" />)
})
Then all we have to do is use jest to get the input with the getByPlaceholderText() function. To type into the text field we use the user.type() function. Notice that we use the await keyword here because this is an asynchronous function.
test('enter text', async () => {
const user = userEvent.setup()
render(<MyTextField placeholder="enter text" />)
const input = screen.getByPlaceholderText('enter text')
await user.type(input, "Entered text")
})
Last but not least, we are going to write our assertion. We are asserting below that the text field value is now “Entered Text”.
test('enter text', async () => {
const user = userEvent.setup()
render(<MyTextField placeholder="enter text" />)
const input = screen.getByPlaceholderText('enter text')
await user.type(input, "Entered text")
expect(input).toHaveValue("Entered text")
})
Run npm test in the terminal and you should be all good to go!
npm test
Yay! Congratulations on writing a unit test that types into a text input using userEvent.
How to update the component to test an onChange Event
It is possible to test that an onChange event handler has been called with userEvent as long as your input doesn’t have a value prop. Some inputs are stateful and therefore must have a value state that begins with an empty value and then is updated to a new value after some function has been performed by the onChange event or another ui event.
Example of a Stateful text input:
const [value, setValue] = useState('')
<TextInput value={value} onChange={(e) => setValue(e.target.value)} />
Update the component to use an onChange prop:
const MyTextField = (props) => {
const { placeholder, onChange } = props
return <TextField placeholder={placeholder} onChange={onChange} />
}
Note that we have added an onChange prop to our text input. Now we can update our test.
Update the unit test to test that an event handler has been called:
test('enter text', async () => {
const user = userEvent.setup()
const handleChange = jest.fn()
render(<MyTextField placeholder="enter text" onChange={handleChange} />)
const input = screen.getByPlaceholderText('enter text')
await user.type(input, "Entered text")
expect(input).toHaveValue("Entered text")
expect(handleChange).toHaveBeenCalled()
})
And that’s it! Now you can test that text has been entered into the text input with jest AND that your onChange event fires whatever function you’ll be using.
Want to use React Testing Library in a Vite project? Check out how to set up RTL in a Vite project here.
Photo by Austin Distel on Unsplash