Skip to content

Commit 0d798a6

Browse files
committed
🤖 Add Storybook and Chromatic visual regression testing
- Initialize Storybook 9.1.10 with React + Vite - Add dark theme matching app (UI chrome, docs, canvas) - Configure global styles (colors, fonts, font smoothing) - Create AssistantMessage component stories (8 variants) - Add Chromatic for automated visual regression testing - Configure GitHub Actions workflow with TurboSnap - Add comprehensive documentation Generated with `cmux`
1 parent 439b5f5 commit 0d798a6

File tree

12 files changed

+696
-20
lines changed

12 files changed

+696
-20
lines changed

.github/CHROMATIC_SETUP.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Chromatic Visual Regression Testing
2+
3+
This repository uses Chromatic for automated visual regression testing of Storybook components.
4+
5+
## Setup Complete ✅
6+
7+
The following has been configured:
8+
9+
- ✅ Chromatic CLI installed (`chromatic@13.3.0`)
10+
- ✅ GitHub Actions workflow (`.github/workflows/chromatic.yml`)
11+
- ✅ Configuration file (`chromatic.config.json`)
12+
- ✅ Project token added to GitHub Secrets
13+
- ✅ Documentation updated
14+
15+
## How It Works
16+
17+
### On Pull Requests
18+
1. Chromatic captures snapshots of all Storybook stories
19+
2. Compares snapshots to the baseline from `main`
20+
3. Posts visual diffs as PR comments
21+
4. Build passes (won't block merge even with visual changes)
22+
5. Developers review changes in Chromatic UI
23+
24+
### On Main Branch
25+
- Changes are automatically accepted as the new baseline
26+
- All future PRs compare against this baseline
27+
28+
## TurboSnap Optimization
29+
30+
**TurboSnap** is enabled to speed up builds:
31+
- Only captures snapshots for changed stories
32+
- Typical build time: ~30 seconds
33+
- Requires full git history (`fetch-depth: 0`)
34+
35+
## Commands
36+
37+
```bash
38+
# Run Chromatic locally (requires CHROMATIC_PROJECT_TOKEN env var)
39+
bun run chromatic
40+
41+
# Build Storybook
42+
bun run build-storybook
43+
44+
# Run Storybook dev server
45+
bun run storybook
46+
```
47+
48+
## Configuration Files
49+
50+
- `.github/workflows/chromatic.yml` - CI workflow
51+
- `chromatic.config.json` - Chromatic settings
52+
- `STORYBOOK.md` - Full Storybook documentation
53+
54+
## Accessing Chromatic
55+
56+
Visit https://www.chromatic.com/ and log in with your GitHub account to:
57+
- View detailed visual diffs
58+
- Approve/reject changes
59+
- See build history
60+
- Manage baselines
61+
62+
## Complements E2E Tests
63+
64+
Chromatic works alongside your existing e2e tests:
65+
- **Chromatic**: Tests visual appearance of isolated components
66+
- **E2E tests**: Test behavior and user interactions
67+
- **No overlap**: Different concerns with minimal maintenance burden
68+
69+
## Free for Open Source
70+
71+
This project qualifies for Chromatic's free open source plan with unlimited builds.
72+

.github/workflows/chromatic.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Chromatic
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: ["**"]
8+
9+
jobs:
10+
chromatic:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v4
15+
with:
16+
fetch-depth: 0 # Required for Chromatic TurboSnap
17+
18+
- name: Setup Bun
19+
uses: oven-sh/setup-bun@v2
20+
with:
21+
bun-version: latest
22+
23+
- name: Install dependencies
24+
run: bun install --frozen-lockfile
25+
26+
- name: Publish to Chromatic
27+
uses: chromaui/action@latest
28+
with:
29+
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
30+
buildScriptName: build-storybook
31+
onlyChanged: true # Only test changed stories (TurboSnap)
32+
exitZeroOnChanges: true # Don't fail on visual changes
33+
autoAcceptChanges: main # Auto-accept changes on main branch

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,8 @@ docs/vercel/
7373
# Profiling
7474
**.cpuprofile
7575
profile.txt
76+
77+
*storybook.log
78+
storybook-static
79+
chromatic-*.log
80+
build-storybook.log

.storybook/main.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { StorybookConfig } from '@storybook/react-vite';
2+
3+
const config: StorybookConfig = {
4+
"stories": [
5+
"../src/**/*.mdx",
6+
"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
7+
],
8+
"addons": [
9+
"@chromatic-com/storybook",
10+
"@storybook/addon-docs",
11+
"@storybook/addon-onboarding",
12+
"@storybook/addon-a11y",
13+
"@storybook/addon-vitest"
14+
],
15+
"framework": {
16+
"name": "@storybook/react-vite",
17+
"options": {}
18+
}
19+
};
20+
export default config;

.storybook/manager.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { addons } from '@storybook/manager-api';
2+
import { themes } from '@storybook/theming';
3+
4+
addons.setConfig({
5+
theme: themes.dark,
6+
});

.storybook/preview.tsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import type { Preview } from '@storybook/react-vite'
2+
import { themes } from '@storybook/theming';
3+
import { Global, css } from '@emotion/react';
4+
import { GlobalColors } from '../src/styles/colors';
5+
import { GlobalFonts } from '../src/styles/fonts';
6+
import React from 'react';
7+
8+
// Base styles matching the app
9+
const globalStyles = css`
10+
* {
11+
margin: 0;
12+
padding: 0;
13+
box-sizing: border-box;
14+
}
15+
16+
body {
17+
font-family: var(--font-primary);
18+
font-size: 14px;
19+
line-height: 1.5;
20+
-webkit-font-smoothing: antialiased;
21+
-moz-osx-font-smoothing: grayscale;
22+
color: var(--color-text);
23+
}
24+
25+
code {
26+
font-family: var(--font-monospace);
27+
}
28+
`;
29+
30+
const preview: Preview = {
31+
parameters: {
32+
controls: {
33+
matchers: {
34+
color: /(background|color)$/i,
35+
date: /Date$/i,
36+
},
37+
},
38+
backgrounds: {
39+
default: 'dark',
40+
values: [
41+
{
42+
name: 'dark',
43+
value: 'hsl(0 0% 12%)',
44+
},
45+
{
46+
name: 'light',
47+
value: '#ffffff',
48+
},
49+
],
50+
},
51+
docs: {
52+
theme: themes.dark,
53+
},
54+
},
55+
decorators: [
56+
(Story) => (
57+
<>
58+
<GlobalColors />
59+
<GlobalFonts />
60+
<Global styles={globalStyles} />
61+
<Story />
62+
</>
63+
),
64+
],
65+
};
66+
67+
export default preview;

STORYBOOK.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Storybook
2+
3+
This project uses [Storybook](https://storybook.js.org/) for component development and documentation.
4+
5+
## Running Storybook
6+
7+
To start Storybook in development mode:
8+
9+
```bash
10+
bun run storybook
11+
```
12+
13+
This will start Storybook on http://localhost:6006
14+
15+
## Building Storybook
16+
17+
To build a static version of Storybook:
18+
19+
```bash
20+
bun run build-storybook
21+
```
22+
23+
The output will be in the `storybook-static` directory.
24+
25+
## Creating Stories
26+
27+
Stories are located next to their components with the `.stories.tsx` extension.
28+
29+
Example structure:
30+
```
31+
src/components/Messages/
32+
├── AssistantMessage.tsx
33+
└── AssistantMessage.stories.tsx
34+
```
35+
36+
### Example Story
37+
38+
```typescript
39+
import type { Meta, StoryObj } from "@storybook/react";
40+
import { MyComponent } from "./MyComponent";
41+
42+
const meta = {
43+
title: "Category/MyComponent",
44+
component: MyComponent,
45+
parameters: {
46+
layout: "padded",
47+
},
48+
tags: ["autodocs"],
49+
} satisfies Meta<typeof MyComponent>;
50+
51+
export default meta;
52+
type Story = StoryObj<typeof meta>;
53+
54+
export const Default: Story = {
55+
args: {
56+
// component props
57+
},
58+
};
59+
```
60+
61+
## Current Stories
62+
63+
- **Messages/AssistantMessage**: Various states of assistant messages including streaming, partial, with models, etc.
64+
65+
## Configuration
66+
67+
- `.storybook/main.ts` - Main Storybook configuration
68+
- `.storybook/preview.tsx` - Preview configuration with global styles and dark theme for docs
69+
- `.storybook/manager.ts` - Manager (UI chrome) configuration with dark theme
70+
71+
## Theme
72+
73+
Storybook is configured with a dark theme to match the application:
74+
- Dark UI chrome (sidebar, toolbar, etc.)
75+
- Dark documentation pages
76+
- Dark canvas background (`hsl(0 0% 12%)`) matching the app's `--color-background`
77+
78+
## Visual Regression Testing with Chromatic
79+
80+
This project uses [Chromatic](https://www.chromatic.com/) for automated visual regression testing.
81+
82+
### How it works
83+
84+
- **On PRs**: Chromatic captures snapshots of all stories and compares them to the baseline
85+
- **On main**: Changes are automatically accepted as the new baseline
86+
- **TurboSnap**: Only changed stories are tested, making builds fast (~30s typical)
87+
88+
### Running Chromatic locally
89+
90+
```bash
91+
bun run chromatic
92+
```
93+
94+
You'll need a `CHROMATIC_PROJECT_TOKEN` environment variable set.
95+
96+
### CI Integration
97+
98+
Chromatic runs automatically in CI via `.github/workflows/chromatic.yml`:
99+
- Runs on all PRs and pushes to main
100+
- Visual diffs are shown inline in PR comments
101+
- Won't fail the build on visual changes (for review)
102+
103+
### Configuration
104+
105+
- `chromatic.config.json` - Chromatic settings (TurboSnap, skip patterns, etc.)
106+
- See [Chromatic docs](https://www.chromatic.com/docs/) for more options

0 commit comments

Comments
 (0)