关于 qa-testing
面向网站团队的通用 QA 指南,用于发布前后检查页面、功能和站点。它通过浏览器控制台代码片段执行检查,并按冒烟、标准和完整三档覆盖。
主要功能
- 01三级 QA 检查
- 02浏览器控制台审查代码
- 03检查元数据与页面结构
- 04基础无障碍与响应式检查
- 05跨浏览器及发布检查
- 06Markdown 审查报告模板
适用场景
- 01对部署进行冒烟测试
- 02检查新上线的页面或功能
- 03在重大版本发布前验证站点
- 04调查页面异常反馈
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rampstackco/ claude-skills --skill qa-testing安装后在 Claude Code 中输入/qa-testing确认已加载。
附带文件README.mdreferences/qa-report-template.md
详细介绍
QA 测试
在宣布页面、功能或网站已交付前,验证其是否正常运行。不依赖特定技术栈。通过控制台代码片段快速检查。
此技能比 accessibility-audit(更深入地检查 WCAG)和 performance-optimization(更深入地检查 Core Web Vitals)更快。一般 QA 请使用此技能;深入审计请使用专用技能。
何时使用
- 每次部署后(冒烟测试)
- 发布新页面或功能后(标准审计)
- 重要版本发布前(完整发布检查矩阵)
- 调查“看起来不太对劲”的报告
- 网站或版块上线前验证
何时不使用
- 深入的无障碍合规工作(使用
accessibility-audit) - 深入的性能调查(使用
performance-optimization) - 代码审查或调试(使用
code-review-web) - 初始网站设置或技术 SEO 基线检查(使用
seo-technical)
必需输入
- 待测试页面的 URL 或网站
- 所需的 QA 级别(冒烟、标准或完整)
- 浏览器开发者工具访问权限
- 标准级别之外需要检查的具体问题
框架:3 个级别
QA 检查范围应与风险相匹配。根据实际情况选择相应级别。
| 级别 | 运行时机 | 时间 | 覆盖范围 |
|---|---|---|---|
| 冒烟 | 每次部署后 | 2 分钟 | 仅检查关键信号 |
| 标准 | 新页面或功能 | 10 分钟 | 页面基础项、无障碍和结构 |
| 完整 | 重要版本发布、上线前 | 30 分钟以上 | 全面检查所有维度 |
级别 1:冒烟测试
用 2 分钟检查“这次部署有没有明显弄坏什么?”。每次部署后运行。
控制台代码片段(粘贴到浏览器开发者工具中):
const smoke = {
title: document.title,
titleLen: document.title.length,
canonical: document.querySelector('link[rel="canonical"]')?.href,
h1Count: document.querySelectorAll('h1').length,
missingAlts: [...document.querySelectorAll('img')].filter(i => !i.hasAttribute('alt')).length,
schema: [...document.querySelectorAll('script[type="application/ld+json"]')]
.map(s => { try { return JSON.parse(s.innerText)['@type'] } catch(e) { return 'invalid' } }),
brokenImages: [...document.querySelectorAll('img')].filter(i => !i.complete || i.naturalWidth === 0).length,
};
console.log(JSON.stringify(smoke, null, 2));
通过标准:
- 标题存在,且长度为 30 至 60 个字符
- Canonical 指向生产域名(绝不能指向 staging 或预览 URL)
- 恰好有一个 H1
- 没有缺少
alt属性的图片。装饰性图片使用空alt=""是正确的标记,可通过检查;只有缺少该属性才算未通过。 - 没有损坏的图片
- 每个 schema 区块都能解析(代码片段输出中没有
invalid条目)。页面类型是否正确属于完整级别的检查,需使用 Rich Results Test。
如果其中任何一项未通过,请先修复冒烟测试发现的问题,再继续深入测试。
级别 2:标准页面审计
用 10 分钟检查新页面或功能。涵盖页面基础项,以及无障碍和结构。
控制台代码片段:
const audit = {
title: document.title,
titleLen: document.title.length,
canonical: document.querySelector('link[rel="canonical"]')?.href,
metaDesc: document.querySelector('meta[name="description"]')?.content,
metaDescLen: document.querySelector('meta[name="description"]')?.content?.length,
ogImage: document.querySelector('meta[property="og:image"]')?.content,
ogTitle: document.querySelector('meta[property="og:title"]')?.content,
twitterCard: document.querySelector('meta[name="twitter:card"]')?.content,
h1Count: document.querySelectorAll('h1').length,
h1Text: document.querySelector('h1')?.innerText,
h2Count: document.querySelectorAll('h2').length,
h2s: [...document.querySelectorAll('h2')].map(h => h.innerText.trim().slice(0, 60)),
totalImages: document.querySelectorAll('img').length,
missingAlts: [...document.querySelectorAll('img')].filter(i => !i.hasAttribute('alt')).length,
brokenImages: [...document.querySelectorAll('img')].filter(i => !i.complete || i.naturalWidth === 0).length,
externalLinksWithoutNoopener: [...document.querySelectorAll('a[target="_blank"]')]
.filter(a => !a.rel?.includes('noopener')).length,
schema: [...document.querySelectorAll('script[type="application/ld+json"]')]
.map(s => {
try {
const d = JSON.parse(s.innerText);
return d['@graph'] ? d['@graph'].map(x => x['@type']) : d['@type'];
} catch(e) { return 'invalid' }
}),
hasSkipLink: [...document.querySelectorAll('a[href^="#"]')].slice(0, 3)
.some(a => /skip/i.test(a.textContent) && !!document.getElementById(a.getAttribute('href').slice(1))),
pageLanguage: document.documentElement.lang || 'NOT SET',
hasFavicon: !!document.querySelector('link[rel*="icon"]'),
};
console.log(JSON.stringify(audit, null, 2));
通过标准(除冒烟测试标准外,还需满足):
- Meta description:120 至 160 个字符
- 存在 og:image、og:title、twitter:card
- 存在描述明确的 H2
- 所有带有
target="_blank"的外部链接都设置了rel="noopener" - 已声明页面语言(
<html>上的lang属性) - 存在 favicon
第 3 级:完整发布检查矩阵
发布前 30 分钟检查。覆盖所有维度。
| 维度 | 通过标准 |
|---|---|
| 冒烟测试和标准检查 | 全部通过 |
| 无障碍(基础) | 运行浏览器审计工具(例如 Lighthouse),得分高于 90 |
| 性能(基础) | 报告模板中「性能」检查清单的每项阈值均达标,包括 INP |
| 移动端响应式 | 报告模板中「响应式」检查清单的每个视口均通过 |
| 跨浏览器 | 已在 Chrome、Safari、Firefox 中测试(如果受众相关,也要测试 Edge) |
| 表单 | 所有表单均可成功提交并正确验证 |
| 内部链接 | 没有失效的内部链接(随机抽查 20 个) |
| 外部链接 | 全部返回 200(抽查 10 个) |
| Sitemap | 返回 200,且仅列出规范 URL |
| robots.txt | 允许生产环境爬虫抓取;如适用,则阻止抓取暂存环境 |
| 安全标头 | 存在 HSTS、X-Frame-Options、X-Content-Type-Options |
| HTTPS | 所有资源均通过 HTTPS 加载,没有混合内容 |
| 404 处理 | 404 页面返回 HTTP 404(而不是软 200) |
| Schema 验证 | 所有 Schema 均通过 Rich Results Test 验证 |
| 分析 | 关键用户操作会按预期触发事件 |
| 缓存行为 | 缓存标头适用于相应页面类型 |
对于标头,运行:
fetch(window.location.origin, { method: 'HEAD' })
.then(r => {
const headers = {};
for (const [k, v] of r.headers.entries()) headers[k] = v;
console.log(JSON.stringify(headers, null, 2));
});
检查:strict-transport-security、x-frame-options、x-content-type-options。
特定 QA 代码片段
图片审计
const imgs = [...document.querySelectorAll('img')].map(i => ({
src: i.src.split('/').pop().split('?')[0].slice(0, 60),
alt: i.hasAttribute('alt') ? (i.alt === '' ? 'DECORATIVE (empty alt)' : i.alt) : 'MISSING',
width: i.naturalWidth,
height: i.naturalHeight,
loaded: i.complete && i.naturalWidth > 0,
}));
console.table(imgs);
console.log({
total: imgs.length,
broken: imgs.filter(i => !i.loaded).length,
noAlt: imgs.filter(i => i.alt === 'MISSING').length,
decorative: imgs.filter(i => i.alt.startsWith('DECORATIVE')).length,
});
标题层级检查
const headings = [...document.querySelectorAll('h1, h2, h3, h4, h5, h6')].map(h => ({
level: parseInt(h.tagName[1]),
text: h.innerText.trim().slice(0, 80),
}));
console.table(headings);
// Check for skipped levels
const levels = headings.map(h => h.level);
let skipped = false;
for (let i = 1; i < levels.length; i++) {
if (levels[i] > levels[i-1] + 1) {
console.warn(`Skipped from H${levels[i-1]} to H${levels[i]}: "${headings[i].text}"`);
skipped = true;
}
}
if (!skipped) console.log('No skipped heading levels');
对比度抽查
function contrast(bg, fg) {
function lum(hex) {
return [hex.slice(1,3), hex.slice(3,5), hex.slice(5,7)]
.map(h => parseInt(h, 16) / 255)
.map(v => v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4))
.reduce((a, v, i) => a + v * [0.2126, 0.7152, 0.0722][i], 0);
}
const [l1, l2] = [lum(bg), lum(fg)];
const r = ((Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05)).toFixed(2);
return r + ':1 ' + (parseFloat(r) >= 4.5 ? 'PASS body' : parseFloat(r) >= 3 ? 'PASS large only' : 'FAIL');
}
// Examples
contrast('#FFFFFF', '#4B5563'); // body color check
contrast('#FFFFFF', '#9CA3AF'); // verify gray choices
表单审计(每个表单)
[...document.querySelectorAll('form')].forEach((form, i) => {
const fields = [...form.querySelectorAll('input, select, textarea')].map(field => ({
type: field.type || field.tagName.toLowerCase(),
name: field.name,
hasLabel: !!form.querySelector(`label[for="${field.id}"]`) || !!field.closest('label'),
required: field.required,
}));
console.log(`Form ${i + 1}:`);
console.table(fields);
});
外部链接审计
const externalLinks = [...document.querySelectorAll('a[href^="http"]')]
.filter(a => !a.href.includes(window.location.host));
const issues = externalLinks.filter(a =>
a.target === '_blank' && (!a.rel?.includes('noopener') || !a.rel?.includes('noreferrer'))
);
if (issues.length) {
console.warn(`${issues.length} external links missing noopener/noreferrer:`);
issues.forEach(a => console.warn(a.href));
} else {
console.log(`All ${externalLinks.length} external links properly attributed`);
}
工作流
- 选择级别。 常规部署做冒烟测试,新工作做标准检查,发布做完整检查。
- 运行代码片段。 粘贴相应的控制台代码片段,并检查输出。
- 记录失败项。 每项失败都必须在发布前修复,或登记为已知问题。
- 对于标准级别,增加以下检查:在 375px、768px 和 1440px 视口进行视觉检查。标准级别有意跳过 1024px;完整级别会根据模板中的其余响应式检查清单检查该视口。测试主要用户流程。
- 对于完整级别,增加以下检查:跨浏览器测试、Lighthouse 审计、Schema 验证、安全标头和 404 处理。
- 记录文档。 完整审计请使用
references/qa-report-template.md中的模板。
常见失败模式
- 在「小型」部署中跳过冒烟测试。 一半的生产环境故障都始于看起来「安全」的部署。
- 运行代码片段却不查看输出。 控制台代码片段只是工具,关键在于解读其返回结果。
- 只做视觉 QA。 只靠目测会漏掉缺失的替代文本、失效的 Schema、缺失的规范链接。务必运行代码片段。
- 只在一种浏览器中测试。 移动版 Safari 和 Chrome 的差异足以让人措手不及。至少测试 Chrome 和 Safari。
- 不做移动端 QA。 大多数用户都在 375px 视口下浏览。务必在该视口测试,否则日后会付出代价。
- 只判定通过或失败,不做补救。 QA 失败必须促成修复或生成已知问题工单。未修复就发布的失败 QA,只是在走流程。
输出格式
冒烟测试:以控制台输出作为报告。
标准和完整审计:生成 Markdown 报告,文件名为 qa-report-[date].md。使用 references/qa-report-template.md 中的模板。
如果所需数据不可用
此技能的输出依赖于它无法自行生成的数据、测量结果或工具结果。当所需输入、工具或数据源不可用或无法验证时,合规的输出方式是交付成果并说明差距:需要什么、实际获取或验证了什么,以及输出的哪些部分受到影响。严禁为完成交付成果而捏造、估算或插值所需数值。明确说明差距,即为完整答复。
参考文件
references/qa-report-template.md- 标准和完整审计的 Markdown 报告模板。