Storybook
Published in

Storybook

How to use Testing Library to test Storybook

Storybook is the best way to develop UI components in isolation. Teams write hundreds or even thousands of stories to catalog all their key component states. This is incredibly useful for prototyping, documentation, review, and more. So useful that it’s used by teams at Github, Netflix, and Spotify and many others.

Today, I’m excited to introduce @storybook/testing-react, a new library that makes Storybook even more useful by helping you to reuse stories in Testing Library. I’ll show how this is useful for a wide variety of scenarios, ranging from simple atomic components to full-blown pages.

The problem

You are using Storybook for your components and writing tests for them with jest, most likely alongside React testing library. In your Storybook stories, you already defined the scenarios of your components. You also set up the necessary decorators (theming, routing, state management, etc.) to make them all render correctly. That is great.

Concept of a storybook configuration

However, when you’re writing tests, you also have to define scenarios of your components, as well as set up the necessary decorators. By doing the same thing twice, you feel like you’re spending too much effort, making writing and maintaining stories/tests become less like fun and more like a burden.

Concept of a testing library configuration

@storybook/testing-react is a utility tool that allows you to compose your component's stories, along with all of the setup you have done already in your Storybook, in your Testing Library tests. That means you can reuse stories in tests without needing to maintain multiple test setups.

Presenting @storybook/testing-react

Demo 1: A themed button

An example of a themed button

Even an atomic component, such as a Button, can have various configurations and states. Here's a themed button using styled components:

In order to render the button anywhere (on your App, tests or Storybook), it's necessary to wrap it in a styled components theme provider, given that it needs properties from the theme, such as color and boxShadow. In Storybook, you will likely have a decorator that provides the theming, either globally or in your stories file:

In the tests, you need to recreate the states again and also wrap the Button component in the theme provider, which might look like this:

You might have noticed that we ended up doing very similar things, twice.

With @storybook/testing-react, you can reuse the stories in your tests, alongside all of the setup you've done for them, such as args, decorators, and global decorators. The library exposes a function called composeStories, which you pass your component stories, and it gives you back every component (with autocompletion if you're using typescript!), composed with their necessary setup.

This way, when writing test, you can just reuse your stories, not having to care to setup the theme provider or the component props, anymore, as it's all already done in Storybook:

The example of a simple button might not be very appealing, but the more context you add to components, the more this library shines.

Consider writing stories for an entire page, as the most leading edge teams are doing, such as the UN World Food Program:

Interactive page with wizard form from UN World Food Program Storybook

Such page might need quite a few contexts, which makes double effort becomes even bigger when writing stories and tests. Let's see how @storybook/testing-react helps in such cases.

Demo 2: A page component

Suppose you have a ProfilePage component.

Say this component requires routing, state management and a theme from styled components. It has the following states: Success, Loading, Error and NotFound.

When writing a basic test for this component, you might need to make a big setup for the component to render correctly. Look at the amount of decorators that are needed in the render function:

If the ProfilePage is also on Storybook, most likely you have global decorators for styled components and state management support. In the stories file, you might setup local decorators for specific routing configuration, maybe even a few args. If all of that setup is already done, why not just.. reuse it?

Here’s what the test would look like if you used @storybook/testing-react:

See what just happened here? We abstracted the configuration phase (as it was already done in Storybook) and focused on choosing the possible states we can use in the tests. It feels like now you have a catalog of pre-configured component states (Success, Loading, etc.) that you can just pick and use in the tests. How cool is that?

The cherry on top is that as soon as you start refactoring your components/features/pages, you might end up changing your stories, and that will directly impact the tests as well. This means that updating your tests will be come easier, and that is if you even need to update them. At the end, you have less maintenance work and more fun!

Get started

If you’re interested in trying this out, here is how you can add it to your project.

This library should be installed as one of your project’s devDependencies:

npm install --save-dev @storybook/testing-reactoryarn add --dev @storybook/testing-react

Global config

This is an optional step. If you don’t have global decorators or don't want them to be applied, there’s no need to do this.

If you have global decorators/parameters/etc and want them applied to your stories when testing them, you first need to set this up. You can do this by adding to or creating a jest setup file:

// setupFile.js - this will run before the tests in jest.
import { setGlobalConfig } from '@storybook/testing-react';
// path of your preview.js file
import * as globalStorybookConfig from './.storybook/preview';
setGlobalConfig(globalStorybookConfig);

For the setup file to be picked up, you need to pass it as an option to jest in your test command:

// package.json
{
"test": "react-scripts test --setupFiles ./setupFile.js"
}

Usage - composeStories

composeStories will process all stories from the component you specify, compose args/decorators in all of them and return an object containing the composed stories.

If you use the composed story (e.g. PrimaryButton), by default the component will render with the args that are passed in the story. However, you are free to pass any props on top of the component, and those props will override the default values passed in the story’s args.

Usage — composeStory

You can use composeStory if you wish to apply it for a single story rather than all of your stories. You need to pass the meta (default export) as well.

That’s it! If you reached till this part of the article, thanks a lot for your time and interest! I'm looking forward to hearing your thoughts and feedback!

Get involved

@storybook/testing-react was developed by Yann Braga (me!) with great support and feedback from Tom Coleman, Aaron Reisman, Kyle Gach, Michael Shilman, Clement Dungler, and Dominic Nguyen.

If you are interested in contributing, check out Storybook on GitHub, create an issue, or submit a pull request. Chat with us in Discord — a maintainer is usually online!

What about other frameworks?

Edit: As of May 21st, @storybook/testing-vue was released with the help of Bart Ledoux!

If you liked the concept of @storybook/testing-react and would like to see the same for other frameworks, such as Svelte or Angular and want to help make that happen, we welcome you in the #contributing channel in our Discord. We are always looking for helping hands and it would be a pleasure to have your support in making cool stuff happen!

The UI development environment you'll ♥️ to use.

Recommended from Medium

JWT Authentication in JavaScript in 5 Minutes

Building a scatter-plot with d3.js

The Hidden side of out-of-the-box functions/features

What is Async/Await and How to Use It

Angular Vs React: How to know Which Technology is Better for your Project

Convert BMP to PNG in Node.JS

ERROR TypeError: undefined is not an object (evaluating ‘_this.props.navigation.navigate’)

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Yann Braga

Yann Braga

More from Medium

How to Create React Component Library and Publish to Private GitHub Package Repository

Build and Share React UI Components between Projects using Material UI and Storybook Part-2

Simple React Infinite Scroll using Intersection Observer API

BDD styled TDD with Jest, React, and React Hooks