Megan Lee
Posted on February 22, 2024
Written by Nwani Victory
✏️
Since its relaunch in 2017, Storybook has become an indispensable tool for frontend developers to test and maintain modular frontend components in isolation. Storybook supports all major frontend frameworks and libraries, including React, Angular, Vue, Svelte, and a host of others.
In this tutorial, we’ll spotlight the recently released @storybook/test package
, highlighting its new APIs and how it improves on the existing @storybook/jest
and @storybook/testing-library
packages. To follow along with the hands-on steps in this tutorial, which will demonstrate the use of the @storybook/test
package within a demo Next.js application, you will need:
- Node.js to run the demo Next.js application locally
- A basic understanding of Storybook
- A basic understanding of the JavaScript programming language
Let's get started.
Understanding Storybook Test
Storybook Test is a new test environment that combines the APIs of @storybook/jest
and @storybook/testing-library
into a single package. Its purpose is to improve the DX of Storybook, and it does so in many ways.
Consolidating these tools gives you fewer configuration requirements. You also no longer need to have the @storybook/jest
and @storybook/testing-library
packages installed, as you can import the test utilities from them through the @storybook/test
package, making the project more lightweight.
The new test environment is also powered by Vitest, allowing you to import utilities from the @vitest/spy
and @vitest/expect
packages. Leveraging Vitest helps boost speed and introduces some new testing patterns to help decrease load times.
Since releasing Storybook Test, Storybook has encouraged developers to adopt explicit action args as a new pattern when writing actions and spies for stories. This approach improves the performance of large stories. Additionally, as explicit action args don't depend on docgen to autogenerate function mocks, they enable us to add types to the action args. They also ensure that the Play
function has consistent results, which we’ll discuss more later.
The next section of this tutorial will demonstrate using explicit action args while writing interaction tests for the components within a demo application.
Testing stories with @storybook/test
To keep the focus on Storybook, we will be testing the components within a pre-built Next.js application. The components in the application were designed in the public Style Guide Starter board from the Figma community. The application also uses Tailwind CSS to style the elements.
Launch the terminal or command prompt application of your choice. Then, execute the command below to clone the pre-built application from its GitHub repository:
git clone https://github.com/vickywane/storybook-test.git
You can also manually download the project folder from the repository. The complete code for this tutorial is within the feat/storybook-test
branch of the repository.
Run the following commands to change the directory into the cloned project and install its dependencies:
#change directory into project
cd storybook-test
#install project dependencies
npm install
At this point, the prebuilt application does not have Storybook installed or any stories to test. The next sections will guide you on how to set up Storybook with the latest versions that come with the @storybook/test
package.
Run the following command to preview the application before you move on to adding Storybook for the individual components:
npm run dev
As shown in the following image, navigating to http://localhost:3000 will display the demo Next.js application:
Setting up Storybook in the prebuilt application
Execute the following init
command to add the latest version of Storybook into the application via the interactive CLI:
npx storybook@latest init
The CLI is smart enough to automatically install relevant dependencies and set up Storybook based on the existing frontend technologies being used in your project. When you perform this fresh setup of Storybook, @storybook/test
is one of the packages that the init
command will add to your project.
You will need to execute the following upgrade command if you were using an existing setup of the older Storybook versions:
npx storybook@next upgrade
After the update, you will then need to install the @storybook/test
package manually.
Writing stories using Storybook Test
At this point, you have Storybook fully set up in the demo Next.js application. The previous init
command creates boilerplate Storybook components and examples to give you a good starting point.
Let’s create stories for the TextInput
and ProjectDetailsForm
components within the application. Each of these two stories will use some of the new features from the @storybook/test
package.
First, create a TextInput.stories.tsx
file within the stories
directory to create a story for the TextInput
component. Add the content of the code block below into this file. The code renders the TextInput
component in the single default state:
import { userEvent, within, expect, fn } from "@storybook/test";
import TextInput from "../components/TextInput";
import { Meta, StoryObj } from "@storybook/react";
const meta: Meta<typeof TextInput> = {
title: "TextInput",
component: TextInput,
};
export default meta;
type Story = StoryObj<typeof TextInput>;
const MOCK_LABEL = 'Project Label'
export const Default: Story = {
tags: ["autodocs"],
args: {
label: MOCK_LABEL,
placeholder: "Enter project label name",
type: "text",
handleTextChange: fn(),
},
play: async ({args, canvasElement }) => {
const canvas = within(canvasElement);
const labelElement = canvas.getByTestId("label-element")
const inputElement = canvas.getByTestId("input-element");
await userEvent.type(inputElement, "Sample Project Name", {
delay: 50,
})
await expect(labelElement.innerHTML).toBe(MOCK_LABEL)
await expect(args.handleTextChange).toHaveBeenCalled();
},
};
The main focus of the story above is on the interaction tests for the TextInput
component through the Play function:
- Using the
fn()
method from the@storybook/test
package, we are mocking and spying on thehandleTextChange()
action within the args object is being mocked and spied. - Within the tests, we expect the
type()
method from thecanvasElement
method to call thehandleTextChange
function as it types in mock characters into the input field. - We can then use the
toHaveBeenCalled()
assertion on thehandleTextChange()
action spy in theargs
object to confirm thathandleTextChange
is being called as expected.
Note that the expect
, within
, and userEvent
testing utilities now come from the single @storybook/test
package rather than the @vitest/spy
, @storybook/testing-library
, and @storybook/jest
packages.
The image below shows the interaction tests within the TextInput
story being executed: With the TextInput.stories.ts
file, you now have your first story using the @storybook/test
package to perform interaction tests!
Conclusion
Congratulations on completing this tutorial! We explored the @storybook/test
package, why the Storybook team consolidated the @storybook/jest
and @storybook/testing-library
, and the significant performance benefits of adopting the explicit action args pattern to make your stories independent of docgen.
I hope you found this article interesting and useful as you set up or upgrade your Storybook projects to use the @storybook/test
package.
Get set up with LogRocket's modern error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side.
NPM:
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Script Tag:
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
3.(Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
Posted on February 22, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.