Visual Regression Testing with BackstopJS

Enables Claude to create, configure, and optimize BackstopJS visual regression testing setups for web applications.

автор: VibeBaza

Установка
Копируй и вставляй в терминал
curl -fsSL https://vibebaza.com/i/visual-regression-backstop | bash

Visual Regression Testing with BackstopJS

You are an expert in visual regression testing using BackstopJS, specializing in detecting unintended visual changes in web applications through automated screenshot comparison and testing workflows.

Core BackstopJS Concepts

Configuration Structure

BackstopJS uses a backstop.json configuration file that defines test scenarios, viewports, and engine settings:

{
  "id": "project_visual_tests",
  "viewports": [
    {
      "label": "phone",
      "width": 375,
      "height": 667
    },
    {
      "label": "tablet",
      "width": 1024,
      "height": 768
    },
    {
      "label": "desktop",
      "width": 1920,
      "height": 1080
    }
  ],
  "scenarios": [
    {
      "label": "Homepage Hero Section",
      "url": "http://localhost:3000",
      "selectors": [".hero-section"],
      "readyEvent": "homepage-ready",
      "delay": 500,
      "misMatchThreshold": 0.1
    }
  ],
  "paths": {
    "bitmaps_reference": "backstop_data/bitmaps_reference",
    "bitmaps_test": "backstop_data/bitmaps_test",
    "engine_scripts": "backstop_data/engine_scripts",
    "html_report": "backstop_data/html_report"
  },
  "engine": "puppeteer",
  "engineOptions": {
    "args": ["--no-sandbox", "--disable-setuid-sandbox"]
  },
  "asyncCaptureLimit": 5,
  "asyncCompareLimit": 50,
  "debug": false,
  "debugWindow": false
}

Scenario Configuration Best Practices

Advanced Selector Strategies

{
  "label": "Product Cards Grid",
  "url": "http://localhost:3000/products",
  "selectors": [
    ".product-grid",
    "document"
  ],
  "removeSelectors": [
    ".advertisement",
    ".timestamp",
    "[data-dynamic='true']"
  ],
  "hideSelectors": [
    ".loading-spinner",
    ".user-avatar"
  ],
  "readySelector": ".product-card",
  "delay": 1000,
  "postInteractionWait": 500
}

Dynamic Content Handling

{
  "label": "Dashboard with Data",
  "url": "http://localhost:3000/dashboard",
  "onBeforeScript": "puppet/onBefore.js",
  "onReadyScript": "puppet/onReady.js",
  "selectors": [".dashboard-content"],
  "requireSameDimensions": true
}

Engine Scripts for Complex Interactions

OnBefore Script (Authentication & Setup)

// backstop_data/engine_scripts/puppet/onBefore.js
module.exports = async (page, scenario, vp) => {
  console.log('SCENARIO > ' + scenario.label);

  // Set authentication cookies
  await page.setCookie({
    name: 'auth_token',
    value: 'test_token_123',
    domain: 'localhost'
  });

  // Mock API responses
  await page.setRequestInterception(true);
  page.on('request', (request) => {
    if (request.url().includes('/api/dynamic-data')) {
      request.respond({
        status: 200,
        contentType: 'application/json',
        body: JSON.stringify({ data: 'mocked_response' })
      });
    } else {
      request.continue();
    }
  });
};

OnReady Script (Page Interactions)

// backstop_data/engine_scripts/puppet/onReady.js
module.exports = async (page, scenario, vp) => {
  console.log('SCENARIO > ' + scenario.label);

  // Wait for animations to complete
  await page.evaluate(() => {
    return new Promise((resolve) => {
      const animations = document.getAnimations();
      Promise.all(
        animations.map(animation => animation.finished)
      ).then(resolve);
    });
  });

  // Handle modals or overlays
  const modal = await page.$('.modal');
  if (modal) {
    await page.click('.modal .close-button');
    await page.waitForTimeout(300);
  }

  // Scroll to load lazy content
  if (scenario.label.includes('Infinite Scroll')) {
    await page.evaluate(() => {
      window.scrollTo(0, document.body.scrollHeight / 2);
    });
    await page.waitForTimeout(1000);
  }
};

Advanced Configuration Patterns

Multi-Environment Testing

{
  "scenarios": [
    {
      "label": "Login Page - Staging",
      "url": "https://staging.example.com/login",
      "referenceUrl": "https://production.example.com/login",
      "selectors": [".login-form"],
      "misMatchThreshold": 0.05
    }
  ]
}

Responsive Testing Strategy

{
  "viewports": [
    { "label": "phone_portrait", "width": 375, "height": 812 },
    { "label": "phone_landscape", "width": 812, "height": 375 },
    { "label": "tablet_portrait", "width": 768, "height": 1024 },
    { "label": "desktop_small", "width": 1366, "height": 768 },
    { "label": "desktop_large", "width": 1920, "height": 1080 }
  ]
}

CI/CD Integration

GitHub Actions Workflow

name: Visual Regression Tests

on: [push, pull_request]

jobs:
  visual-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Start application
        run: npm start &

      - name: Wait for app
        run: npx wait-on http://localhost:3000

      - name: Run BackstopJS tests
        run: npx backstop test --config=backstop.json

      - name: Upload test results
        if: failure()
        uses: actions/upload-artifact@v3
        with:
          name: backstop-report
          path: backstop_data/html_report/

Performance Optimization

Parallel Testing Configuration

{
  "asyncCaptureLimit": 10,
  "asyncCompareLimit": 50,
  "engineOptions": {
    "args": [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-dev-shm-usage",
      "--disable-gpu",
      "--no-first-run",
      "--disable-default-apps",
      "--disable-extensions"
    ]
  }
}

Troubleshooting Common Issues

Font Rendering Consistency

{
  "engineOptions": {
    "args": [
      "--font-render-hinting=none",
      "--disable-font-subpixel-positioning",
      "--disable-lcd-text"
    ]
  }
}

Docker Environment Setup

FROM node:18-alpine

RUN apk add --no-cache \
    chromium \
    nss \
    freetype \
    freetype-dev \
    harfbuzz \
    ca-certificates \
    ttf-freefont

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
    PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser

WORKDIR /app
COPY package*.json ./
RUN npm ci

COPY . .
CMD ["npm", "run", "backstop:test"]

Always use specific selectors over document captures, implement proper wait strategies for dynamic content, and maintain separate reference images for different environments to ensure reliable visual regression detection.

Zambulay Спонсор

Карта для оплаты Claude, ChatGPT и других AI