| name | storybook-testing-workflow |
| description | Daily Storybook development workflow and testing patterns. Make sure to use this skill whenever working on existing Storybook stories, writing play() functions, running interaction tests, or debugging component behavior — even if the user doesn't mention 'workflow' or 'testing' explicitly. For initial setup and configuration, see the storybook-v10-setup skill. |
Storybook Effective Usage & Development Workflow
Overview
Use Storybook v10+ as a development tool for building, testing, and validating React components. This skill emphasizes using Storybook's interaction testing capabilities, proper testing workflows, and avoiding common pitfalls.
For initial setup and configuration, see storybook-v10-setup skill.
Key Focus: Move from "create stories in Storybook" to "develop and validate components IN Storybook"
Mental Model Shift
❌ Old Mindset:
Storybook = screenshot tool for documentation
✅ New Mindset:
Storybook = integrated dev + test environment for components
- Rapid iteration (hot reload on every change)
- Isolated testing (no app complexity)
- Automated behavior validation (play functions)
- Visual regression detection (snapshot tests)
- Accessibility checking (a11y scans)
Development Workflow
┌─────────────────────────────────────────────────────────────┐
│ Typical Component Development Session in Storybook │
├─────────────────────────────────────────────────────────────┤
│ │
│ Start: npm run storybook (dev server, port 6006) │
│ │
│ Loop (repeat 4-8 times): │
│ ├─ Add/modify story or component code │
│ ├─ Sees hot-reload in browser (< 100ms) │
│ ├─ Inspect visual changes in Story tab │
│ ├─ Click "Interactions" tab to see play() steps │
│ ├─ Verify accessibility in "A11y" tab │
│ ├─ Review "Docs" tab for generated documentation │
│ └─ If issue found, go to source and repeat │
│ │
│ Validate: npm run storybook:test (local) │
│ ├─ Detects visual regressions │
│ ├─ Runs all play() functions │
│ └─ Fails on assertion errors │
│ │
│ Commit: Visual snapshots already approved │
│ ├─ git add src/**/__*_snapshots__/ │
│ └─ Snapshots are part of code review │
│ │
└─────────────────────────────────────────────────────────────┘
Core Concept: The Play Function
A play function is a test script that runs automatically when you view a story in Storybook. It simulates user interactions and verifies component behavior.
export const UserClicksButton: Story = {
play: async ({canvasElement, step}) => {
const canvas = within(canvasElement);
await step('User clicks button', async () => {
const button = canvas.getByRole('button');
await userEvent.click(button);
expect(button).toHaveAttribute('aria-pressed', 'true');
});
},
};
Why Play Functions Matter
Play functions solve a critical problem:
Without Play Functions:
export const FilteredView: Story = {
args: {data: filteredData},
};
With Play Functions:
export const UserAppliesFilter: Story = {
args: {data: allData},
play: async ({canvasElement, step}) => {
const canvas = within(canvasElement);
await step('User clicks filter button', async () => {
await userEvent.click(canvas.getByRole('button', {name: /filter/i}));
});
await step('Only filtered entries shown', async () => {
const rows = canvas.getAllByRole('row');
expect(rows.length).toBeLessThan(allData.length);
});
},
};
Browser Developer Tools Integration
Viewing Play Function Steps
- Open Story in Storybook
- Click "Interactions" tab (below story preview)
- Each
await step() call shows as expandable item
- Click step to see what was tested
- Hover to highlight affected elements
Example Output:
▼ UserAppliesFilter
▼ User opens filter dropdown
✓ Clicked combobox[aria-haspopup="listbox"]
▼ User selects "errors only"
✓ Clicked option[id="errors"]
▼ Grid shows only error rows
✓ Assertion passed: rows.length > 0
Inspecting Snapshots
- Open "Assets" tab in Storybook
- View both visual and markup snapshots
- Compare against previous commits to see what changed
Accessibility Testing
- Click "A11y" tab
- Storybook automatically runs accessibility checks (WCAG AA/AAA, ARIA, semantic HTML, keyboard navigation)
- Fix as indicated - story can't be approved with A11y violations
No More Python HTTP Server Anti-Pattern
❌ WRONG: Manual Python Server
python3 -m http.server 6006 &
npm run storybook:test
pkill -f "python3 -m http.server"
Problems: External to Node.js, manual process killing, can't integrate into CI/CD, port conflicts hard to debug
✅ RIGHT: Use CI Script Already in package.json
npm run storybook:test:ci
Benefits: All Node.js tools, automatic cleanup, perfect for CI/CD, easy to troubleshoot, reproducible everywhere
When NOT to Use Storybook
- ❌ Testing server-side logic (use Jest/TAP)
- ❌ Testing database interactions (use integration tests)
- ❌ Testing full application workflows (use E2E tests)
- ❌ Testing third-party library behavior
- ❌ Performance benchmarking (use dedicated load testing)
RIGHT SCOPE: Component-level rendering, interaction, and visual behavior
Advanced Topics
For detailed implementation patterns and examples, see the reference files:
Interaction Testing Patterns
See interaction-patterns.md for complete examples:
- Pattern 1: Form Interaction - Fill forms, submit, verify callbacks
- Pattern 2: Filtering/Search - Apply filters, search, verify highlighting
- Pattern 3: Open/Close Modal - Toggle visibility, verify content
- Pattern 4: Real-Time Updates - Simulate WebSocket messages
- Pattern 5: Keyboard Navigation - Tab, arrows, Enter interactions
Development Workflow Scenarios
See development-scenarios.md for step-by-step workflows:
- Scenario 1: Building a New Component - From basic rendering to interaction tests
- Scenario 2: Fixing a Bug - Use play functions to reproduce and verify fixes
- Scenario 3: Adding New Feature - Cover feature with comprehensive tests
Testing Checklist
See testing-checklist.md for comprehensive checklists:
- Component Testing Checklist Template - Use for any component
- LogViewer Example Checklist - Complete example with all feature categories
Common Development Patterns
See common-patterns.md for reusable patterns:
- Pattern A: Debugging with Console - Use console.log in play() functions
- Pattern B: Testing with Different Props - Factory functions for variations
- Pattern C: Testing Error Scenarios - Graceful error handling
- Pattern D: Testing WebSocket Lifecycle - Connection/reconnection flows
Troubleshooting
Play Function Not Running
Problem: Story loads but Interactions tab empty
Solution:
- Add explicit play() function to story
- Check syntax:
play: async ({ canvasElement, step }) => { ... }
- Ensure step() calls wrap each block
- Open browser console for error messages
Snapshot Tests Failing Incorrectly
Problem: Tests fail but changes look correct
Solution:
- Review diff in
__diff_output__/ directory
- If change is intentional:
npm run visual:update
- If change is bug: Fix component code and retry
- Never commit snapshot without review
WebSocket Mock Not Working
Problem: Component can't connect in Storybook
Solution:
- Mock WebSocket in story decorator
- Use MockProvider wrapper component
- Dispatch mock messages in play() function
- Never try real WebSocket in Storybook
Large Dataset Performance
Problem: 10k entries story is slow
Solution:
- Keep datasets < 1000 for interaction tests
- Use separate "PerformanceTest" story with 10k
- Disable auto-play:
parameters: { play: { autoplay: false } }
- Use Playwright performance API to measure
Key Takeaways
- Play functions are assertions: Every story should have a
play() function that tests user scenarios
- No external servers: Use
npm run storybook:test:ci, never python3 -m http.server
- Storybook = dev environment: Use it actively during development, not just documentation
- Step annotations help debugging: Every
await step() appears in Interactions tab
- Snapshots are version control: Commit visual + markup snapshots as part of feature
- Tests must pass before commit: Run
npm run storybook:test locally before pushing
- Mock all external state: WebSocket, HTTP, time - everything mocked in Storybook
- Accessibility matters: Run A11y tab before approving, fix violations immediately
Resources