Unit testing in React - deploy to production with confidence

Hey Friend, it's Anthony from Fullstack React.

Testing user interfaces can be daunting. Thankfully, in React we have tooling that makes it easy.

Today we're going to look at a tool call Jest to compose our test suite. Jest is the testing framework developed and maintained by Facebook. If you've used other JavaScript testing frameworks like Mocha or Jasmine, you'll find Jest very familiar.

For testing React components, we'll use Enzyme, a testing tool developed by Airbnb and is gaining widespread adoption among the React open-source community. Facebook even recommends the utility in its documentation.

When rendered in the browser, our React components are written to the DOM. While we typically see a DOM visually in a browser, we could load a "headless" one into our test suite. We could use the DOM's API to write and read React components as if we were working directly with a browser. But there's an alternative: shallow rendering.

Normally, when a React component renders it first produces its virtual DOM representation. This virtual DOM representation is then used to make updates to an actual DOM.

When we shallow-render a component, we don't write it to the DOM, but rather construct a virtual DOM representation of it. We can then make assertions against the virtual DOM as though we are making assertions against an actual DOM.

A shallowly rendered component is rendered only one level deep (hence "shallow"), so if the render function of your component contains children, those children won't actually be rendered. Instead, the virtual DOM representation will just contain references to the un-rendered child components.

React provides a library for shallow rendering React components, ReactTestUtils. This library is useful, but is a bit low-level and can be verbose.

Enzyme is a library that wraps ReactTestUtils, providing lots of handy functionality that is helpful for writing React component tests.

Using Enzyme

Instead of using ReactDOM.render() to render a component to a real DOM, you use Enzyme's shallow() to shallow render it.

For example, consider a BookTable component. This component renders a list of books and the amount of inventory for each book. There is a plus and minus icon adjacent to each which allows the user to adjust the inventory figure:

 
const BookTable = (props) => (
  <table>
    <thead>
      <tr>
        <th>Title</th>
        <th>Author</th>
        <th># in inventory</th>
        <th></th>
        <th></th>
      </tr>
    </thead>
    <tbody>
      {
        props.books.map((book)
=> (
          <tr>
            <td>{book.title}</td>
            <td>{book.author}</td>
            <td>{book.inventoryCount}</td>
            <td>
              <i
                className='plus icon'
                onClick={() => props.addInventory(book.id)}
              />
            </td>
            <td>
              <i
                className='minus icon'
                onClick={() => props.removeInventory(book.id)}
              />
            </td>
          </tr>
        ))
      }
    </tbody>
  </table>
);

What the component might look like:

To shallow render it, we call shallow(). Let's provide it with a list of books:

 
const books = [
  {
    title: 'Brave New World',
    author: 'Aldous Huxley',
    inventoryCount: '96',
    id: 1,
  },
  {
    title: 'Catch-22',
    author: 'Joseph Heller',
    inventoryCount: '22',
    id: 2,
  },
];

const wrapper = Enzyme.shallow(
  <BookTable
    books={books}
  />
);

Here, wrapper is an EnzymeWrapper object. Inside of this object is our React component with its virtual DOM representation. We can call methods on this wrapper to hunt through the component's output and make assertions on what it looks like.

For example, imagine if we wanted to assert that the output contains the title of the first book.

Don't worry if you are unfamiliar with Jest or haven't written tests with JavaScript before. We work through these concepts in the unit testing chapter of Fullstack React. For now, hopefully you can get the gist of what this is doing:

 
// Assert that output contains the title of the
first book
const td = wrapper.find('td').first();
expect(
  td.text()
).toEqual('Brave New
World');

We begin by finding the first td element. We then call text() to get the inner-text of that tag. We assert that it equals 'Brave New World'.

We use a CSS selector in find() to pick out the element we want to write an assertion for. Enzyme's support for CSS selectors makes traversing the virtual DOM a cinch.

We can even use Enzyme to simulate clicks. Imagine if we rendered our BookTablecomponent again, except this time we specified one of its prop-functions, like addInventory:

 
const addInventory = (bookId) => (
  console.log(`Called with ${bookId}!`)
);

const wrapper = Enzyme.shallow(
  <BookTable
    books={books}
    addInventory={addInventory}
  />
);

Now, we just need to find the plus icon in our component's output. We can then use simulate() to simulate a click and see that the addInventory function has been called:

 
const icon = wrapper.find('i').first();
icon.simulate('click');
// -> "Called with 1"

Approaching a React component as a module, we write two different kinds of specs for our components:

  1. Given a set of inputs (state & props), assert what a component should output (render).
  2. Given a user action, assert how the component behaves. The component might make a state update or call a prop-function passed to it by a parent.

Hopefully this gives you a taste on how we can write reliable, testable components with React.

Never wince again as you deploy to production. Sleep soundly knowing that your recent refactor didn't introduce a litany of new bugs for your users to discover.

Cheers!

Anthony

P.S.

In the unit testing chapter of the book, armed with Jest and Enzyme, we go deepdetailing how to use these tools to write comprehensive unit tests. Along the way, we explore best practices for organizing unit tests that scale well alongside an application's complexity.

We survey tons of examples, including a component that interfaces with an API. Read the chapter, play with the sample code, and then go write tests for your React components with confidence.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值