-
Notifications
You must be signed in to change notification settings - Fork 0
visual regression testing
Visual regression testing helps catch unintended UI changes by comparing screenshots before and after code changes.
We use Playwright's built-in screenshot comparison for visual regression testing. For advanced needs, we also support Percy and Chromatic integrations.
# Run visual regression tests
pnpm exec playwright test e2e/visual-regression.spec.ts
# Update snapshots (when UI changes are intentional)
pnpm exec playwright test e2e/visual-regression.spec.ts --update-snapshots
# View test report
pnpm exec playwright show-reportSnapshots are stored in:
-
e2e/__screenshots__/- Baseline snapshots -
test-results/- Test results and diffs (gitignored)
import { test, expect } from '@playwright/test'
test('homepage visual test', async ({ page }) => {
await page.goto('/')
await page.waitForLoadState('networkidle')
await expect(page).toHaveScreenshot('homepage.png', {
fullPage: true,
maxDiffPixels: 100,
})
})test('button component', async ({ page }) => {
await page.goto('/components/button')
const button = page.locator('[data-testid="primary-button"]')
await expect(button).toHaveScreenshot('primary-button.png', {
maxDiffPixels: 10,
})
})test('mobile view', async ({ page }) => {
await page.setViewportSize({ width: 375, height: 667 })
await page.goto('/chat')
await expect(page).toHaveScreenshot('chat-mobile.png', {
fullPage: true,
})
})test('dark mode', async ({ page }) => {
await page.goto('/chat')
// Toggle dark mode
await page.locator('[data-testid="theme-toggle"]').click()
await page.waitForTimeout(300) // Wait for theme transition
await expect(page).toHaveScreenshot('chat-dark.png')
})Visual test settings in playwright.config.ts:
export default defineConfig({
// Screenshot comparison settings
expect: {
toHaveScreenshot: {
maxDiffPixels: 100,
threshold: 0.2,
},
},
// Update snapshots in CI
updateSnapshots: process.env.CI ? 'none' : 'missing',
})await expect(page).toHaveScreenshot('name.png', {
// Full page screenshot
fullPage: true,
// Maximum acceptable different pixels
maxDiffPixels: 100,
// Maximum acceptable different pixel ratio (0-1)
threshold: 0.2,
// Clip to specific area
clip: { x: 0, y: 0, width: 800, height: 600 },
// Mask dynamic content
mask: [page.locator('.timestamp')],
// Animations: 'allow', 'disabled'
animations: 'disabled',
})test('chat with masked timestamps', async ({ page }) => {
await page.goto('/chat')
await expect(page).toHaveScreenshot('chat.png', {
mask: [
page.locator('.timestamp'),
page.locator('.online-status'),
page.locator('[data-dynamic]'),
],
})
})test('modal snapshot', async ({ page }) => {
await page.goto('/chat')
await page.locator('button:has-text("Settings")').click()
// Wait for modal animation to complete
await page.waitForTimeout(300)
await expect(page).toHaveScreenshot('settings-modal.png', {
animations: 'disabled',
})
})test('loaded state', async ({ page }) => {
await page.goto('/chat')
// Wait for loading to complete
await page.waitForLoadState('networkidle')
await page.waitForSelector('[data-testid="message-list"]')
await expect(page).toHaveScreenshot('chat-loaded.png')
})const viewports = [
{ name: 'mobile', width: 375, height: 667 },
{ name: 'tablet', width: 768, height: 1024 },
{ name: 'desktop', width: 1920, height: 1080 },
]
viewports.forEach(({ name, width, height }) => {
test(`homepage ${name}`, async ({ page }) => {
await page.setViewportSize({ width, height })
await page.goto('/')
await expect(page).toHaveScreenshot(`homepage-${name}.png`)
})
})Percy provides advanced visual testing with baseline management and visual review tools.
# Install Percy
pnpm add -D @percy/cli @percy/playwright
# Set Percy token
export PERCY_TOKEN=your_token_here# Run tests with Percy
pnpm exec percy exec -- pnpm test:e2eimport percySnapshot from '@percy/playwright'
test('percy snapshot', async ({ page }) => {
await page.goto('/chat')
await percySnapshot(page, 'Chat Page')
})Chromatic provides visual testing integrated with Storybook.
# Install Chromatic
pnpm add -D chromatic
# Publish to Chromatic
pnpm exec chromatic --project-token=your_token_hereVisual regression tests run automatically on pull requests. See .github/workflows/visual-regression.yml.
Update snapshots when:
- β UI changes are intentional
- β Design updates approved
- β Component refactoring with same visual output
# Update all snapshots
pnpm exec playwright test e2e/visual-regression.spec.ts --update-snapshots
# Update specific test
pnpm exec playwright test e2e/visual-regression.spec.ts:10 --update-snapshots
# Review changes before committing
git diff e2e/__screenshots__/- Run tests locally first
- Review snapshot diffs carefully
- Commit updated snapshots
- Include screenshot changes in PR description
- Request visual review from team
Causes:
- Font rendering differences
- Timezone differences
- OS-specific rendering
Solutions:
- Use Playwright's
--update-snapshotsin CI once - Increase
maxDiffPixelsthreshold - Mask problematic elements
Causes:
- Animations not disabled
- Dynamic content (timestamps, online status)
- Loading states
Solutions:
await expect(page).toHaveScreenshot('page.png', {
animations: 'disabled',
mask: [page.locator('.dynamic-content')],
maxDiffPixels: 200, // Allow small differences
})Solutions:
- Use
clipto capture only relevant areas - Test components instead of full pages
- Compress snapshots (Playwright does this automatically)
component-name-{variant}-{viewport}.png
Examples:
- button-primary.png
- chat-page-desktop.png
- modal-create-channel-dark.png
- sidebar-mobile.png
e2e/
__screenshots__/
components/
button-*.png
modal-*.png
pages/
chat-*.png
settings-*.png
mobile/
*.png
tablet/
*.png
Visual regression tests run on:
- β Pull requests (blocks merge if tests fail)
- β Main branch (updates baseline)
View results:
- Playwright HTML report in GitHub Actions artifacts
- Percy dashboard (if enabled)
- Chromatic dashboard (if enabled)
- Playwright Screenshots
- Percy Documentation
- Chromatic Documentation
- Visual Regression Testing Best Practices
- Check existing visual tests in
e2e/visual-regression.spec.ts - Review Playwright screenshot documentation
- Ask in team chat
nself-chat v0.3.0 | GitHub | Issues | Discussions | Demo
Edit this page | MIT License | Β© 2026
(See π Security section below for 2FA, PIN Lock, and security audits.)
(Search lives in π Reference below.)
- π¬ Advanced Messaging
- π E2EE Setup
- π Search Setup
- π Call Management
- πΊ Live Streaming
- π₯οΈ Screen Sharing
- πΉ Video Calling
- ποΈ Voice Calling
- π± Mobile Optimization
- π§ͺ Testing
- π i18n
- π API Overview
- π Complete Reference
- π» API Examples
- π€ Bot API
- π Auth API
- π GraphQL Schema
- π Deployment Overview
- π³ Docker
- βΈοΈ Kubernetes
- β Helm Charts
- β Production Checklist
- π Production Validation
- π’ Multi-Tenant
- ποΈ Architecture
- π Diagrams
- ποΈ Database Schema
- π Project Structure
- π TypeScript Types
- π SPORT Reference
- π 2FA
- π¬ Messaging
- π Call Management
- π Call State Machine
- π E2EE
- πΊ Live Streaming
- π± Mobile Calls
- π PIN Lock
- π Polls
- π₯οΈ Screen Sharing
- π Search
- π Social Media
- ποΈ Voice Calling
- π Security Overview
- π‘οΈ Security Audit
- β‘ Performance
- π Best Practices
- π 2FA
- π PIN Lock
- π E2EE
- π‘οΈ E2EE Audit
v1.0.0 β’ 2026