Using getByRole is preferred, but sometimes it will not be ideal
const submitButton = screen.getByRole('button', {
name: /submit/i
})- Fallbacks:
getByTestIdcontainer.querySelector(All)
Mock functions
Fake functions that don’t do anything
const mockProps = {
onSwitchToggle: jest.fn(),
}Fake functions records whenever it gets called, and the arguments it was called with - toHaveBeenCalled(), toHaveBeenCalledWith().
They are used to make sure a component calls a callback function.
User
userfrom@testing-library/user-eventis preferred overfireEvent- is an async function, therefore user methods need
await
within
const rows = within(screen
.getByTestId('users')
.getAllByRole('row')
)- within an element with a test id of
users, get all the elements with a role ofrow - helps to exclude rows you don’t want outside of the element with test id of
users
render
render(<Component />returns a{ container }- container is automatically created to wrap the component
- useful for when using
container.querySelector
logTestingPlaygroundURL
screen.logTestingPlaygroundURL()opens a browser window which helps you select elements
avoiding beforeEach
- a global variable built in to Jest
- Jest runs the arrow function inside
beforeEachbefore each individual test - React Testing Library does not recommend rendering components in
beforeEach
Partial list of commonly used roles:
const roles = [
'link', // <a href="/"></a>
'button', // <button>
'contentinfo', // <footer>
'heading', // <h1>
'banner', // <header>
'img', // <img />
'checkbox', // <input type="checkbox" />
'spinbutton', // <input type="number" />
'radio', // <input type="radio" />
'textbox', // <input type="text" />
'listitem', // <li>
'list', // <ul>
]
for (let role of roles) {
const el = screen.getByRole(role);
expect(el).toBeInTheDocument()
}Finding by Accessible Names
// Component
<div>
<button>Submit</button>
<button>Cancel</button>
</div>
test('can select by accessible name', () => {
render(<Component />)
const submitButton = screen.getByRole('button', {
name: /submit/i
})
const cancelButton = screen.getByRole('button', {
name: /cancel/i
})
})Directly Assigning an Accessible Name
- when you can’t use plain text
// Component
<div>
<button aria-label="sign in"><svg /></button>
<button aria-label="sign out"><svg /></button>
</div>
test('can select by accessible name', () => {
render(<Component />)
const signInButton = screen.getByRole('button', {
name: /sign in/i
})
const signOutButton = screen.getByRole('button', {
name: /sign out/i
})
})GetBy, QueryBy, FindBy
Finding 0 elements
getBy___- looks for exactly 1 element. If not found, returns anerror.queryBy___- returnsnull.findBy___- works asynchronously. By default, it will watch the output of your component for 1 second. Throws anerrorand returns aPromisethat gets rejected.
Finding 1 element
getBy___- looks for exactly 1 element.queryBy___- looks for exactly 1 element.findBy___- asynchronously looks for exactly 1 element for 1 second.
Find > 1 element
getBy___- returnserror.queryBy___- returnsnull.findBy___- Throws anerrorand returns aPromisethat gets rejected after 1 second.
Multiple Element Variations
Finding 0 elements
getAllBy___- throws an errorqueryAllBy___- returns an empty arrayfindAllBy___- throws an error
Finding 1 element
getAllBy___- returns an arrayqueryAllBy___- returns an arrayfindAllBy___- returns an array
Finding > 1 element
getAllBy___- returns an arrayqueryAllBy___- returns an arrayfindAllBy___- returns an array
When to use each
| Goal of test | Use |
|---|---|
| Prove an element exists | getBy, getAllBy |
| Prove an element does not exist | queryBy, queryAllBy |
| Make sure an element eventually exists | findBy, findAllBy |
Querying for Elements with Different Criteria
| End of function name | Search Criteria |
|---|---|
| ByRole | Finds elements based on their implicit or explicit ARIA role |
| ByLabelText | Find form elements based upon the text their paired labels contain |
| ByPlaceholderText | Find form elements based upon their placeholder text |
| ByText | Find elements based upon the text they contain |
| ByDisplayValue | Find elements based upon their current value |
| ByAltText | Find elements based upon their alt attribute |
| ByTitle | Find elements based upon their title attribute |
| ByTestId | Find elements based upon their data-testid attribute |
When to use each of these
Always prefer using query functions ending with ByRole. Only use others if ByRole is not an option.
Matchers
within is used for looking for elements inside of another element
- helps avoid brittle tests for when you’re looking for a specific number of elements, but may add more later which will break the test
// Component
<div>
<button>Go back</button>
<form aria-label="form">
<button>Submit</button>
<button>Cancel</button>
</form>
</div>
test('can get buttons within form only', () => {
render(<Component />)
const form = screen.getByRole('form')
const formButtons = within(form).getAllByRole('button')
expect(formButtons).toHaveLength(2)
})