- Using class-based selectors to find elements
- Manually triggering the re-rendering of components
- Using fixed-duration waits when expecting state changes
- Simulating browser events
// Instead of using
const usernameInput = wrapper.find('input').first();
const passwordInput = wrapper.find('input').last();
// ...or using
const usernameInput = wrapper.find('.sign-in-modal .username-field');
const passwordInput = wrapper.find('.sign-in-modal .password-field');
// We should consider
const usernameInput = getByLabelText('Username');
const passwordInput = getByLabelText('Password');
react-testing-library re-exports everything from dom-testing-library
// In order of preference
getByLabelText()
getByPlaceholderText()
getByText()
getByAltText()
getByTitle()
getByValue()
// Escape hatch
getByTestId()
All methods accept a TextMatch which can be either a string, regex or a predicate function
// The "for" attribute
// (NOTE: in JSX with React you'll write "htmlFor" rather than "for")
<label for="username-input">Username</label>
<input id="username-input" />
// The aria-labelledby attribute
<label id="username-label">Username</label>
<input aria-labelledby="username-label" />
// Wrapper labels
<label>Username <input /></label>
// It will NOT find the input node for this:
<label><span>Username</span> <input /></label>
// A shortcut for document.querySelector(`[data-testid="${yourId}"]`)
// <input data-testid="username-input" />
const usernameInputElement = getByTestId(container, 'username-input')
Should only be used in situations where all other selectors don't work for your use case.
// In a situation where you'd want to select a specific item in a list
const thirdLiInUl = container.querySelector('ul > li:nth-child(3)')
// You can include an index or ID in your attribute
const items = [
/* your items */
]
const thirdItem = getByTestId(`item-${items[2].id}`)
Nothing to do here! 😁
react-testing-library uses ReactDOM directly on JSDOM
JSDOM should update automatically as the browser would
// react-testing-library provides us with two wait methods:
// wait
// Polls the DOM with an assertion
// To be used for non-deterministic waits (API calls)
await wait(() => getByLabelText(container, 'username'))
getByLabelText(container, 'username').value = 'chucknorris'
// waitForElement
// Uses MutationObserver
// To be used for deterministic DOM changes
const usernameElement = await waitForElement(
() => getByLabelText(container, 'username')
)
const [usernameElement, passwordElement] = waitForElement(
() => [
getByLabelText(container, 'username'),
getByLabelText(container, 'password'),
]
)
// react-testing-library provides us with fireEvent
// <button>Submit</button>
const rightClick = {button: 2}
fireEvent.click(getElementByText('Submit'), rightClick)
// default `button` property for click events is set to `0` which is a left click.
// toBeInTheDOM
expect(queryByTestId('count-value')).toBeInTheDOM()
expect(queryByTestId('count-value')).not.toBeInTheDOM()
// toHaveTextContent
expect(getByTestId('count-value')).toHaveTextContent('2')
expect(getByTestId('count-value')).not.toHaveTextContent('2')
// toBeVisible
expect(container.querySelector('header')).toBeVisible()
expect(container.querySelector('header')).not.toBeVisible()
jest-dom provides us with many DOM-specific Jest matchers
test('Fetch makes an API call and displays the greeting when load-greeting is clicked', async () => {
// Arrange
axiosMock.get.mockResolvedValueOnce({data: {greeting: 'hello there'}})
const url = '/greeting'
const {getByText, getByTestId, container} = render(App)
// Act
fireEvent.click(getByText('Load Greeting'))
// let's wait for our mocked `get` request promise to resolve
// wait will wait until the callback doesn't throw an error
const greetingTextNode = await waitForElement(() =>
getByTestId('greeting-text'),
)
// Assert
expect(axiosMock.get).toHaveBeenCalledTimes(1)
expect(axiosMock.get).toHaveBeenCalledWith(url)
expect(getByTestId('greeting-text')).toHaveTextContent('hello there')
expect(getByTestId('ok-button')).toHaveAttribute('disabled')
})
Used the "AAA" (Arrange-Act-Assert) testing pattern
https://github.com/kentcdodds/react-testing-library
https://github.com/gnapse/jest-dom
https://github.com/kentcdodds/dom-testing-library