Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to test input value in dom-testing-library or react-testing-library

Tags:

What is the best way to test the value of an <input> element in dom-testing-library/react-testing-library?

The approach I've taken is to fetch the raw input element itself via the closest() method, which then gives me direct access to the value attribute:

const input = getByLabelText("Some Label") expect(input.closest("input").value).toEqual("Some Value") 

I was hoping that there was a way I could this without having to directly access HTML attributes. It didn't seem like it was in the spirit of the testing library. Perhaps something like the jest-dom toHaveTextContent matcher matcher:

const input = getByLabelText("Some Label") expect(input).toHaveTextContent("Some Value") 

UPDATE

Based on request in the comments, here is a code example showing a situation where I felt the need to test the value in the input box.

This is a simplified version of a modal component I built in my app. Like, extremely simplified. The whole idea here is that the modal opens up with the input pre-filled with some text, based on a string prop. The user can freely edit this input and submit it by pressing a button. But, if the user closes the modal and then reopens it, I would like to have the text reset to that original string prop. I wrote a test for it because a previous version of the modal DID NOT reset the input value.

I'm writing this in TypeScript so that the types of each prop are very clear.

interface Props {   onClose: () => void   isOpen: boolean   initialValue: string }  export default function MyModal({ onClose, isOpen, initialValue }) {   const [inputValue, setInputValue] = useState(initialValue)    // useEffect does the reset!   useEffect(() => {     if (!isOpen) {       setNameInput(initialValue)     }   }, [isOpen, initialValue])    return (     <SomeExternalLibraryModal isOpen={isOpen} onClose={onClose}>       <form>         <input           value={inputValue}           onChange={(e: ChangeEvent<HTMLInputElement>) =>             setInputValue(e.target.value)           }         />         <button onClick={onClose}>Cancel</button>       </form>     </SomeExternalLibraryModal>   ) } 
like image 205
ecbrodie Avatar asked Jun 19 '20 15:06

ecbrodie


People also ask

What should I test with React testing library?

React Testing Library encourages you to test the behavior of your application instead of implementation details. By testing your application the way a user would use it, you can be confident that your application will behave as expected when all test cases have passed.

Which is better enzyme or React testing library?

If you want mimic real-world user interactions, the React Testing Library is the way to go because you can do the same with fireEvent functions. Meanwhile, Enzyme is better suited to situations where you have to match the state of React or some other function with state.

Does React testing library use real DOM?

So rather than dealing with instances of rendered React components, your tests will work with actual DOM nodes. The utilities this library provides facilitate querying the DOM in the same way the user would.


1 Answers

You are right in being suspicious of your testing method in regards to how this testing library wants you to test. The simplest answer to this question would be to use the getByDisplayValue query. It will search for an input, textarea, or select that has the value you are attempting to find. For example, using your component as an example, if I was trying to verify that inputValue = 'test', I would search like

expect(screen.getByDisplayValue('test')).toBeInTheDocument(); 

That is all you need to do. I assume your test is only rendering the MyModal component. Even if you have multiple inputs, it doesn't matter in regards to testing philosophy. As long as the getByDisplayValue finds any input with that value, it is a successful test. If you have multiple inputs and want to test that the exact input has the value, you could then dig into the element to determine it is the correct input:

note: you will need jest-dom for this to work.

expect(screen.getByDisplayValue('test')).toHaveAttribute('id', 'the-id'); 

or (without jest-dom):

expect(screen.getByDisplayValue('test').id).toBe('the-id'); 

You can of course search for any attribute you like.

One final alternative for testing the value is to find the input by role. This won't work in your example's case unless you add a label and affiliate it to your input through the htmlFor attribute. You could then test it like such:

expect(screen.getByRole('input', { name: 'the-inputs-id' })).toHaveValue('test'); 

or (without jest-dom):

expect(screen.getByRole('input', { name: 'the-inputs-id' }).value).toBe('test'); 

This I believe is the best way to test for the value while making sure the correct input has the value. I would suggest the getByRole method, but again, you will need to add a label to your example.

like image 157
Devin Fields Avatar answered Oct 06 '22 09:10

Devin Fields