@vizzly-testing/storybook
v0.6.0
Published
Storybook plugin for Vizzly - seamlessly integrate Storybook stories into your visual development workflow
Maintainers
Readme
@vizzly-testing/storybook
Seamlessly integrate your Storybook stories into Vizzly's visual development workflow. Iterate
locally with vizzly tdd, automatically create team builds from CI/CD, and collaborate on visual
changes with position-based comments and review rules.
Installation
npm install @vizzly-testing/storybookThe plugin is automatically discovered by the Vizzly CLI via the @vizzly-testing/* scope.
Quick Start
CLI Usage
# Capture screenshots from a static Storybook build
vizzly storybook ./storybook-static
# With custom viewports
vizzly storybook ./storybook-static \
--viewports "mobile:375x667,tablet:768x1024,desktop:1920x1080"
# With filtering
vizzly storybook ./storybook-static \
--include "components/**" \
--exclude "**/*.deprecated"
# With concurrency control
vizzly storybook ./storybook-static --concurrency 5Programmatic Usage
import { run } from '@vizzly-testing/storybook';
await run('./storybook-static', {
viewports: 'mobile:375x667,desktop:1920x1080',
concurrency: 3,
}, {
logger: console,
});Configuration
Config File
Add a storybook section to your vizzly.config.js file:
// vizzly.config.js
export default {
storybook: {
viewports: [
{ name: 'mobile', width: 375, height: 667 },
{ name: 'tablet', width: 768, height: 1024 },
{ name: 'desktop', width: 1920, height: 1080 },
],
browser: {
headless: true,
args: ['--no-sandbox'],
},
screenshot: {
fullPage: false,
omitBackground: false,
},
concurrency: 3,
include: 'components/**',
exclude: '**/*.test',
interactions: {
// Pattern-based hooks
'Button/*': async (page) => {
await page.hover('button');
},
'Tooltip/*': async (page) => {
await page.click('.tooltip-trigger');
},
},
},
};Run vizzly init to generate a config file with sensible defaults.
Per-Story Configuration
You can configure specific stories by adding tags and vizzly parameters in your story files.
Use tags: ['vizzly-skip'] as the primary way to skip screenshot capture:
// Button.stories.js
export let Primary = {
args: { label: 'Click me' },
parameters: {
vizzly: {
viewports: [
{ name: 'mobile', width: 375, height: 667 },
],
beforeScreenshot: async (page) => {
await page.hover('button');
},
},
},
};
export let Disabled = {
args: { label: 'Disabled', disabled: true },
tags: ['vizzly-skip'], // Don't screenshot this story
};parameters.vizzly.skip is still supported for backwards compatibility.
Configuration Priority
Configuration is merged in this order (later overrides earlier):
- Default configuration (from plugin's
configSchema) - Config file (
storybookkey invizzly.config.js) - CLI options
- Per-story parameters
CLI Options
--viewports <list>- Comma-separated viewport definitions (format:name:WxH)--concurrency <n>- Number of parallel stories to process (default: 3)--include <pattern>- Include story pattern (glob)--exclude <pattern>- Exclude story pattern (glob)--config <path>- Path to custom config file--browser-args <args>- Additional Puppeteer browser arguments--headless- Run browser in headless mode (default: true)--full-page- Capture full page screenshots (default: false)
Interaction Hooks
Interaction hooks allow you to interact with stories before capturing screenshots.
Global Hooks (Pattern-Based)
// vizzly.config.js
export default {
storybook: {
interactions: {
'Button/*': async (page) => {
// Apply to all Button stories
await page.hover('button');
},
'Form/*': async (page) => {
// Apply to all Form stories
await page.fill('input[name="email"]', '[email protected]');
await page.click('button[type="submit"]');
},
'Dropdown/WithOptions': async (page) => {
// Specific story
await page.click('.dropdown-toggle');
},
},
},
};Per-Story Hooks
export let WithTooltip = {
parameters: {
vizzly: {
beforeScreenshot: async (page) => {
await page.hover('.info-icon');
await page.waitForSelector('.tooltip', { visible: true });
},
},
},
};Pattern Matching
Patterns support glob-like syntax:
*- Match any characters except/**- Match any characters including/Button/*- Match all Button storiescomponents/**- Match all stories under components**/*.deprecated- Match all deprecated stories
Screenshot Naming
Screenshots are named using the format:
ComponentName/StoryName@viewportNameExamples:
Button/Primary@mobileCard/WithImage@desktopComponents/Atoms/Input/Default@tablet
Visual Development Workflow
This plugin integrates Storybook into Vizzly's visual development workflow, enabling both local TDD iteration and seamless team collaboration. The plugin automatically detects which mode to use:
TDD Mode (Local Development)
When a TDD server is running, screenshots are compared locally for fast iteration:
# Start TDD server
vizzly tdd start
# Capture Storybook screenshots (automatically uses TDD mode)
vizzly storybook ./storybook-static
# View live results at http://localhost:47392Output:
ℹ 📍 TDD mode: Using local server
ℹ 📚 Found 5 stories in ./storybook-static
ℹ ✓ Components/Button/Primary@default
ℹ ✅ Captured 5 screenshots successfullyRun Mode (CI/CD & Cloud)
When a VIZZLY_TOKEN is set, screenshots are uploaded to the cloud for team review:
# Capture and upload to Vizzly cloud (automatically uses Run mode)
VIZZLY_TOKEN=your-token vizzly storybook ./storybook-staticOutput:
ℹ ☁️ Run mode: Uploading to cloud
ℹ 🔗 https://app.vizzly.dev/your-org/project/builds/...
ℹ 📚 Found 5 stories in ./storybook-static
ℹ ✓ Components/Button/Primary@default
ℹ ✅ Captured 5 screenshots successfully
ℹ 🔗 View results: https://app.vizzly.dev/your-org/project/builds/...Mode Detection
The plugin automatically chooses the mode:
- TDD mode - If a TDD server is running (
.vizzly/server.jsonfound) - Run mode - If
VIZZLY_TOKENenvironment variable is set - Warning - If neither is available, warns and skips screenshots
No need to wrap with vizzly run - the plugin handles everything!
Supported Storybook Versions
- Storybook v6.x
- Storybook v7.x
- Storybook v8.x
Example Workflow
Build your Storybook:
npm run build-storybookCapture screenshots with Vizzly:
vizzly storybook ./storybook-staticReview in the Vizzly dashboard
Troubleshooting
Stories not found
Ensure your Storybook build has an index.json file:
ls storybook-static/index.jsonBrowser launch fails
Try adding browser arguments:
vizzly storybook ./storybook-static --browser-args "--no-sandbox,--disable-dev-shm-usage"Screenshots are blank
If your component needs time to render, wait for specific elements from your component to appear:
interactions: {
'**': async (page) => {
// Wait for your component's content to be visible
await page.waitForSelector('.your-component-class', { visible: true });
},
}License
MIT © Stubborn Mule Software
