Storybook is a frontend workshop for building UI components and pages in isolation. Storybook with Vitest also enables interactive component testing.
This post guides you through setting up Storybook with Angular using Vite and the @storybook/addon-vitest package for interactive component testing.
Setting up Storybook
If you don't have Storybook setup already, run the following command to initialize Storybook for your project:
npx storybook@latest init --type angular
This installs the necessary Storybook dependencies and sets up a Storybook with example components including a Button component.
Follow the provided prompts, and commit your changes.
Setting up Storybook to use Vite with Analog
Install the AnalogJS Storybook Angular integration:
npm install @analogjs/storybook-angular @angular/animations zone.js --save-dev
Update the .storybook/main.ts file to use the @analogjs/storybook-angular package:
import { StorybookConfig } from '@analogjs/storybook-angular';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: {
name: '@analogjs/storybook-angular',
options: {},
},
};
export default config;
Update the angular.json storybook targets to use the @analogjs/storybook-angular builders:
"storybook": {
"builder": "@analogjs/storybook-angular:start-storybook",
"options": {
"configDir": ".storybook",
"styles": ["src/styles.css"],
"experimentalZoneless": true
}
},
"build-storybook": {
"builder": "@analogjs/storybook-angular:build-storybook",
"options": {
"configDir": ".storybook",
"styles": ["src/styles.css"],
"experimentalZoneless": true
}
}
Run Storybook to verify everything works:
npm run storybook
Setting up Vitest for Interaction Testing
Install the Vitest addon and dependencies:
npm install @analogjs/vitest-angular @storybook/addon-vitest vitest @vitest/browser-playwright --save-dev
Add the addon to your .storybook/main.ts:
import { StorybookConfig } from '@analogjs/storybook-angular';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-vitest',
],
framework: {
name: '@analogjs/storybook-angular',
options: {},
},
};
export default config;
Create a .storybook/vitest.setup.ts file:
import '@angular/compiler';
import { setProjectAnnotations } from '@analogjs/storybook-angular/testing';
import { beforeAll } from 'vitest';
import * as projectAnnotations from './preview';
const project = setProjectAnnotations([projectAnnotations]);
beforeAll(project.beforeAll);
Update .storybook/tsconfig.json to include the setup file:
{
"extends": "../tsconfig.app.json",
"compilerOptions": {
"types": ["node"],
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"exclude": ["../src/test.ts", "../src/**/*.spec.ts"],
"include": ["../src/**/*.stories.*", "./preview.ts", "./vitest.setup.ts"],
"files": ["./typings.d.ts"]
}
Create a vitest.config.ts file in your project root:
/// <reference types="vitest/config" />
import { defineConfig } from 'vite';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
import { playwright } from '@vitest/browser-playwright';
const dirname =
typeof __dirname !== 'undefined'
? __dirname
: path.dirname(fileURLToPath(import.meta.url));
export default defineConfig({
test: {
projects: [
{
extends: true,
plugins: [
storybookTest({
configDir: path.join(dirname, '.storybook'),
}),
],
test: {
name: 'storybook',
browser: {
enabled: true,
headless: true,
provider: playwright(),
instances: [{ browser: 'chromium' }],
},
setupFiles: ['.storybook/vitest.setup.ts'],
},
},
],
},
});
Install Playwright browser binaries:
npx playwright install chromium
Add the test-storybook target to your angular.json:
"test-storybook": {
"builder": "@analogjs/vitest-angular:test",
"options": {
"configFile": "vitest.config.ts"
}
}
Add a test script to your package.json:
"scripts": {
"test-storybook": "ng run your-app:test-storybook"
}
Writing Interaction Tests
The Button component from Storybook's initial setup is a great example for interaction testing. Here's how to add a play function to test user interactions:
import type { Meta, StoryObj } from '@storybook/angular';
import { fn, expect, userEvent, within } from '@storybook/test';
import { Button } from './button.component';
const meta: Meta<Button> = {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
args: { onClick: fn() },
};
export default meta;
type Story = StoryObj<Button>;
export const Primary: Story = {
args: {
primary: true,
label: 'Button',
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button', { name: /Button/i });
await userEvent.click(button);
await expect(args.onClick).toHaveBeenCalled();
},
};
export const Secondary: Story = {
args: {
label: 'Button',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button', { name: /Button/i });
await expect(button).toBeInTheDocument();
await expect(button).toHaveClass('storybook-button--secondary');
},
};
The play function allows you to:
- Query elements using
within(canvasElement) - Simulate user interactions with
userEvent - Make assertions with
expect - And more ...
Running Tests
Run your interaction tests with:
npm run test-storybook
This runs all stories with play functions as tests in a real browser using Playwright, giving you confidence that your components work as expected.
You can also run tests directly in the Storybook UI. Start Storybook and use the "Run Tests" button in the sidebar, or navigate to a story to see interaction tests run automatically in the Interactions panel.
Conclusion
Using Storybook with Angular and Vite provides faster builds and a better developer experience. Adding Vitest for interaction testing lets you verify component behavior directly in your stories.
See the example repository with a full Storybook setup
https://github.com/brandonroberts/angular-vite-storybook
If you enjoyed this post, click the ❤️ so other people will see it. Follow AnalogJS and me on Twitter/X, and subscribe to my YouTube Channel for more content!
Top comments (0)