Any test has these three steps,
Render the component
Find the element rendered by the component
Assert against the element found in the last step --> Decide to pass or fail the test.
For render -->, we use the 'render' method from RTL.
For Assertions --> we use 'expect' and the matcher function from Jest and Jest-dom.
Finding the element in dom is called 'querying'.
The query methods are available in the RTL library.
getBy,queryBy,findBy --> to find a single element on the page.
getAllBy,queryAllBy,findAllBy --> to find multiple elements on the page.
Everything is followed by a suffix -->: Role, LabelText, PlaceHolderText, Text, DisplayValue, AltText, Title, and TestId.
We will start with getBy,
getBy class of queries --> matching node and error if no or more than one found!
Roles are ARIA roles. Some HTML elements come with 'role' by default, and there are some we need to define using the 'role' attribute. You can check the roles of all elements below,
I just added some fields inside the form with different roles in 'GetbyRole.js', and test files are checked whether a particular is rendered inside the document.
Querying is done by getByRole.
There are elements with unique roles - one textbox, combo box, checkbox, and button.
What if there are multiple roles on the same file?
You will get the above error.
You can pass in the second argument as an object called options.
This options object can take properties like name, level, checked, selected, etc.
'name' property value can be the label of form element/text content of button/value of aria-label-attribute.
Similarly, we can use,
getByLabelText,getByPlaceHolder, same as getByRole method.
Used for <p>,<div> or <span>.
What if the value is given in the input itself?
It will warn you and nudge you to include the onChange handler.
So let's add an empty event handler.
Notice warning is gone.
Now you can find this input element using 'getByDisplayValue' method.
Same as getBy but
getAllBy --> returns all elements that match the query and throw an error if none are found.
What if we don't want some components on the page?
Say you have a 'login' button.
If you are not logged in, the button shows 'Login', and if you are logged in, the button shows 'Hello User'.
Naturally, we don't need the 'Hello User' button text on the page at first.
But GetBy or GetAllBy queries throw you an error because it throws an error if no matches are found.
That's why there are other classes of query --> QueryBy and QueryAllBy.
QueryBy --> returns null if no matches are found and hence used for checking element is not found.
QueryAll --> Same as above but returns an empty array if no matches are found.
What if we want to check components that render later and not at first, like Promises?
Notice the later render test is throwing an error because we use getBy and cannot handle later components.
That's why another class of queries comes --> findBy and findAllBy.
findBy --> returns a promise that resolves when an element is found or rejected if the promise takes more than the default timeout of 1000ms
findAllBy --> same as above but return an array
The syntax of findBy is,
await screen.findByText('text', queryOptions, waitForOptions)
That's the basic idea about queries.