名称: playwright-浏览器自动化 description: 使用Playwright完成浏览器自动化。自动检测开发服务器,将干净的测试脚本写入/tmp目录。测试页面、填写表单、截图、检查响应式设计、验证用户体验、测试登录流程、检查链接、自动化任何浏览器任务。当用户想要测试网站、自动化浏览器交互、验证网页功能或执行任何基于浏览器的测试时使用。 版本: 4.0.0 作者: Claude助手 tags: [测试, 自动化, 浏览器, 端到端测试, playwright, 网页测试]
重要提示 - 路径解析:
此技能可以安装在不同位置(插件系统、手动安装、全局安装或项目特定安装)。在执行任何命令之前,请根据加载此SKILL.md文件的位置确定技能目录,并在以下所有命令中使用该路径。将$SKILL_DIR替换为实际发现的路径。
常见安装路径:
- 插件系统:
~/.claude/plugins/marketplaces/playwright-skill/skills/playwright-skill - 手动全局安装:
~/.claude/skills/playwright-skill - 项目特定:
<项目>/.claude/skills/playwright-skill
Playwright浏览器自动化
通用浏览器自动化技能。我将为您请求的任何自动化任务编写自定义Playwright代码,并通过通用执行器执行。
关键工作流程 - 按顺序执行以下步骤:
-
自动检测开发服务器 - 对于本地主机测试,始终首先运行服务器检测:
cd $SKILL_DIR && node -e "require('./lib/helpers').detectDevServers().then(servers => console.log(JSON.stringify(servers)))"- 如果找到1个服务器: 自动使用,通知用户
- 如果找到多个服务器: 询问用户要测试哪个
- 如果未找到服务器: 询问URL或帮助启动开发服务器
-
将脚本写入/tmp - 切勿将测试文件写入技能目录;始终使用
/tmp/playwright-test-*.js -
默认使用可见浏览器 - 除非用户特别请求无头模式,否则始终使用
headless: false -
参数化URL - 始终通过环境变量或脚本顶部的常量使URL可配置
工作原理
- 您描述想要测试/自动化的内容
- 我自动检测正在运行的开发服务器(或询问URL以测试外部站点)
- 我将自定义Playwright代码写入
/tmp/playwright-test-*.js(不会弄乱您的项目) - 我通过以下方式执行:
cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js - 实时显示结果,浏览器窗口可见以便调试
- 测试文件由您的操作系统自动从/tmp清理
设置(首次使用)
cd $SKILL_DIR
npm run setup
这将安装Playwright和Chromium浏览器。只需执行一次。
执行模式
步骤1: 检测开发服务器(用于本地主机测试)
cd $SKILL_DIR && node -e "require('./lib/helpers').detectDevServers().then(s => console.log(JSON.stringify(s)))"
步骤2: 将测试脚本写入/tmp并参数化URL
// /tmp/playwright-test-page.js
const { chromium } = require('playwright');
// 参数化URL(检测到或用户提供)
const TARGET_URL = 'http://localhost:3001'; // <-- 自动检测或来自用户
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(TARGET_URL);
console.log('页面加载:', await page.title());
await page.screenshot({ path: '/tmp/screenshot.png', fullPage: true });
console.log('📸 截图已保存到 /tmp/screenshot.png');
await browser.close();
})();
步骤3: 从技能目录执行
cd $SKILL_DIR && node run.js /tmp/playwright-test-page.js
常见模式
测试页面(多个视口)
// /tmp/playwright-test-responsive.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自动检测
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 100 });
const page = await browser.newPage();
// 桌面测试
await page.setViewportSize({ width: 1920, height: 1080 });
await page.goto(TARGET_URL);
console.log('桌面 - 标题:', await page.title());
await page.screenshot({ path: '/tmp/desktop.png', fullPage: true });
// 移动端测试
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({ path: '/tmp/mobile.png', fullPage: true });
await browser.close();
})();
测试登录流程
// /tmp/playwright-test-login.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自动检测
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(`${TARGET_URL}/login`);
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
// 等待重定向
await page.waitForURL('**/dashboard');
console.log('✅ 登录成功,重定向到仪表板');
await browser.close();
})();
填写并提交表单
// /tmp/playwright-test-form.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自动检测
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 50 });
const page = await browser.newPage();
await page.goto(`${TARGET_URL}/contact`);
await page.fill('input[name="name"]', 'John Doe');
await page.fill('input[name="email"]', 'john@example.com');
await page.fill('textarea[name="message"]', 'Test message');
await page.click('button[type="submit"]');
// 验证提交
await page.waitForSelector('.success-message');
console.log('✅ 表单提交成功');
await browser.close();
})();
检查损坏链接
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3000');
const links = await page.locator('a[href^="http"]').all();
const results = { working: 0, broken: [] };
for (const link of links) {
const href = await link.getAttribute('href');
try {
const response = await page.request.head(href);
if (response.ok()) {
results.working++;
} else {
results.broken.push({ url: href, status: response.status() });
}
} catch (e) {
results.broken.push({ url: href, error: e.message });
}
}
console.log(`✅ 工作链接: ${results.working}`);
console.log(`❌ 损坏链接:`, results.broken);
await browser.close();
})();
截图与错误处理
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
try {
await page.goto('http://localhost:3000', {
waitUntil: 'networkidle',
timeout: 10000
});
await page.screenshot({
path: '/tmp/screenshot.png',
fullPage: true
});
console.log('📸 截图已保存到 /tmp/screenshot.png');
} catch (error) {
console.error('❌ 错误:', error.message);
} finally {
await browser.close();
}
})();
测试响应式设计
// /tmp/playwright-test-responsive-full.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自动检测
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
const viewports = [
{ name: 'Desktop', width: 1920, height: 1080 },
{ name: 'Tablet', width: 768, height: 1024 },
{ name: 'Mobile', width: 375, height: 667 }
];
for (const viewport of viewports) {
console.log(`测试 ${viewport.name} (${viewport.width}x${viewport.height})`);
await page.setViewportSize({
width: viewport.width,
height: viewport.height
});
await page.goto(TARGET_URL);
await page.waitForTimeout(1000);
await page.screenshot({
path: `/tmp/${viewport.name.toLowerCase()}.png`,
fullPage: true
});
}
console.log('✅ 所有视口已测试');
await browser.close();
})();
内联执行(简单任务)
对于快速的一次性任务,您可以在不创建文件的情况下内联执行代码:
# 快速截图
cd $SKILL_DIR && node run.js "
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3001');
await page.screenshot({ path: '/tmp/quick-screenshot.png', fullPage: true });
console.log('截图已保存');
await browser.close();
"
何时使用内联与文件:
- 内联: 快速一次性任务(截图、检查元素是否存在、获取页面标题)
- 文件: 复杂测试、响应式设计检查、用户可能想要重新运行的任何内容
可用助手函数
lib/helpers.js中的可选实用函数:
const helpers = require('./lib/helpers');
// 检测正在运行的开发服务器(关键 - 首先使用此功能!)
const servers = await helpers.detectDevServers();
console.log('找到的服务器:', servers);
// 带重试的安全点击
await helpers.safeClick(page, 'button.submit', { retries: 3 });
// 带清除的安全输入
await helpers.safeType(page, '#username', 'testuser');
// 带时间戳的截图
await helpers.takeScreenshot(page, 'test-result');
// 处理Cookie横幅
await helpers.handleCookieBanner(page);
// 提取表格数据
const data = await helpers.extractTableData(page, 'table.results');
完整列表请参见lib/helpers.js。
高级用法
有关全面的Playwright API文档,请参见API_REFERENCE.md:
- 选择器和定位器最佳实践
- 网络拦截和API模拟
- 身份验证和会话管理
- 视觉回归测试
- 移动设备模拟
- 性能测试
- 调试技术
- CI/CD集成
提示
- 关键: 首先检测服务器 - 对于本地主机测试,始终在编写测试代码之前运行
detectDevServers() - 使用/tmp存储测试文件 - 写入
/tmp/playwright-test-*.js,切勿写入技能目录或用户项目 - 参数化URL - 在每个脚本顶部将检测到/提供的URL放入
TARGET_URL常量中 - 默认: 可见浏览器 - 除非用户明确要求无头模式,否则始终使用
headless: false - 无头模式 - 仅当用户特别请求"无头"或"后台"执行时才使用
headless: true - 放慢速度: 使用
slowMo: 100使操作可见且更易于跟踪 - 等待策略: 使用
waitForURL、waitForSelector、waitForLoadState而不是固定超时 - 错误处理: 始终使用try-catch进行稳健的自动化
- 控制台输出: 使用
console.log()跟踪进度并显示正在发生的情况
故障排除
Playwright未安装:
cd $SKILL_DIR && npm run setup
模块未找到:
确保通过run.js包装器从技能目录运行
浏览器未打开:
检查headless: false并确保显示可用
元素未找到:
添加等待: await page.waitForSelector('.element', { timeout: 10000 })
使用示例
用户: "测试营销页面是否看起来不错"
Claude: 我将跨多个视口测试营销页面。让我首先检测正在运行的服务器...
[运行: detectDevServers()]
[输出: 在端口3001上找到服务器]
我找到您的开发服务器运行在 http://localhost:3001
[将自定义自动化脚本写入/tmp/playwright-test-marketing.js,URL参数化]
[运行: cd $SKILL_DIR && node run.js /tmp/playwright-test-marketing.js]
[显示结果,包含来自/tmp/的截图]
用户: "检查登录是否正确重定向"
Claude: 我将测试登录流程。首先,让我检查正在运行的服务器...
[运行: detectDevServers()]
[输出: 在端口3000和3001上找到服务器]
我找到2个开发服务器。应该测试哪个?
- http://localhost:3000
- http://localhost:3001
用户: "使用3001"
[将登录自动化写入/tmp/playwright-test-login.js]
[运行: cd $SKILL_DIR && node run.js /tmp/playwright-test-login.js]
[报告: ✅ 登录成功,重定向到/dashboard]
注意事项
- 每个自动化都是根据您的特定请求自定义编写的
- 不限于预构建脚本 - 任何浏览器任务都可能
- 自动检测正在运行的开发服务器以消除硬编码URL
- 测试脚本写入
/tmp以自动清理(无杂乱) - 通过
run.js进行适当的模块解析,代码可靠执行 - 渐进式披露 - 仅在需要高级功能时加载API_REFERENCE.md