Back to blog

Storybook 8.2

Towards no-compromise component testing

loading
Michael Shilman
@mshilman
Last updated:

Storybook is the component workshop behind the world’s top design systems (Carbon, Polaris, Fluent, Lightning, etc.). Accordingly, it is often associated with building and documenting atomic components for reuse.

But UI components come in many sizes and shapes.

For teams at Faire, Yoobic, and Monday.com, Storybook is the tool of choice for “product UI” such as shopping carts, dashboards, chat widgets, calendars, and full pages. These are complex, stateful components, and high quality tests give the teams confidence to build and iterate.

That’s why we’re beefing up testing in Storybook. I’m excited to announce Storybook 8.2, the next stop on our journey to no-compromise component testing:

  • 🪝 New test hooks for parity with other popular testing tools
  • 🧳 Portable stories for reuse in other testing and docs tools
  • 📦 Package consolidation to reduce dependency conflicts
  • 🛼 Streamlined onboarding to get new users up to speed
  • ✨ New and improved website with better framework docs
  • 💯 Hundreds more improvements

New test hooks

Modern testing tools like Jest/Vitest/Playwright/Cypress all use Jasmine test constructs. Each tool syntax varies slightly, but they all boil down to the following test hooks: before/afterAll, before/afterEach, describe , and test.

Storybook has its own story syntax, Component Story Format (CSF). CSF is the best way to capture examples of components in their various states. In Storybook 6.4, we added play functions to make it possible to script interactions and assertions:

// ToolbarMenu.stories.js
import { fn, expect } from '@storybook/test';
import { ToolbarMenu } from './ToolbarMenu';

export default { component: ToolbarMenu };
export const Disabled = {
  args: { disabled: true, onSelected: fn() },
  play: async ({ canvas, args }) => {
    await userEvent.click(canvas.getByRole('button'));
    expect(args.onSelected).not.toHaveBeenCalled();
  },
};

Using the play function, it’s been possible to create many Jasmine-style tests in Storybook. But not all of them. And if you’re coming from another testing tool there has been a learning curve to translate your tests into CSF.

No more. In Storybook 8.2, we’ve introduced before hooks (which can return cleanup functions, to serve as after hooks) and an optional mount argument to play (for React, Vue 3, and Svelte). Now you can write component tests with the same control flow as you would in a Jasmine-style tool, where you are able to “arrange, act, and assert” all within a single play function:

// ToolbarMenu.stories.jsx
import { fn, expect } from '@storybook/test';
import { ToolbarMenu } from './ToolbarMenu';

export default {
  component: ToolbarMenu,
};

export const Disabled = {
  args: { disabled: true, onSelected: fn() },
  play: async ({ mount, args }) => {
    // Arrange
    const items = await loadItems(10);
    const canvas = await mount(<ToolbarMenu items={items} />);
    
    // Act
    await userEvent.click(canvas.getByRole('button'));
    
    // Assert
    expect(canvas.getAllByRole('button').length).toBe(items.length);
    expect(args.onSelected).not.toHaveBeenCalled();
  },
};

It’s a non-breaking change so all of your existing stories will continue to work as before. And the recommended way to write stories (using an implicit mount) has not changed either. However, when you need the extra power, the new test hooks are there for you.

“First time I use @storybookjs play tests. OMG! 🥰 Never written tests so fast!!”
@brechtilliet

Check out the docs and stay tuned for a full feature announcement and more hooks examples in the weeks to come!

Portable stories

Storybook is the best tool for iteratively building, documenting, and testing your components. But there are plenty of other amazing tools in the JS ecosystem, and we want you to be able to use your stories in those as you see fit.

In 8.1, we released a limited form of “portable stories” for Playwright Component Tests. Now in 8.2, I’m happy to present Portable Stories for React and Vue 3, with experimental Svelte support. This allows you to ergonomically turn a story into a “native” component for your framework, bundled with some extra code to run any test hooks that a story might have:

// Button.test.js
import { test, expect } from 'vitest';
import { screen } from '@testing-library/react';
import { composeStories } from '@storybook/react';
 
// Import all stories and the component annotations from the stories file
import * as stories from './Button.stories';
 
// Every component that is returned maps 1:1 with the stories,
// but they already contain all annotations from story, meta, and project levels
const { Primary, Secondary } = composeStories(stories);
 
test('renders primary button with default args', async () => {
  /**
   * Runs through story lifecycle:
   * 1. loaders
   * 2. beforeEach
   * 3. render w/ decorators (and other annotations)
   * 4. play fn (including mount, when used)
   * 5. cleanup (from beforeEach, hooks)
   */
  await Primary.run();
});

