截图对比Skill screenshot-comparison

截图对比技能是一个专业的视觉回归测试工具,用于通过自动化截图捕获和像素级差异分析来检测UI界面变化。该技能支持跨不同视口的响应式测试、基线管理、组件级验证,并能生成可视化差异报告,帮助开发团队确保Web应用和组件库在迭代更新过程中的视觉一致性。主要功能包括:像素差异比较、响应式截图、基线管理、组件测试、CI/CD集成。关键词:视觉回归测试、UI测试自动化、截图对比、像素差异分析、响应式测试、基线管理、组件测试、Playwright、Puppeteer、前端测试。

测试 0 次安装 0 次浏览 更新于 2/26/2026

name: screenshot-comparison description: 通过截图捕获和比较进行视觉回归测试。像素差异分析、跨视口的响应式截图捕获以及高亮显示差异的可视化变更报告。 allowed-tools: Bash(*) Read Write Edit Glob Grep WebFetch metadata: author: babysitter-sdk version: “1.0.0” category: visual-testing backlog-id: SK-UX-005

截图对比

您是 截图对比 - 一个专门用于通过截图捕获和像素级比较进行视觉回归测试的技能,确保UI在变更中的一致性。

概述

此技能支持AI驱动的视觉回归测试,包括:

  • 捕获组件和页面截图
  • 可配置阈值的像素差异比较
  • 跨断点的响应式截图捕获
  • 高亮显示差异的可视化变更报告
  • 基线管理和审批工作流
  • 与CI/CD管道集成

前提条件

  • 已安装Node.js 18+
  • 浏览器自动化工具(Playwright, Puppeteer)
  • pixelmatch 或类似的差异库
  • 可选:Percy, Chromatic用于基于云的测试

能力

1. 截图捕获

使用各种配置捕获截图:

// 全页面截图
const screenshot = await page.screenshot({
  fullPage: true,
  path: 'screenshots/home-full.png'
});

// 元素截图
const element = await page.locator('.hero-section');
await element.screenshot({ path: 'screenshots/hero.png' });

// 特定视口截图
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({ path: 'screenshots/home-mobile.png' });

// 隐藏动态元素
await page.evaluate(() => {
  document.querySelectorAll('[data-testid="timestamp"]')
    .forEach(el => el.style.visibility = 'hidden');
});
await page.screenshot({ path: 'screenshots/home-stable.png' });

2. 像素差异比较

比较截图并生成差异图像:

const pixelmatch = require('pixelmatch');
const { PNG } = require('pngjs');
const fs = require('fs');

const baseline = PNG.sync.read(fs.readFileSync('baseline.png'));
const current = PNG.sync.read(fs.readFileSync('current.png'));
const { width, height } = baseline;

const diff = new PNG({ width, height });

const numDiffPixels = pixelmatch(
  baseline.data,
  current.data,
  diff.data,
  width,
  height,
  {
    threshold: 0.1,           // 敏感度(0-1)
    includeAA: false,         // 忽略抗锯齿
    diffColor: [255, 0, 0],   // 差异高亮颜色
    diffColorAlt: [0, 255, 0] // 抗锯齿备用颜色
  }
);

fs.writeFileSync('diff.png', PNG.sync.write(diff));

const diffPercentage = (numDiffPixels / (width * height)) * 100;
console.log(`差异:${diffPercentage.toFixed(2)}%`);

3. 响应式测试

跨多个视口捕获截图:

const viewports = [
  { name: 'mobile', width: 375, height: 667 },
  { name: 'tablet', width: 768, height: 1024 },
  { name: 'desktop', width: 1440, height: 900 },
  { name: 'wide', width: 1920, height: 1080 }
];

const results = [];

for (const viewport of viewports) {
  await page.setViewportSize({
    width: viewport.width,
    height: viewport.height
  });

  await page.screenshot({
    path: `screenshots/${pageName}-${viewport.name}.png`,
    fullPage: true
  });

  results.push({
    viewport: viewport.name,
    path: `screenshots/${pageName}-${viewport.name}.png`
  });
}

4. 可视化变更报告

生成全面的差异报告:

{
  "testRun": {
    "id": "vr-2026-01-24-001",
    "timestamp": "2026-01-24T10:30:00Z",
    "branch": "feature/new-header",
    "commit": "abc123"
  },
  "summary": {
    "total": 25,
    "passed": 22,
    "failed": 2,
    "new": 1,
    "passRate": "88%"
  },
  "comparisons": [
    {
      "name": "homepage-desktop",
      "status": "passed",
      "diffPercentage": 0.01,
      "threshold": 0.1,
      "baseline": "baseline/homepage-desktop.png",
      "current": "current/homepage-desktop.png"
    },
    {
      "name": "header-mobile",
      "status": "failed",
      "diffPercentage": 5.2,
      "threshold": 0.1,
      "baseline": "baseline/header-mobile.png",
      "current": "current/header-mobile.png",
      "diff": "diffs/header-mobile-diff.png",
      "changedRegions": [
        { "x": 10, "y": 5, "width": 200, "height": 50, "description": "Logo区域" }
      ]
    },
    {
      "name": "new-feature-banner",
      "status": "new",
      "current": "current/new-feature-banner.png",
      "requiresApproval": true
    }
  ]
}

5. 基线管理

管理截图基线:

# 更新特定测试的基线
/skill screenshot-comparison update-baseline \
  --test header-mobile \
  --approve

# 更新所有失败的基线
/skill screenshot-comparison update-baseline \
  --all-failed \
  --approve

# 审查待审批项
/skill screenshot-comparison review \
  --status pending

6. 组件级测试

隔离测试单个组件:

// Storybook集成
const stories = await getStorybookStories();

for (const story of stories) {
  // 导航到story
  await page.goto(`${storybookUrl}/iframe.html?id=${story.id}`);

  // 等待组件
  await page.waitForSelector('#storybook-root > *');

  // 捕获组件截图
  const component = await page.locator('#storybook-root > *');
  await component.screenshot({
    path: `screenshots/components/${story.id}.png`
  });
}

MCP服务器集成

此技能可以利用以下MCP服务器:

服务器 描述 安装
Percy via BrowserStack MCP 基于云的视觉测试 BrowserStack
Playwright MCP Server 带截图的浏览器自动化 GitHub

最佳实践

  1. 忽略动态内容 - 在捕获前隐藏时间戳、广告、动画
  2. 使用一致的环境 - 相同的浏览器版本、操作系统、字体
  3. 设置适当的阈值 - 平衡敏感度与误报
  4. 组织基线 - 清晰的命名约定和版本控制
  5. 审批前审查 - 在接收前始终审查差异
  6. 测试关键路径 - 专注于高影响力的用户旅程

流程集成

此技能与以下流程集成:

  • component-library.js - 组件视觉回归
  • responsive-design.js - 响应式视觉测试
  • hifi-prototyping.js - 设计到实现比较

输出格式

执行操作时,提供结构化输出:

{
  "operation": "compare",
  "status": "completed",
  "summary": {
    "total": 10,
    "passed": 9,
    "failed": 1
  },
  "results": [
    {
      "name": "header-desktop",
      "status": "passed",
      "diffPercentage": 0.02
    }
  ],
  "artifacts": [
    "report.html",
    "diffs/header-mobile-diff.png"
  ]
}

错误处理

  • 优雅处理页面加载失败
  • 报告元素未找到错误
  • 管理基线未找到场景
  • 提供清晰的差异可视化

约束

  • 截图可能因浏览器/操作系统而异
  • 动画和过渡会导致误报
  • 大页面可能需要分块捕获
  • 字体渲染差异需要容差