Using getByRole
is preferred, but sometimes it will not be ideal
const submitButton = screen.getByRole('button', {
name: /submit/i
})
- Fallbacks:
getByTestId
container.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
user
from@testing-library/user-event
is 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
beforeEach
before 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 anerror
and returns aPromise
that 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 anerror
and returns aPromise
that 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)
})