Testing 101: Overview of tooling for UI component testing

In order to write tests that avoid implementation details, we need a collection of tools that encourage us to test our components from the perspective of the user. This article outlines the four types of tools you need to test your components successfully.

Summary

  1. Test framework
  2. Testing library
  3. Custom matchers
  4. DOM environment

Test framework

Testing frameworks allow us to run our tests, and provides APIs for writing tests. Examples of such tools include Jest and Vitest.

The most common activities include running tests from the command line with a script like npm run test, describing test structures (e.g. using the describe method in Jest to demarcate test suites) and making assertions.

Writing assertions that describe the expected behaviour of an application is a fundemental activity in testing. Our assertions let us check that values meet certain conditions. The expect method gives us access to the matchers provided by the testing framework.

Custom matchers

Most testing frameworks provide built in matchers with which we can form assertions. As noted above, the expect method in Jest gives us access to the built in matchers, eg toBe(), toStrictEqual().

jest-dom is a library that extends these built in matchers, and is part of the testing-library family. It provides custom DOM element matchers for Jest. This helps us write more idiomatic, user-centric tests by asserting various things about the state of the DOM. For example, expecting a particular element toBeInTheDocument().

Testing library

Testing Library is a family of packages that allows us to test web pages by querying and interacting with DOM nodes in a way that is similar to how users would find them. The core API is a set of queries for selecting elements, some user actions for simiulating user interaction (click events etc.) as well as more advanced features for debugging and accessibility.

React Testing Library builds on this core API by providing methods specific to React. For example, the render function takes any JSX as an argument to render it as output. There are a few packages within testing library that are framework specific (Angular, Vue etc.) to make this kind of component testing easier.

DOM environment

Since we are testing UI components for web apps that run in the browser, we need access to a DOM environment so we can use the DOM API to query and traverse the DOM tree. This way of querying components is most similar to the real behaviour of a user, e.g. finding a form input by looking for the label text. ByLabelText.

If you are using Jest, you do this by setting your testEnvironment config to jsdom. A project boostrapped using Create React App will have this as a default.

/**
 * @jest-environment jsdom
 */

jsdom is a pure-JavaScript implementation of many web standards, notably the WHATWG DOM and HTML Standards, for use with Node.js. In general, the goal of the project is to emulate enough of a subset of a web browser to be useful for testing and scraping real-world web applications.

Wrapping up

Done badly, testing can introduce unwanted complexity to the development process. Knowing the difference between these types of tools can help in writing well defined tests that behave as expected, and improve the developer and user experience.