This post is part of the series 30 Days of React.

In this series, we're starting from the very basics and walk through everything you need to know to get started with React. If you've ever wanted to learn React, this is the place to start!

Testing the App

Edit this page on Github

Let's start by looking at one feature of our application and thinking about where the edge cases are and what we assume will happen with the component.

Let's start with the Timeline component as it's the most complex in our current app.

The Timeline component dispays a list of statuses with a header with a dynamic title. We'll want to test any dynamic logic we have in our components. The simplest bit of logic we have to start out with our tests are around the dynamic title presented on the timeline.

We like to start out testing by listing our assumptions about a component and under what circumstances these assumptions are true. For instance, a list of assumptions we can make about our Timeline component might include the following:

  • Under all circumstances, the Timeline will be contained within a <div /> with the class of .notificationsFrame
  • Under all circumstances, we can assume there will be a title
  • Under all circumstances, we assume the search button will start out as hidden
  • There is a list of at least four status updates

These assumptions will translate into our tests.

Testing

Let's open the file src/components/Timeline/__tests__/Timeline-test.js. We left off with some dummy tests in this file, so let's clear those off and start with a fresh describe block:

describe('Timeline', () => {
  // Tests go here
})

For every test that we write against React, we'll want to import react into our test file. We'll also want to bring in the react test utilities:

import React from 'react';
import TestUtils from 'react-addons-test-utils';

describe('Timeline', () => {
  // Tests go here
})

Since we're testing the Timeline component here, we'll also want to bring that into our workspace:

import React from 'react';
import TestUtils from 'react-addons-test-utils';

import Timeline from '../Timeline';

describe('Timeline', () => {
  // Tests go here
})

Let's write our first test. Our first assumption is pretty simple to test. We're testing to make sure the element is wrapped in a .notificationsFrame class. With every test we'll write, we'll need to render our application into the working test document. The react-addons-test-utils library provides a function to do just this called renderIntoDocument():

import React from 'react';
import TestUtils from 'react-addons-test-utils';

import Timeline from '../Timeline';

describe('Timeline', () => {

  it('wraps content in a div with .notificationsFrame class', () => {
    const wrapper = TestUtils.renderIntoDocument(<Timeline />);
  });

})

If we run this test (even though we're not setting any expectations yet), we'll see that we have a problem with the testing code. React thinks we're trying to render an undefined component:

Let's find the element we expect to be in the DOM using another TestUtils function called findRenderedDOMComponentWithClass().

The findRenderedDOMComponentWithClass() function accepts two arguments. The first is the render tree (our wrapper object) and the second is the CSS class name we want it to look for:

import React from 'react';
import TestUtils from 'react-addons-test-utils';

import Timeline from '../Timeline';

describe('Timeline', () => {

  it('wraps content in a div with .notificationsFrame class', () => {
    const wrapper = TestUtils.renderIntoDocument(<Timeline />);
    const node =
    TestUtils
      .findRenderedDOMComponentWithClass(wrapper, 'notificationsFrame');
  });

})

With that, our tests will pass (believe it or not). The TestUtils sets up an expectation that it can find the component with the .notificationsFrame class. If it doesn't find one, it will throw an error and our tests will fail.

As a reminder, we can run our tests using either the npm test command or the yarn test command. We'll use the yarn test command for now since we're testing one component:

yarn test

With our one passing test, we've confirmed our test setup is working.

Unfortunately, the interface for TestUtils is a little complex and low-level. The enzyme library wraps TestUtils, providing an easier and higher-level interface for asserting against a React component under test. We'll discuss enzyme in detail tomorrow.

Great job today and see you tomorrow!


Ari Lerner

Hi, I'm Ari. I'm an author of Fullstack React and ng-book and I've been teaching Web Development for a long time. I like to speak at conferences and eat spicy food. I technically got paid while I traveled the country as a professional comedian, but have come to terms with the fact that I am not funny.

Connect with Ari on Twitter at @auser.