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 |
最佳实践
- 忽略动态内容 - 在捕获前隐藏时间戳、广告、动画
- 使用一致的环境 - 相同的浏览器版本、操作系统、字体
- 设置适当的阈值 - 平衡敏感度与误报
- 组织基线 - 清晰的命名约定和版本控制
- 审批前审查 - 在接收前始终审查差异
- 测试关键路径 - 专注于高影响力的用户旅程
流程集成
此技能与以下流程集成:
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"
]
}
错误处理
- 优雅处理页面加载失败
- 报告元素未找到错误
- 管理基线未找到场景
- 提供清晰的差异可视化
约束
- 截图可能因浏览器/操作系统而异
- 动画和过渡会导致误报
- 大页面可能需要分块捕获
- 字体渲染差异需要容差