Skip to content

Commit 823ac71

Browse files
committed
🤖 Add Chromatic for visual regression testing
- Add chromatic package for visual diff reviews on Storybook - Create GitHub Actions workflow for automated PR checks - Add chromatic config file with sensible defaults - Add comprehensive setup guide (CHROMATIC_SETUP.md) - Add 'make chromatic' command for local testing Requires CHROMATIC_PROJECT_TOKEN secret to be set in GitHub. Generated with `cmux`
1 parent e388034 commit 823ac71

File tree

6 files changed

+224
-3
lines changed

6 files changed

+224
-3
lines changed

.github/workflows/chromatic.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Chromatic
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches: ["**"]
9+
10+
jobs:
11+
chromatic:
12+
name: Visual Regression Testing
13+
runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }}
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0 # Required for Chromatic to track changes
19+
20+
- uses: ./.github/actions/setup-cmux
21+
22+
- name: Generate version file
23+
run: ./scripts/generate-version.sh
24+
25+
- name: Run Chromatic
26+
uses: chromaui/action@latest
27+
with:
28+
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
29+
exitZeroOnChanges: true
30+
onlyChanged: true
31+
buildScriptName: storybook:build
32+

CHROMATIC_SETUP.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# 🎨 Chromatic Setup Guide
2+
3+
This guide explains how to set up and use Chromatic for visual regression testing in cmux.
4+
5+
## What is Chromatic?
6+
7+
Chromatic is a visual testing platform that:
8+
- Captures screenshots of your Storybook components
9+
- Detects visual changes between commits
10+
- Provides a UI review workflow for accepting/rejecting changes
11+
- Integrates with GitHub PRs to show visual diffs
12+
13+
## Initial Setup
14+
15+
### 1. Create a Chromatic Account
16+
17+
1. Go to [chromatic.com](https://www.chromatic.com/)
18+
2. Sign in with your GitHub account
19+
3. Click "Add project" and select the `coder/cmux` repository
20+
21+
### 2. Get Your Project Token
22+
23+
After creating the project, you'll receive a project token that looks like:
24+
```
25+
chpt_1234567890abcdef
26+
```
27+
28+
### 3. Configure GitHub Secrets
29+
30+
Add the Chromatic project token to your GitHub repository:
31+
32+
1. Go to repository **Settings****Secrets and variables****Actions**
33+
2. Click **New repository secret**
34+
3. Name: `CHROMATIC_PROJECT_TOKEN`
35+
4. Value: Your Chromatic project token from step 2
36+
5. Click **Add secret**
37+
38+
### 4. Update Configuration File
39+
40+
Edit `chromatic.config.json` and replace the placeholder with your actual project ID:
41+
42+
```json
43+
{
44+
"projectId": "your-actual-project-id-here"
45+
}
46+
```
47+
48+
You can find your project ID in the Chromatic dashboard URL or in the setup instructions.
49+
50+
## Usage
51+
52+
### Running Chromatic Locally
53+
54+
Test your Storybook components with Chromatic before pushing:
55+
56+
```bash
57+
# Set your project token (one-time setup)
58+
export CHROMATIC_PROJECT_TOKEN=chpt_your_token_here
59+
60+
# Run Chromatic
61+
make chromatic
62+
# or
63+
bun run chromatic
64+
```
65+
66+
### Automated PR Checks
67+
68+
Chromatic automatically runs on every pull request via GitHub Actions. The workflow:
69+
70+
1. Builds your Storybook
71+
2. Captures screenshots of all stories
72+
3. Compares them against the baseline (main branch)
73+
4. Posts a status check and comment on your PR with:
74+
- Number of visual changes detected
75+
- Link to review changes in Chromatic UI
76+
- Direct comparison images
77+
78+
### Reviewing Changes
79+
80+
When Chromatic detects visual changes:
81+
82+
1. Click the **"View changes in Chromatic"** link in the PR
83+
2. Review each component change in the Chromatic UI
84+
3. Accept or reject changes:
85+
-**Accept**: Updates the baseline for future comparisons
86+
-**Reject**: Keeps the existing baseline (treat as a regression)
87+
88+
### Workflow Integration
89+
90+
The Chromatic check is **informational** (won't block PRs) thanks to `exitZeroOnChanges: true`. This allows you to:
91+
- Review visual changes at your own pace
92+
- Merge PRs even with pending visual reviews
93+
- Accept/reject changes after merging if needed
94+
95+
To make it a **required check** (block PRs with unreviewed changes):
96+
1. Update `.github/workflows/chromatic.yml`: Remove `exitZeroOnChanges: true`
97+
2. Add Chromatic as a required status check in GitHub branch protection
98+
99+
## Best Practices
100+
101+
### Component Development
102+
103+
1. **Create stories for visual states**: Add Storybook stories for each significant visual state
104+
2. **Keep stories focused**: Each story should demonstrate one specific state or variant
105+
3. **Use controls**: Make stories interactive with Storybook controls for easier testing
106+
107+
### Managing Changes
108+
109+
1. **Accept intentional changes**: When you update styling, accept the Chromatic changes
110+
2. **Investigate unexpected changes**: If Chromatic catches changes you didn't make, investigate before accepting
111+
3. **Batch reviews**: Review multiple small changes together rather than one at a time
112+
113+
### Performance
114+
115+
- Chromatic uses **smart diffing** - only changed stories are captured
116+
- The workflow uses `onlyChanged: true` to speed up builds
117+
- First run takes longer (captures all baselines)
118+
- Subsequent runs are much faster
119+
120+
## Troubleshooting
121+
122+
### "Project token not found" Error
123+
124+
Make sure you've added `CHROMATIC_PROJECT_TOKEN` to GitHub Secrets and it matches your Chromatic project token exactly.
125+
126+
### Workflow Fails to Build Storybook
127+
128+
Check that:
129+
1. `make storybook-build` works locally
130+
2. All dependencies are installed
131+
3. No TypeScript errors in story files
132+
133+
### Visual Differences in Fonts/Colors
134+
135+
This can happen due to OS-level rendering differences. Chromatic uses consistent rendering, but local previews might look different. Trust the Chromatic UI for accurate comparisons.
136+
137+
### Too Many Changes Detected
138+
139+
If you've refactored significantly:
140+
1. Review and accept legitimate changes in batches
141+
2. Consider using Chromatic's "Accept all" feature for major style updates
142+
3. Use Chromatic's branch comparison to see changes against your feature branch
143+
144+
## Configuration Reference
145+
146+
### chromatic.config.json
147+
148+
```json
149+
{
150+
"projectId": "your-project-id",
151+
"buildScriptName": "storybook:build", // npm script to build Storybook
152+
"storybookBuildDir": "storybook-static", // Where Storybook builds to
153+
"exitZeroOnChanges": true, // Don't fail on visual changes
154+
"exitOnceUploaded": true, // Exit after upload completes
155+
"autoAcceptChanges": false // Don't auto-accept changes
156+
}
157+
```
158+
159+
### Workflow Options
160+
161+
In `.github/workflows/chromatic.yml`:
162+
163+
- `onlyChanged: true` - Only test changed stories (faster)
164+
- `exitZeroOnChanges: true` - Don't block PRs on visual changes
165+
- `buildScriptName` - The npm/make script that builds Storybook
166+
167+
## Resources
168+
169+
- [Chromatic Documentation](https://www.chromatic.com/docs/)
170+
- [Storybook Documentation](https://storybook.js.org/docs)
171+
- [Visual Testing Best Practices](https://www.chromatic.com/docs/test)
172+

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ include fmt.mk
3838
.PHONY: test test-unit test-integration test-watch test-coverage test-e2e
3939
.PHONY: dist dist-mac dist-win dist-linux
4040
.PHONY: docs docs-build docs-watch
41-
.PHONY: storybook storybook-build test-storybook
41+
.PHONY: storybook storybook-build test-storybook chromatic
4242
.PHONY: benchmark-terminal
4343
.PHONY: ensure-deps
4444
.PHONY: check-eager-imports check-bundle-size check-startup
@@ -252,6 +252,9 @@ storybook-build: node_modules/.installed src/version.ts ## Build static Storyboo
252252
test-storybook: node_modules/.installed ## Run Storybook interaction tests (requires Storybook to be running or built)
253253
@bun x test-storybook
254254

255+
chromatic: node_modules/.installed ## Run Chromatic for visual regression testing
256+
@bun x chromatic --exit-zero-on-changes
257+
255258
## Benchmarks
256259
benchmark-terminal: ## Run Terminal-Bench with the cmux agent (use TB_DATASET/TB_SAMPLE_SIZE/TB_ARGS to customize)
257260
@TB_DATASET=$${TB_DATASET:-terminal-bench-core==0.1.1}; \

bun.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"@typescript/native-preview": "^7.0.0-dev.20251014.1",
5959
"@vitejs/plugin-react": "^4.0.0",
6060
"babel-plugin-react-compiler": "^1.0.0",
61+
"chromatic": "^13.3.1",
6162
"cmdk": "^1.0.0",
6263
"concurrently": "^8.2.0",
6364
"dotenv": "^17.2.3",
@@ -1074,6 +1075,8 @@
10741075

10751076
"chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
10761077

1078+
"chromatic": ["chromatic@13.3.1", "", { "peerDependencies": { "@chromatic-com/cypress": "^0.*.* || ^1.0.0", "@chromatic-com/playwright": "^0.*.* || ^1.0.0" }, "optionalPeers": ["@chromatic-com/cypress", "@chromatic-com/playwright"], "bin": { "chroma": "dist/bin.js", "chromatic": "dist/bin.js", "chromatic-cli": "dist/bin.js" } }, "sha512-qJ/el70Wo7jFgiXPpuukqxCEc7IKiH/e8MjTzIF9uKw+3XZ6GghOTTLC7lGfeZtosiQBMkRlYet77tC4KKHUng=="],
1079+
10771080
"chromium-pickle-js": ["chromium-pickle-js@0.2.0", "", {}, "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw=="],
10781081

10791082
"ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],

chromatic.config.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"projectId": "REPLACE_WITH_YOUR_PROJECT_ID",
3+
"buildScriptName": "storybook:build",
4+
"storybookBuildDir": "storybook-static",
5+
"exitZeroOnChanges": true,
6+
"exitOnceUploaded": true,
7+
"autoAcceptChanges": false
8+
}
9+

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
"docs:watch": "make docs-watch",
4242
"storybook": "make storybook",
4343
"storybook:build": "make storybook-build",
44-
"test:storybook": "make test-storybook"
44+
"test:storybook": "make test-storybook",
45+
"chromatic": "make chromatic"
4546
},
4647
"dependencies": {
4748
"@ai-sdk/anthropic": "^2.0.29",
@@ -98,17 +99,18 @@
9899
"@typescript/native-preview": "^7.0.0-dev.20251014.1",
99100
"@vitejs/plugin-react": "^4.0.0",
100101
"babel-plugin-react-compiler": "^1.0.0",
102+
"chromatic": "^13.3.1",
101103
"cmdk": "^1.0.0",
102104
"concurrently": "^8.2.0",
103105
"dotenv": "^17.2.3",
104106
"electron": "^38.2.1",
105107
"electron-builder": "^24.6.0",
106108
"electron-devtools-installer": "^4.0.0",
107109
"electron-mock-ipc": "^0.3.12",
110+
"escape-html": "^1.0.3",
108111
"eslint": "^9.36.0",
109112
"eslint-plugin-react": "^7.37.5",
110113
"eslint-plugin-react-hooks": "^5.2.0",
111-
"escape-html": "^1.0.3",
112114
"jest": "^30.1.3",
113115
"mermaid": "^11.12.0",
114116
"playwright": "^1.56.0",

0 commit comments

Comments
 (0)