React 13: Testing: RTL


Docs

https://testing-library.com/docs/

DOM Testing Cheatsheet : https://testing-library.com/docs/dom-testing-library/cheatsheet/

  • getBy , findBy , queryBy , getAllBy , findAllBy , queryAllBy

Jest Matchers : https://jestjs.io/docs/expect

  • toBe , toEqual , toBeDefined , toBeUndefined() , toBeTruthy , toBeFalsy , toBeNull , toThrow, expect.not


Common Imports

import { render, screen, cleanup , waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';

Problem Statement

We want a reliable way to test our UI as if we were a user, from a user perspective.

UI-layer testing framework that helps us ensure that our React components are rendering and behaving properly.

  • built explicitly for testing React components.

  • allows us to test our components in a way that mimics real user interactions.


Best Practice Reminder

AAA: Arrange, Act, Assert


RTL : Install

npm install --save-dev @testing-library/react

p.s. create-react-app by default includes RTL

npm install --save-dev @testing-library/jest-dom

p.s. create-react-app by default includes jest-dom (and jest)

npm install --save-dev @testing-library/user-event

p.s. create-react-app by default includes user-event (and jest)


RTL : Watch Mode

npm test

Launches the test in watch mode, allowing the test to re-run every time the file is saved!

Type q in the terminal to quit out of the watch mode.


RTL : Watch Mode

Customize terminal output by RTL

npm test -- --coverage // --coverage : Indicates that test coverage information should be collected and reported in the output

npm test -- --silent // --silent : Prevents tests from printing messages through the console.

npm test -- --help // --help : Displays help


RTL : render() and screen

render() : function that we can use to virtually render components and make them available in our unit tests

render() : similar to ReactDOM.render(), RTL’s render() function takes in JSX as an argument

screen : special object which can be thought of as a representation of the browser window

screen.debug() : prints out all the DOM contents

After importing the render and screen values from @testing-library/react, you can test using the it() function from the Jest testing framework.


RTL : Example


RTL : Example

GroceryList.js

testfile.js


RTL : it() Example Skeleton


RTL : getByRole() Example Skeleton

TLDR on Accessible Name : https://www.tpgi.com/what-is-an-accessible-name/


RTL : getByText() w Regex

Matching a string

Matching a regex

https://testing-library.com/docs/dom-testing-library/cheatsheet/#text-match-options


RTL : getByX vs queryByX methods

.getByX methods: throw an error and immediately cause the test to fail.

.queryByX methods: return null if they don’t find a DOM node

  • useful when asserting that an element is NOT present in the DOM.


RTL : queryByX methods


RTL : queryByX methods

something.test.js


RTL : getByX VS findByX methods

.getByX methods: throw an error and immediately cause the test to fail.

.findByX methods: query for asynchronous elements, which will eventually appear in the DOM.

  • The .findByX methods work by returning a Promise, which resolves when the queried element renders in the DOM.

  • async/await keywords can be used to enable asynchronous logic.


RTL : getByX VS findByX vs queryByX

.getByX methods: throw an error and immediately cause the test to fail.

  • assert regular elements - synchronous ones

.queryByX methods: return null if they don’t find a DOM node

  • assert an element is NOT present in the DOM.

  • whether sync or asynch

.findByX methods: query for asynchronous elements

  • asset an element will eventually appear in the DOM.


RTL : findByX methods

Thought.test.js


RTL : findByX + Await


RTL : Mimick User Interactions

Problem Statement

As a JS Dev testing my app, I want to mimic user interactions such as clicking a checkbox and typing text.

Solution

The library @testing-library/user-event in the @testing-library suite is there just for that.


RTL : userEvent library/object

https://github.com/testing-library/user-event

https://testing-library.com/docs/user-event/utility


RTL : userEvent.interaction() vs user.interaction()

You can do

userEvent.click();

Or

const user = userEvent.setup();

user.click();

TLDR: most of the time userEvent.click() is ok

c.f. https://github.com/testing-library/user-event/discussions/1036


RTL : waitFor() method

Problem Statement

I have components that disappear asynchronously. How can I test they disappear as planned?

  • waitFor() method

Basic Syntax


RTL : waitFor() Example

App.js


RTL : waitFor() deets

waitFor() callback function : confirms this by querying for this element and then waiting for the expect() assertion to pass.

waitFor() optional 2nd arg: options object, can be used to control how long to wait for before aborting and much more


RTL : Testing for Accessibility

Writing tests that adhere to this principle forces you to make your applications more accessible. If a test can find and interact with your elements by their text, it’s more likely that a user who uses assistive technology can as well.

One way we can write tests with accessibility concerns in mind is by sticking to querying with ByRole queries (getByRole, findByRole, queryByRole). The ByRole variant will be able to query any elements within the accessibility tree. If you are unable to query for the component you want to test, you may have just exposed a part of your application that is inaccessible.

React Testing Library Playground for suggestions on accessible queries for more complex needs.

https://testing-playground.com/


RTL : Testing for Accessibility

CheckoutForm.js

CheckoutForm.test.js

Last updated