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-dom/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-dom/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-dom/test-utils
library provides a function to do just this called renderIntoDocument()
:
import React from "react";
import TestUtils from "react-dom/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-dom/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!