How React Storybook can simplify component testing
Tags: react, storybook
Published: 2019-07-25 17:49:11

---
title: How React Storybook can simplify component testing
published: true
tags: react, storybook
canonical_url: https://blog.logrocket.com/react-storybook/
---

![react storybook](https://thepracticaldev.s3.amazonaws.com/i/5hwijbpj55rjmxgqb247.png)

## Introduction

Every developer wants to build software that works. We can make sure our software’s code works flawlessly by isolating it and showing its behavior in a series of tests. The same can’t be said for our components as they are tested within the context of our app.

Storybook lets you view and interact with your components in an isolated manner. It’s just like unit testing but for UI components. In the words of [Storybook’s documentation](https://storybook.js.org/docs/basics/introduction/):

_Storybook is a user interface development environment and playground for UI components. The tool enables developers to create components independently and showcase components interactively in an isolated development environment._

In this post, we will find out how Storybook can help us create UI components and improve our component testing.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## Getting started with Storybook

Let’s start with bootstrapping a new React project and in it, we’ll install Storybook via CLI:

```jsx
npx create-react-app my-storybook-app
cd my-storybook-app
#install storybook
npx -p @storybook/cli sb init
yarn storybook
```

When running `yarn storybook`, you should see Storybook’s testing page on the local address `http://localhost:9009/`:

![storybook ui](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/07/storybookui.png?resize=1366%2C733&ssl=1)

For the purpose of testing, we’ll create a basic component – a button called `CoffeeButton`. It displays the number of cups of coffee to be served.

```jsx
// /src/stories/CoffeeButton.js
import React, { useState } from 'react';
const ButtonStyle = {
    backgroundColor: 'lightgrey',
    padding: '10px',
    borderRadius: '5px',
    fontSize: '15px',
    border: '#66c2ff 3px solid',
    cursor: 'pointer'
};
const CoffeeButton = ({children}) => {
    const [count, setCount] = useState(1);
    return (
        <button style = {ButtonStyle} onClick = {() => setCount(count + 1)} >
        {new Array(count).fill(children)}
        {(count < 2)
        ? <div> Please serve 1 cup of coffee </div>
        : <div> Please serve {count} cups of coffee </div>
        }
        </button>
    );
};
export default CoffeeButton;
```

Storybook works by using “stories”. A **story** is a function that contains the single state of one component and renders that component to the screen for testing purposes. Let’s write a story for our `CoffeeButton` component. In `src/stories` create a file and name it `CoffeeButtonStory.js`:

```jsx
import React from 'react';
import { storiesOf } from '@storybook/react';
import CoffeeButton from './CoffeeButton';
storiesOf('CoffeeButton', module)
  .add('Black', () => (
    <CoffeeButton>
      <span role="img" aria-label="without-milk">
         🏿
      </span>
    </CoffeeButton>
  ))
  .add('White', () => (
    <CoffeeButton>
      <span role="img" aria-label="with-milk">
        🏼
      </span>
    </CoffeeButton>
));
```

Here’s how our component looks in Storybook:

![](https://thepracticaldev.s3.amazonaws.com/i/nccu3yoohccikek8pp2e.gif)

## UI testing

Storybook offers different techniques for testing UI components. Components need to undergo tests for a variety of reasons some of which are:

- Detection of bugs
- Tests can be documented to serve as guidelines for other developers who will work on the project
- To prevent stuff from breaking during new commits

Let’s go on to examine some of the ways Storybook can make component testing seamless.

## Structural testing

Structural testing involves the testing of a component based on the knowledge of its internal implementation. Storybook implements structural testing through `storyshots` – an add-on that works by comparing snapshots of code. To install `storyshots` run:

```jsx
npm i -D @storybook/addon-storyshots react-test-renderer
```

`react-test-renderer` renders React components to pure JavaScript objects without depending on the DOM. This makes it possible to grab the screenshot of the DOM tree rendered by a React DOM.

After installing, let’s create a test file `storyshots.test.js`, in it we’ll initialize `storyshots`:

```jsx
// src/storyshots.test.js
import initStoryshots from '@storybook/addon-storyshots';  
initStoryshots({ /* configuration options */ });
```

To test a component we run `npm test`. What this does is generate a snapshot where you can inspect the component’s output. Every time you run a test, a snapshot is automatically generated and compared with snapshots generated from previous tests. If `storyshots` spots any differences, the test will fail. Below is a snapshot generated on testing for the first time:

![passed test](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/07/successfultest.png?resize=417%2C259&ssl=1)

Our tests were successful, now let’s try to change something in our `CoffeeButton` component. Change line 16 of `CoffeeButton.js` to:

`? <div> Please DO NOT serve 1 cup of coffee </div>`

On running tests we get the following errors:

![failed test](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/07/failedtest.png?resize=333%2C100&ssl=1)

A more detailed view:

![](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/07/failedtestdetailed.png?resize=466%2C317&ssl=1)

## Automated visual testing

Automated visual testing involves automatically verifying that our UI visually appears as intended. This is useful in cross-browser testing as it can detect lapses that escaped the observations of developers. Storybook tests UI visually via an add-on called `storyshot-puppeteer` . Same as `storyshots`, this add-on works by comparing screenshots – only this time it takes screenshots of the browser and not code. To install `storyshot-puppeteer` run:

```jsx
npm i -D @storybook/addon-storyshots-puppeteer
```

Once installed, to make it compare UI and not code we’ll need to override the test comparison with `imageSnapshot` from the `puppeteer` add-on. We can do this by editing the `initStoryshots` function we created when carrying our structural testing. We’ll also need to specify the URL where our storybook will be running:

```jsx
// src/storyshots.test.js
import initStoryshots from '@storybook/addon-storyshots';
import {imageSnapshot} from '@storybook/addon-storyshots-puppeteer';
initStoryshots({
    test: imageSnapshot({storybookUrl: 'http://localhost:9009/'}),
});
```

Below is a snapshot generated when we test our images for the first time:

![](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/07/passedtestdetailed.png?resize=602%2C365&ssl=1)

Should we change any UI property in our component, our tests will fail and `puppeteer` will return the difference in the form of snapshots. Let’s change a part of our UI. In line 3 of `CoffeeButton.js`, change the background color from `lightgrey` to `lightblue`:

```jsx
backgroundColor: 'lightblue',
```

Now when we run the tests:

![](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/07/test2.png?resize=408%2C132&ssl=1)

Below is a generated snapshot of the difference noticed by `puppeteer` in our UI:

![](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/07/coffeebutton.png?resize=2173%2C180&ssl=1)

In the diffing above, the original image is on the left, the modified image is on the right and the difference between both of them is in the middle.

## Interaction testing

With Interaction testing, Storybook lets you display tests and their results alongside your stories in the DOM. It does this via an addon – `react-storybook-specifications`. To install this addon, run:

```jsx
npm install -D storybook-addon-specifications
```

Then add this line to your `addons.js` file:

```jsx
import 'storybook-addon-specifications/register';
```

`react-storybook-specifications` does not work alone, we still need to install the following:

`enzyme`: JavaScript’s testing utility for React.  
`enzyme-adapter-react-16`: Enzyme’s adapter corresponding to the version of React you’re using.  
`expect`: Jest’s inbuilt method used for checking that values meet certain conditions when writing tests.

To install these add-ons, run:

```jsx
npm install -D enzyme expect enzyme-adapter-react-16
```

In our `config.js` file, we’ll import `configure` and `Adapter` from `enzyme` and `enzyme-adapter-react-16`. Notice that we’ll be having two instances of `configure` now so we’ll need to specify both like this:

```jsx
import { configure as configure1 } from '@storybook/react';
import {configure as configure2} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
function loadStories() {
  require('../src/stories');
}
configure1(loadStories, module);
configure2({ adapter: new Adapter() });
```

Let’s see how this works by testing part of `CoffeeButton` component. In `CoffeeButtonStory.js`, input the following block of code:

```jsx
import React from 'react';
    import { storiesOf } from '@storybook/react';
    import { action } from '@storybook/addon-actions';
    import { specs, describe, it } from 'storybook-addon-specifications';
    import {mount} from "enzyme";
    import expect from "expect";
    import CoffeeButton from './CoffeeButton';
    const stories = storiesOf('CoffeeButton', module)
    stories
    .add('Black', () => {
        const story =
        <CoffeeButton onMouseOver={action('click')}>
        <span role="img" aria-label="without-milk">
        🏿
        </span>
      </CoffeeButton>;
      specs(() => describe('Black', () => {
         it('Should have the following text: 🏿Please serve 1 cup of coffee', () => {
             let output = mount(story);
             expect(output.text()).toContain('🏿Please serve 1 cup of coffee');
         }); 
      }));
      return story;
    })
```

Now save and run the app. In our browser, we should see this:

![](https://thepracticaldev.s3.amazonaws.com/i/c9eps8k6m8ka92p5eegw.gif)

Let’s alter our tests expectations. Change line 20 of `CoffeeButtonStory.js` to:

```jsx
expect(output.text()).toContain('🏿Please serve a cup of coffee');
```

Now when we run the app and check out our browser, this is what we get:

![](https://thepracticaldev.s3.amazonaws.com/i/zi1zvjqddm45vmq663ki.gif)

As can be seen, changing our expected output will render an error to the DOM. Interaction testing via `storybook-addon-specifications` enables us to have a `living` documentation, where we can interact with our components and their test results side by side.

## Conclusion

Storybook provides a great way to test our UI components. It may seem like we are doing away with unit testing but that’s not the case. Unit testing aims at finding out what went wrong with code. In this case, we’re testing React components and if something went wrong with our UI we would still ask questions about what markup we have to fix.

This implies that integration and snapshot tests are as good as unit tests – in this context. Should you want to play around with code, you can always check out the source code [here](https://github.com/fullstackmafia/react-storybook-app) on Github.
* * *
## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
[Try it for free](https://logrocket.com/signup/).
* * *
The post [How React Storybook can simplify component testing](https://blog.logrocket.com/react-storybook/) appeared first on [LogRocket Blog](https://blog.logrocket.com).