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:
Let’s get started.
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.
@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:
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.
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:
fn()
method from the @storybook/test
package, we are mocking and spying on the handleTextChange()
action within the args object is being mocked and spied.type()
method from the canvasElement
method to call the handleTextChange
function as it types in mock characters into the input field. toHaveBeenCalled()
assertion on the handleTextChange()
action spy in the args
object to confirm that handleTextChange
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!
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.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowExplore use cases for using npm vs. npx such as long-term dependency management or temporary tasks and running packages on the fly.
Validating and auditing AI-generated code reduces code errors and ensures that code is compliant.
Build a real-time image background remover in Vue using Transformers.js and WebGPU for client-side processing with privacy and efficiency.
Optimize search parameter handling in React and Next.js with nuqs for SEO-friendly, shareable URLs and a better user experience.