Testing React Components


5 years ago -  
React

create-react-app comes with a built-in test runner called Jest which is basically a tool for executing unite tests and also reporting the result. To run the test files in projects, all we need to do is type in npm run test command. This command searches for all test files in the project and executes them one after another. Once the tests have been run, it enters into watch mode, which means that whenever we change the test files in goes and re-run them.

There are two approaches that we can use for testing a component:

  • Shallow rendering
  • Full rendering

Shallow rendering

Shallow rendering allows us to render a component without rendering its children. It means that it isolates the component from its children. This type of rendering makes more sense when testing a component’s functionality. For example, let’s say we have a blog application and want to check if the App component contains a header:

import React from "react";
import Adapter from "enzyme-adapter-react-16";
import Enzyme, { shallow } from "enzyme";
import App from "./App";
import { Header } from "./components/Header";

Enzyme.configure({ adapter: new Adapter() });

it("renders app component", () => {
  const wrapper = shallow(<App />);
  const header = <Header />;
  expect(wrapper.contains(header)).toEqual(true);
});

Since the test is using shallow rendering, the child components are not used to render it means that only the App component’s state and props are used for when rendering the content and its children are not rendered:

<Fragment>
  <div className="columns">
    <div className="column">
      <Header />
    </div>
  </div>
  <div className="container">
    <div className="columns">
      <div className="column is-8">
        <List />
      </div>
      <div className="column is-4">
        <AuthorList />
      </div>
    </div>
  </div>
</Fragment>

Full rendering

Full rendering means that the App component children are fully rendered:

it("renders app component", () => {
  const wrapper = mount(<App />);
  const header = <Header />;
  expect(wrapper.contains(header)).toEqual(true);
});

Which produeces the following output.

<App>
  <div className="columns">
    <div className="column">
      <header>
        <nav className="navbar is-primary">
          <div className="navbar-brand">
            <a className="navbar-item" href="https://myblog.com">
              <h1>My Blog</h1>
            </a>
            <div className="navbar-burger burger">
              <span />
              <span />
              <span />
            </div>
          </div>
          <div className="navbar-menu">
            <div className="navbar-start">
              <a className="navbar-item" href="/home"> Home </a>
              <a className="navbar-item" href="/posts"> Posts </a>
            </div>
          </div>
        </nav>
      </header>
    </div>
  </div>
  <div className="container">
    <div className="columns">
      <div className="column is-8">
        <List>
          <h1 className="title">Latest posts</h1>
          <div className="box">
            <ActionButton text="Sort" callback="{[Function]}">
              <button className="button is-primary" onClick="{[Function]}">
                Sort
              </button>
            </ActionButton>
          </div>
          <div id="boxDiv" className="box">
            <Post post="{{...}}">
              <div className="panel">
                <p className="panel-heading">Post1</p>
                <section className="panel-block">
                  <p>Hello</p>
                </section>
              </div>
            </Post>
            <Post post="{{...}}">
              <div className="panel">
                <p className="panel-heading">Post2</p>
                <section className="panel-block">
                  <p>Hello</p>
                </section>
              </div>
            </Post>
            <Post post="{{...}}">
              <div className="panel">
                <p className="panel-heading">Post3</p>
                <section className="panel-block">
                  <p>Hello</p>
                </section>
              </div>
            </Post>
            <Post post="{{...}}">
              <div className="panel">
                <p className="panel-heading">Post4</p>
                <section className="panel-block">
                  <p>Hello</p>
                </section>
              </div>
            </Post>
          </div>
        </List>
      </div>
      <div className="column is-4">
        <AuthorList>
          <h1 className="title">Authors</h1>
          <ul className="list">
            <a href="/" className="list-item"> Sirwan Afifi </a>
          </ul>
        </AuthorList>
      </div>
    </div>
  </div>
</App>