跳到正文
cccskills
免费在 GitHub 公开

playwright-visual-regression

Use when setting up visual regression testing with Playwright - toHaveScreenshot baselines, masking dynamic content, handling animations, full-page and element screenshots, cross-browser runs, CI integration, VUDA MCP tooling, or debugging flaky visual diffs

中文简介正在准备中。当前显示原文说明。

集成工具Playwright
查看安装方法

包含的文件(4)

  • SKILL.md9.3 KB
  • references/ci-debugging.md3.4 KB
  • references/screenshot-techniques.md3.6 KB
  • references/vuda-ai.md10.4 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Playwright Visual Regression Testing

Complete guide to visual regression testing using Playwright's built-in toHaveScreenshot() API, VUDA MCP integration, and AI-powered visual analysis with vision models.

Overview

Playwright provides native visual regression testing through the toHaveScreenshot() assertion. It captures screenshots, compares them against baselines using pixelmatch, and fails tests when visual differences exceed configured thresholds.

Key Features:

  • Built-in screenshot comparison (no external dependencies)
  • Pixel-by-pixel comparison with configurable thresholds
  • Dynamic content masking
  • Animation handling
  • Cross-browser testing (Chromium, Firefox, WebKit)
  • Full-page and element-level screenshots
  • Integration with VUDA MCP for AI-powered visual debugging
  • Vision model integration for screenshot analysis

Installation

Python Installation

# Install Playwright for Python
pip install playwright

# Install browser drivers
playwright install chromium firefox webkit

# Or install all browsers
playwright install

TypeScript/JavaScript Installation

# Install Playwright
npm install -D @playwright/test

# Install browsers
npx playwright install chromium firefox webkit

Basic Usage

Python Example

from playwright.sync_api import sync_playwright, expect

def test_homepage_screenshot():
    """Visual regression test for homepage"""
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        
        page.goto("https://your-app.com")
        
        # Take screenshot for comparison
        expect(page).to_have_screenshot("homepage.png")
        
        browser.close()

def test_element_screenshot():
    """Test specific element instead of full page"""
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        
        page.goto("/pricing")
        
        # Screenshot of specific element
        pricing_card = page.locator('[data-testid="pro-plan"]')
        expect(pricing_card).to_have_screenshot("pro-plan-card.png")
        
        browser.close()

def test_with_masking():
    """Mask dynamic content before screenshot"""
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        
        page.goto("/dashboard")
        
        # Mask dynamic elements
        expect(page).to_have_screenshot("dashboard.png", mask=[
            page.locator(".timestamp"),
            page.locator(".user-avatar"),
        ])
        
        browser.close()

Using pytest with Playwright

# conftest.py
import pytest
from playwright.sync_api import sync_playwright, Browser, Page

@pytest.fixture(scope="session")
def browser():
    with sync_playwright() as p:
        yield p.chromium.launch()

@pytest.fixture
def page(browser: Browser):
    page = browser.new_page()
    yield page
    page.close()

# test_visual.py
def test_login_page(page: Page):
    page.goto("/login")
    expect(page).to_have_screenshot("login-page.png")

def test_login_with_errors(page: Page):
    page.goto("/login")
    page.fill("#email", "invalid")
    page.click('[data-testid="submit"]')
    expect(page).to_have_screenshot("login-error.png")

Pytest Markers for Visual Tests

import pytest

@pytest.mark.visual
def test_visual_regression(page):
    """Run only visual tests with: pytest -m visual"""
    page.goto("/")
    expect(page).to_have_screenshot("homepage.png")

@pytest.mark.visual
@pytest.mark.parametrize("viewport", [
    {"width": 1280, "height": 720},  # Desktop
    {"width": 375, "height": 667},   # Mobile
])
def test_responsive_visual(page, viewport):
    """Test different viewports"""
    page.set_viewport_size(viewport)
    page.goto("/")
    name = f"homepage-{viewport['width']}x{viewport['height']}.png"
    expect(page).to_have_screenshot(name)

TypeScript/JavaScript Example

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

test('homepage matches baseline', async ({ page }) => {
  await page.goto('https://your-app.com');
  await expect(page).toHaveScreenshot();
});

First Run Behavior

The first run creates baseline images. Run with --update-snapshots to generate baselines:

npx playwright test --update-snapshots

Baselines are stored in __snapshots__ directories next to test files.

Named Screenshots

test('login form states', async ({ page }) => {
  await page.goto('/login');
  
  // Empty state
  await expect(page).toHaveScreenshot('login-empty.png');
  
  // Validation error
  await page.fill('#email', 'invalid');
  await page.click('[data-testid="submit"]');
  await expect(page).toHaveScreenshot('login-validation-error.png');
});

Configuration

Playwright Config

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  retries: 2,
  
  // Cross-browser projects
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
    // Mobile viewports
    {
      name: 'mobile-chrome',
      use: { ...devices['Pixel 7'] },
    },
  ],
  
  // Visual regression settings
  expect: {
    toHaveScreenshot: {
      timeout: 5000,
      animations: 'disabled',
    },
  },
});

