Skip to main content
โšก Calmops

Visual Regression Testing: Catch UI Bugs Before Users Do

Introduction

Visual regression testing captures screenshots of your UI and automatically detects unintended changes. It’s essential for catching layout bugs, style regressions, and responsive issues. This guide covers tools and implementation.


What Is Visual Regression Testing?

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚            Visual Regression Testing Flow                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                             โ”‚
โ”‚  Build          Capture          Compare         Result    โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€          โ”€โ”€โ”€โ”€โ”€โ”€โ”€          โ”€โ”€โ”€โ”€โ”€โ”€โ”€         โ”€โ”€โ”€โ”€โ”€โ”€    โ”‚
โ”‚                                                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”                   โ”‚
โ”‚  โ”‚ Page โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚Screenshotโ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚ Diff  โ”‚โ”€โ”€โ”€โ”€โ–ถ Pass/Fail  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                   โ”‚
โ”‚                                      โ”‚                      โ”‚
โ”‚                               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”‚
โ”‚                               โ”‚  Changed?  โ”‚               โ”‚
โ”‚                               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
โ”‚                                                             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Tools Comparison

tools:
  - name: "Percy"
    type: "Cloud service"
    features: "Visual review, CI integration"
    pricing: "Free tier available"
    
  - name: "Chromatic"
    type: "Cloud service"
    features: "Storybook integration, component testing"
    pricing: "Free tier available"
    
  - name: "Playwright Screenshot"
    type: "Built-in"
    features: "Local comparison, full control"
    pricing: "Free (own infrastructure)"
    
  - name: "BackstopJS"
    type: "Open source"
    features: "Self-hosted, local comparison"
    pricing: "Free"

Playwright Visual Testing

Setup

npm install -D @playwright/test
npx playwright install chromium

Screenshot Tests

import { test, expect } from '@playwright/test';

test('homepage visual snapshot', async ({ page }) => {
  await page.goto('https://example.com');
  
  // Take screenshot
  await expect(page).toHaveScreenshot('homepage.png');
});

test('login page visual', async ({ page }) => {
  await page.goto('https://example.com/login');
  
  await expect(page).toHaveScreenshot('login.png', {
    fullPage: true,
  });
});

Visual Comparison Options

test('with comparison options', async ({ page }) => {
  await page.goto('https://example.com');
  
  await expect(page).toHaveScreenshot('page.png', {
    // Pixel match threshold (0-1)
    maxDiffPixelRatio: 0.1,
    
    // Ignore certain elements
    mask: [
      page.locator('[data-testid="dynamic-content"]'),
      page.locator('.advertisement'),
    ],
    
    // Animations disabled
    animations: 'disabled',
  });
});

CI Integration

# GitHub Actions
- name: Visual Tests
  run: npx playwright test --project=visual
  env:
    CI: true

Percy

Setup

npm install --save-dev @percy/cli @percy/ember
# or
npm install --save-dev @percy/ng2

Configuration

# .percy.yml
version: 2
snapshot:
  widths: [375, 768, 1280]
  minHeight: 1024
static:
  base-url: "http://localhost:3000"
  files: "**/*.html"

Percy Test

import { test, expect } from '@playwright/test';

test.percy('homepage', async ({ page }) => {
  await page.goto('https://example.com');
  await percySnapshot(page, 'Homepage');
});

Chromatic (Storybook)

Setup

npx chromatic --project-token=YOUR_TOKEN

GitHub Action

# .github/workflows/chromatic.yml
name: Chromatic

on: push

jobs:
  chromatic:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 18
      
      - name: Install dependencies
        run: npm ci
      
      - name: Publish to Chromatic
        uses: chromaui/action@v1
        with:
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}

Best Practices

best_practices:
  - "Test at multiple viewports (mobile, tablet, desktop)"
  - "Disable animations for consistent results"
  - "Mask dynamic content (dates, ads)"
  - "Use CI to catch regressions automatically"
  - "Review visual changes in PRs before merging"

Key Takeaways

  • Visual testing catches UI bugs - Layout, style regressions
  • Percy/Chromatic - Cloud services, great review workflow
  • Playwright - Built-in, self-controlled
  • Essential for UI libraries - Component testing

External Resources

Comments