In addition to the API, we’ve prepared additional documentation for how to reuse your stories in Vitest and Jest. Check out the docs and we’ll post a full feature announcement soon.

Consolidated dependency management

With 20k+ devs surveyed, the State of JS survey is the pulse of the JS ecosystem. After a drop in 2022, our hard work to improve Storybook paid off with amazing results in 2023. The biggest gripe this time around was poor dependency management: bloat, install footprint, and version conflicts.

In 8.2, we’re starting to tackle this. We’ve consolidated 18 packages into a single core package, storybook, and a set of satellite packages for builders/renderers/addons. This is a non-breaking change to follow Vite’s package structure. In addition, we’re bundling in many of Storybook’s dependencies to eliminate version conflicts.

We’ve also been collaborating with James Garbutt, lead of the Ecosystem Performance (e18e) project, to upgrade our utility libraries to smaller/faster/more modern versions (see ya doctrine! 👋).

This effort is still in its early days, but so far we’ve managed to reduce install size/time by ~20%. And the new consolidated structure sets us up for future optimizations, so keep an eye out for even bigger drops in 8.3 and beyond.

Streamlined onboarding

Another area we’re focused on is onboarding experience. Thousands of developers try Storybook every week, but the road from install to becoming a successful user is fraught with pitfalls. In Storybook 8.2, we’ve refreshed the onboarding experience and expanded it from React to Vue 3 and Angular, to help point users in the right direction:

0:00
/0:24

Stay tuned as we extend this experience in 8.x to make Storybook easier to configure in your project.

New and improved docs site

Storybook has a brand new docs site! It includes:

  • ✨ New homepage with a new, fully responsive animation that better illustrates Storybook’s many features
  • 📚 New docs home with dedicated landing pages per framework (Next.js, SvelteKit, etc.)
  • 🌙 Docs light/dark mode to match your system settings
  • 🧱 Foundational work to enable further improvements, faster iteration
Screenshot of new docs site, half in light mode, half in dark

Hundreds more improvements

In addition to the features above, every Storybook release contains hundreds of improvements and bug fixes at every level. Some highlights:

Try it today!

Storybook 8.2 is available today. Try it in a new project:

npx storybook@latest init

Or upgrade an existing project:

npx storybook@latest upgrade

If you’re upgrading from 7.x, we have a guide to help you. We also have a guide for migrating from older versions.

What’s next

We’re got a bunch of stuff cooking for 8.3:

  1. Integrating with Vitest for blazing fast component testing
  2. Adding Vite support to our Next.js framework for Vitest compatibility and better DX
  3. Story tags with UI for interactive sidebar filtering
  4. Further reducing install size (try out 8.3-alpha that’s another 40% smaller!)
  5. Story globals, a cleaner way to write stories for specific viewports, themes, and locales

For an up-to-date view on what we’re working on and considering, please check out Storybook’s new roadmap.

Credits

Huge shoutout to the 39 contributors whose PRs feature in Storybook 8.2!

@43081j @64bitasura @alexatvista @alirezaebrahimkhani @benmccann @cdedreuille @cherry @cosielq @dario-baumberger @deiga @dexofthewild @edoardocavazza @ghengeveld @girgetto @jonniebigodes @jreinhold @kasperpeulen @kevinfoerster @kongallis @kylegach @mnigh @ndelangen @pl12133 @rocktakey @seanparmelee @shilman @simenb @sinnedh @sni-j @superhermione @tmeasday @tobiasdiez @tony19 @valentinpalkovic @vanessayuenn @yannbf @yk-kd @yuheiy

Join the Storybook mailing list

Get the latest news, updates and releases

6,624 developers and counting

We’re hiring!

Join the team behind Storybook and Chromatic. Build tools that are used in production by 100s of thousands of developers. Remote-first.

View jobs

Popular posts

Component testing in Storybook

The future of UI testing
loading
Michael Shilman

Storybook 8.3

Blazing fast component tests
loading
Michael Shilman

State of JS 2023: Fighting back from a sharp left hook

How Storybook uses surveys to guide development
loading
Michael Shilman
Join the community
6,624 developers and counting
WhyWhy StorybookComponent-driven UI
DocsGuidesTutorialsChangelogTelemetry
CommunityAddonsGet involvedBlog
ShowcaseExploreProjectsComponent glossary
Open source software
Storybook

Maintained by
Chromatic
Special thanks to Netlify and CircleCI