Threshold Options

// Allow minor pixel differences
await expect(page).toHaveScreenshot('page.png', {
  maxDiffPixels: 100,           // Maximum pixels that can differ
  maxDiffPixelRatio: 0.01,      // Maximum 1% pixel difference
  threshold: 0.3,               // Per-pixel color sensitivity (0-1)
});

Deep Dives

For detailed guidance on specific topics, load these reference files on demand:

  • Screenshot Techniques (references/screenshot-techniques.md) - Masking dynamic content, handling animations, full-page screenshots, element-level testing, cross-browser considerations
  • VUDA AI Tools (references/vuda-ai.md) - VUDA MCP integration, vision model look_at usage
  • CI & Debugging (references/ci-debugging.md) - CI/CD integration, debugging visual failures, advanced patterns, troubleshooting flaky tests

Best Practices

1. Test Organization

// Tag visual tests for selective execution
test('homepage visual @visual', async ({ page }) => {
  await page.goto('/');
  await expect(page).toHaveScreenshot('homepage.png');
});

// Run only visual tests
npx playwright test --grep @visual

2. Component Over Full Page

// ✅ Good: Targeted, fast, precise
await expect(page.locator('.product-card')).toHaveScreenshot('product-card.png');

// ⚠️ Full page: Slower, more noise, harder to diagnose failures
await expect(page).toHaveScreenshot('page.png');

3. Consistent Environments

# Always use Docker for consistent rendering
docker run --rm -v $(pwd):/app mcr.microsoft.com/playwright:v1.50.0-noble

4. Threshold Guidelines

TypeRecommended Threshold
Simple componentsmaxDiffPixelRatio: 0.001 (0.1%)
Text-heavy pagesmaxDiffPixelRatio: 0.01 (1%)
Full-page with fontsmaxDiffPixelRatio: 0.02 (2%)

5. Handle Dynamic Content

// Always mask:
test('feed with masking', async ({ page }) => {
  await page.goto('/feed');
  
  await expect(page).toHaveScreenshot('feed.png', {
    mask: [
      page.locator('.timestamp'),
      page.locator('.user-avatar'),
      page.locator('.ad-slot'),
      page.locator('[data-testid="like-count"]'),
    ],
  });
});

Test Pyramid for Visual Testing

        /\
       /  \     E2E Visual Tests (5-10%)
      /----\    - Critical user flows
     /      \   - Full-page regression
    /--------\  Component Tests (20-30%)
   /          \ - Individual components
  /------------\- UI component variants
 /              \ Element Tests (60-70%)
/________________\ - Smallest UI units
                 - Buttons, inputs, cards

Resources


When to Use What:

NeedSolution
Basic VRTtoHaveScreenshot() - built into Playwright
AI-powered analysisVUDA MCP tools
Vision model analysislook_at tool with screenshots
Cross-browser at scaleRun against multiple browsers in CI
Component testingElement-level screenshots

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

aiohttp

免费

Use when building Python async HTTP services or clients with aiohttp - web server routing, middleware, WebSocket, SSE, streaming, client sessions, pytest-aiohttp testing, or troubleshooting SSL and timeout issues

中文简介正在准备中。当前显示原文说明。

CodeAtCode/oss-ai-skills242026年10月9日 更新

ast-grep

免费

Use when doing structural code search and rewriting - ast-grep linting, refactoring, multi-language patterns

中文简介正在准备中。当前显示原文说明。

CodeAtCode/oss-ai-skills242026年10月9日 更新

Use when building GBA games with the BPCore Lua engine - entity, sprite and tilemap functions, SRAM save and load, link cable multiplayer protocol, camera and scrolling, or optimization patterns

中文简介正在准备中。当前显示原文说明。

CodeAtCode/oss-ai-skills242026年10月9日 更新

celery

免费

Use when running background tasks with Celery - worker and broker configuration (Redis, RabbitMQ), task routing by name vs queue, chains/groups/chords, retry patterns (autoretry_for, retry_backoff), acks_late semantics, failure detection, and monitoring with Flower

中文简介正在准备中。当前显示原文说明。

CodeAtCode/oss-ai-skills242026年10月9日 更新

django

免费

Use when building Django applications - security hardening, authentication and permissions, ORM optimization, PostgreSQL features, Django 6.0, migrations, testing, and ecosystem libraries

中文简介正在准备中。当前显示原文说明。

CodeAtCode/oss-ai-skills242026年10月9日 更新

Use when customizing Django Admin - save_formset, get_search_results, formsets, queryset optimization, db_index, custom URLs

中文简介正在准备中。当前显示原文说明。

CodeAtCode/oss-ai-skills242026年10月9日 更新

查看 CodeAtCode 的全部技能

报告此技能的问题