Getting Started with @qs/design-tests
Status: Stable
This guide walks you through setting up visual regression testing for your project using @qs/design-tests.
Installation
Install the package as a dev dependency:
pnpm add -D @qs/design-tests
Configuration
Create a .designTests.js file in your project root:
module.exports = {
projects: {
myapp: {
key: "myapp",
name: "My Application",
url: "http://localhost:6006", // Your Storybook or application URL
// Optional: Test specific pages (for non-Storybook projects)
pages: [
{ name: "Homepage", path: "/en/" },
{ name: "About", path: "/en/about" },
],
// Optional: Filter which stories to test
ignoreList: ["components/internal/*"],
}
},
viewports: [
{ name: "mobile", width: 375, height: 812 },
{ name: "tablet", width: 768, height: 1024 },
{ name: "desktop", width: 1440, height: 900 },
],
stability: {
strategy: "advanced",
waitForNetworkIdle: true,
waitBeforeScreenshot: 1000,
},
};
Check the configuration before the first run. The command validates it against the schema and prints what it resolves to, without launching a browser:
pnpm exec design-tests config --config .designTests.js
First Run
Run the tests for the first time:
pnpm exec design-tests run --config .designTests.js --all
No baseline exists yet, so the run reports every test as NEW and writes its screenshot to the actual directory (design-tests/actual-images by default). The run prints the platform it captured on, and the report shows every new image:
🖥️ Capture platform: linux-x64, Chromium 112.0.5615.29, Playwright 1.32.3, Node v24.0.0
BASELINE.json records no capture platform yet; `design-tests baseline-update` writes it.
...
📸 🌱 NEW! [#1/150] mobile pages/homepage "Homepage" (2314ms)
...
✅ Tests complete: 0 passed, 150 new (4m 12s)
🚪 Exit 0 (report-only mode: 0 once the report is written, 2 on an empty run; pass --fail-on-changes to exit 1 on visual diffs)
Create the Baseline
Review the images in the report (design-tests/report/index.html), then promote them:
pnpm exec design-tests baseline-update --config .designTests.js
This copies every NEW screenshot into the baseline directory and writes BASELINE.json beside them, recording the deployment reference and the capture platform. Commit both:
git add design-tests/baseline-images/
git commit -m "Add design tests baseline"
git push
Subsequent Runs
On subsequent runs, the tests compare against the baseline:
pnpm exec design-tests run --config .designTests.js --all
If everything matches:
✅ Tests complete: 150 passed (4m 08s)
If there are visual changes:
🔍 Tests complete: 138 passed, 12 diffs (4m 10s)
🔗 Non-Passed Test URLs:
🔄 Changed:
[MYAPP] pages/homepage "Homepage" (desktop) [2.34% diff] - http://localhost:6006/iframe.html?id=pages-homepage--homepage&viewMode=story
Review the HTML report at design-tests/report/index.html to see the differences. When they are intended, design-tests baseline-update promotes them; see Baseline Management.
Docker Usage (Recommended for CI)
Baselines are platform-sensitive: font rendering and anti-aliasing differ between macOS, Windows and Linux. Capture baselines on the platform your CI runs on — for Linux CI, in a Linux container:
# Add docker-compose.yml to your project
# Run tests in Docker
docker compose run --rm design-tests
BASELINE.json records the platform the baseline was captured on. A later run on another platform warns at the top of its log, and baseline-update refuses to promote such a run unless --allow-platform-change is passed.
Next Steps
- Adding Projects - Add more projects to your configuration
- Baseline Management - Learn how to update and recreate baselines
- CLI Reference - Full command-line options
Common Issues
Tests fail immediately
Make sure your application URL is accessible from where the tests run:
curl -I http://localhost:6006
Every test reporting FAIL with HTTP 404 or a connection error points at the configured url: check it before the page.
Baseline images differ between local and CI
The run prints ⚠️ Capture platform differs from the baseline when this is the cause. Capture baselines in the container CI uses:
docker compose run --rm design-tests
An override does not apply
design-tests config lists every override that reached the configuration and names variables that start with DESIGN_TESTS_ but set nothing — DESIGN_TESTS_PLAYWRIGHT_WORKERS with one underscore, for example.
Too many screenshots
Use ignoreList to exclude stories you don't want to test:
projects: {
myapp: {
ignoreList: [
"internal/*",
"examples/*",
"deprecated/*"
]
}
}