CS 312 Software Development

Lecture 10 - React testing

Testing React

Testing functions like the ones you wrote for assignment 1 is conceptually straightforward. You call a function and get a result. You compare the result against what you expect the function to return and they either match or they don't. As we saw, it is not necessarily simple, and it takes some effort to make sure that our tests abide by our F.I.R.S.T. principles, but it is still relatively straightforward.

When we start thinking about testing websites built with a framework like React, we have a couple of new challenges. How do we automatically test to make sure the website looks right? How do we test functionality that is driven by user interaction (like clicking and filling in forms)?

The answer is that we need more tools. We will be using the Testing Library.

The Testing Library

The Testing Library provides a set of utilities specifically for testing web pages and user interaction.

The library is opinionated, which is to say it was written with a particular view as to how to write tests, and it enforces that view on its users (opinionated tools are not a bad thing if you buy into the underlying philosophy, if you don't, well...).

The more your tests resemble the way software is used, the more confidence they can give you. [Kent C. Dodds]

In essence, the library is designed to promote testing DOM elements instead of React components. So, you render your component using the library and the there are a number of queries we can use for finding content within the rendered DOM.

You are encouraged to visit the documentation for details of its use.

Mocking fetch

One of the issues we run into when testing is that our components may rely on getting information from the server via fetch. This obviously is problematic for our testing. It means that our tests are not Independent (other tests will alter the state on the server, and we don't have a simple mechanism for resetting), nor are the Repeatable (content on the server can change, or the server can go down).

Our solution is to mock the fetch call. This can be tricky because the server is providing somewhat complex behavior and normal fetch operations are asynchronous, so we need to mimic that. Fortunately, we have another library: fetch-mock-jest.

This provides a mock server that we can configure to react like the real one. We can easily specify the behavior for different routes, and it handles the creation of all of the Promises for us.

here is an example of it in action:

beforeAll(() => {
    localFilms = films.map((film) => ({ ...film }));

    fetchMock.reset();
    fetchMock.get(
      'http://basin.cs.middlebury.edu:3042/api/films',
      () => localFilms
    );
    fetchMock.put(
      'http://basin.cs.middlebury.edu:3042/api/films/102',
      (url, options) => {
        const id = 102;

        const modifiedFilm = JSON.parse(options.body);
        localFilms = localFilms.map((film) => {
          if (id === film.id) {
            return modifiedFilm;
          } else {
            return film;
          }
        });
        return modifiedFilm;
      }
    );

Last updated 03/30/2021