Testing โ
Stories can be tested with AAA - Arrange, Act, Assert. The story itself arranges the scene, you add acting and assertions.
Vitest Browser Tests โ
The @storybook/addon-vitest addon runs all your stories through Vitest in a real browser (Playwright), including their play functions, which functions contains the test code.
pnpm exec storybook add @storybook/addon-vitestnpx storybook add @storybook/addon-vitestyarn storybook add @storybook/addon-vitestbun x storybook add @storybook/addon-vitestThe wizard wires up a Vitest project in your vite.config.js:
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
import { playwright } from '@vitest/browser-playwright';
import { defineConfig } from 'vite';
const dirname = path.dirname(fileURLToPath(import.meta.url));
export default defineConfig({
// ...
test: {
projects: [
{
extends: true,
plugins: [
storybookTest({
configDir: path.join(dirname, '.storybook'),
storybookScript: 'pnpm storybook --no-open',
}),
],
test: {
name: 'storybook',
browser: {
enabled: true,
provider: playwright({}),
headless: true,
instances: [{ browser: 'chromium' }],
},
},
},
],
},
});Tag your stories so the addon picks them up โ in preview.ts:
export default {
tags: ['vitest'],
}Run them like any Vitest suite.
Interaction Tests โ
The play function is where a story describes behavior: query the canvas, fire events, assert the result.
import { expect, fn } from 'storybook/test';
import Field from './field.gts';
import type { Meta, StoryObj } from 'ember-storybook';
export default {
title: 'Form/Field',
component: Field
} satisfies Meta;
export const Default: StoryObj = {
args: {
submit: fn()
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.type(canvas.getByRole('textbox', { name: 'Title' }), 'abc');
await expect(canvas.getByRole('textbox', { name: 'Slug' })).toHaveValue('abc');
await userEvent.click(canvas.getByRole('button', { name: 'Catalog' }));
await expect(args.submit).toBeCalled();
}
};A play function doubles as living documentation for the interaction โ anyone can watch it run in the browser.
Visual Regression โ
Options that play well with this stack, from the slides' toolkit:
- Chromatic โ Storybook's own, snapshots every story
- Vitest visual regression โ snapshots inside the browser tests above
Continuous Integration โ
As your storybook is injected as a project in vite.config.ts, you can run vitest from CLI and thus run it on your CI system:
pnpm vitestnpm vitestyarn vitestbun vitestLimits Worth Knowing โ
- Route stories render in the canvas only; portable rendering of them is not supported (see Route Stories).
- Switching between a component story and a route story remounts the Ember application โ state does not carry over.