Storybook 8.2
Towards no-compromise component testing
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:
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
Hundreds more improvements
In addition to the features above, every Storybook release contains hundreds of improvements and bug fixes at every level. Some highlights:
- ✅ Webpack5/Vite: Fix sourcemaps - #27171, thanks @valentinpalkovic!
- ✅ Angular: Allow format configuration of source preview - #28305, thanks @64BitAsura!
- ✅ CLI: Add
--no-dev
option toinit
- #26918, thanks @fastfrwrd! - ✅ CLI: Include
@storybook/addon-svelte-csf
in new projects - #27070, thanks @benmccann - ✅ Core: Fix startup hang caused by watchStorySpecifiers - #27016, thanks @heyimalex!
- ✅ Vue3: Enable new hydration mismatch compile time flag - #27192, thanks @Cherry
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:
- Integrating with Vitest for blazing fast component testing
- Adding Vite support to our Next.js framework for Vitest compatibility and better DX
- Story tags with UI for interactive sidebar filtering
- Further reducing install size (try out 8.3-alpha that’s another 40% smaller!)
- 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