测试助手
- 作者仓库星标 926
- 作者更新于 实时读取
- 作者仓库 WHartTest
- 领域
- 工程开发
- 兼容 Agent
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- 信任分
- 88 / 100 · 社区维护
- 作者 / 版本 / 许可
- @MGdaasLab · 未声明 license
- Token 消耗评级
- 低消耗
- 接入复杂程度
- 需简单配置
- 是否需要外部 API Key
- 不需要
- 兼容的系统
- macOS · Linux · Windows
- 底层运行要求
- Node.js · Python
- 文件与系统权限
-
- 只读
- Shell 执行
- 读取环境变量
- 允许写入 / 修改
- 网络行为
- 仅限本地
- 安装命令数
- 26 条
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
需要注意: 未限定 allowed-tools,默认拥有全部工具权限。
---
name: playwright-skill
description: 浏览器自动化执行工具。用于执行 Web 页面测试、表单填写、登录验证、截图等浏览器操作。 执行浏览器自动化任务,支持页面测试、表单操作、登录验证等。 打开任何页面后,必须立即调用 helper…
category: 工程开发
runtime: Node.js / Python
---
# playwright-skill 输出预览
## PART A: 任务判断
- 适用问题:代码实现、重构、调试或代码审查。
- 输入要求:目标材料、限制条件、期望输出和验收方式。
- 证据边界:围绕“⚠️ 强制规则:先获取页面结构,再操作元素 / Page: WHartTest / Input Fields (2)”读取原文规则,不把推断写成作者承诺。
## PART B: 执行结果
- **01** 任务判断:确认你的需求是否属于代码实现、重构、调试或代码审查,并标出输入、限制和预期结果。
- **02** 执行计划:优先按“⚠️ 强制规则:先获取页面结构,再操作元素 / Page: WHartTest / Input Fields (2)”拆成步骤,说明每一步会读取什么、修改什么、产出什么。
- **03** 交付结果:给出可复制的命令、文件改动、检查清单或内容草稿,并说明如何继续迭代。
- **04** 风险边界:结合 读取文件、执行终端命令、读取环境变量、写入/修改文件、主要在本地完成、通常不需要额外 API Key 给出执行前确认项。
## Running Rules
- 读取文件、执行终端命令、读取环境变量、写入/修改文件;主要在本地完成;通常不需要额外 API Key。
- 先小样例验证,再放大到真实任务。
- 交付时同时给结果、检查口径和下一步迭代建议。 原文没有稳定的斜杠命令要求。安装验证后通常全局生效,直接在对话里点名这个 Skill 并描述任务即可。
告诉 Agent 目标文件或材料、期望结果、不可改范围、是否允许联网或执行命令。本 Skill 的权限画像是:读取文件、执行终端命令、读取环境变量、写入/修改文件。
先用一个小任务确认它会围绕“⚠️ 强制规则:先获取页面结构,再操作元素 / Page: WHartTest / Input Fields (2)”工作;涉及文件或命令时,先看 diff、日志、预览或测试结果。
检查最终产物是否包含明确结果、必要证据和下一步动作;如果输出泛泛而谈,就补充输入、边界和验收标准后重跑。
---
name: playwright-skill
description: 浏览器自动化执行工具。用于执行 Web 页面测试、表单填写、登录验证、截图等浏览器操作。 执行浏览器自动化任务,支持页面测试、表单操作、登录验证等。 打开任何页面后,必须立即调用 helper…
category: 工程开发
source: MGdaasLab/WHartTest
---
# playwright-skill
## 什么时候使用
- 把工程方向的常用动作沉淀成 Agent 可调用的技能 适合处理工程开发场景下的代码实现、调试、重构、测试或代码审查,核心价值是把输入、判断、执行、验证和交付边界固定下来,避免 Agent 泛泛回答。 把任务拆成可执行、可检查、可继续迭代…
- 面向代码实现、重构、调试或代码审查,优先处理能明确输入、步骤和验收标准的工作。
## 需要提供什么
- 目标材料、目录范围、期望结果和不可改动内容。
- 是否允许联网、执行命令、读写文件或调用外部服务。
## 执行规则
- 围绕「⚠️ 强制规则:先获取页面结构,再操作元素 / Page: WHartTest / Input Fields (2)」组织步骤,不把推断写成作者事实。
- 读取文件、执行终端命令、读取环境变量、写入/修改文件;主要在本地完成;通常不需要额外 API Key。
- 先跑小样例,确认结果可检查后再扩大任务范围。
## 输出要求
- 给出最终产物、关键证据、验证方式和下一步动作。
- 信息不足时标记 unknown,不编造命令、平台或依赖。 作者原文负责流程事实;仓库文件负责来源和命令;流狐只补充适用场景、限制和质量判断。
skill "playwright-skill" {
输入层 -> 用户目标 + 目标文件 + 禁止范围 + 验收标准
上下文层 -> ⚠️ 强制规则:先获取页面结构,再操作元素 / Page: WHartTest / Input Fields (2)
规则层 -> SKILL.md 触发条件 / 执行顺序 / 输出格式
运行层 -> Node.js / Python | 读取文件、执行终端命令、读取环境变量、写入/修改文件 | 主要在本地完成
安全层 -> 通常不需要额外 API Key + 小任务验证 + diff / 日志复核
输出层 -> 可复制结果 + 检查清单 + 下一步迭代
} Playwright 浏览器自动化
执行浏览器自动化任务,支持页面测试、表单操作、登录验证等。
⚠️ 强制规则:先获取页面结构,再操作元素
禁止猜测选择器!禁止通过截图识别元素!
打开任何页面后,必须立即调用 helpers.describePageForAI(page) 获取页面元素列表,然后根据返回的选择器进行操作。
// 打开页面后第一件事:获取页面结构
await page.goto('http://example.com');
const desc = await helpers.describePageForAI(page);
console.log(desc); // 输出所有可交互元素及其选择器
输出示例:
## Page: WHartTest
URL: http://192.168.150.114:8913/login
### Input Fields (2)
- text: selector="#username" placeholder="请输入用户名"
- password: selector="#password" placeholder="请输入密码"
### Buttons (1)
- "登录": selector="button[type="submit"]"
然后根据输出的选择器进行操作:
await page.fill('#username', 'admin');
await page.fill('#password', '123456');
await page.click('button[type="submit"]');
使用方法
通过 execute_skill_script 工具调用,传入 inline 代码:
node run.js "your playwright code here"
重要:代码必须写在一行,语句用分号分隔。run.js 会自动包装 async IIFE 和 require 语句。禁止添加 --session、--inline、--eval 等参数,run.js 不支持这些参数。
截图路径约定
必须使用环境变量 process.env.SCREENSHOT_DIR 作为截图保存目录。系统会自动设置该变量指向 playwright-skill 目录下的 media/screenshots/ 子目录。
截图命名建议:case_{case_id}_step{step_number}.png
示例:
const screenshotDir = process.env.SCREENSHOT_DIR || './media/screenshots';
await page.screenshot({ path: `${screenshotDir}/case_11_step1.png` });
基础示例
打开页面并截图
node run.js "const dir = process.env.SCREENSHOT_DIR; const browser = await chromium.launch({ headless: false }); const page = await browser.newPage(); await page.goto('http://example.com'); await page.screenshot({ path: dir + '/example.png' }); console.log('截图已保存:', dir + '/example.png'); await browser.close();"
登录测试(带截图)
node run.js "const dir = process.env.SCREENSHOT_DIR; const browser = await chromium.launch({ headless: false, slowMo: 100 }); const page = await browser.newPage(); await page.goto('http://192.168.150.114:8913/'); await page.screenshot({ path: dir + '/step1_open.png' }); await page.fill('input[type=\"text\"]', 'admin'); await page.fill('input[type=\"password\"]', 'admin123456'); await page.screenshot({ path: dir + '/step2_filled.png' }); await page.click('button[type=\"submit\"]'); await page.waitForTimeout(2000); await page.screenshot({ path: dir + '/step3_result.png' }); console.log('截图已保存到', dir); await browser.close();"
表单填写
node run.js "const browser = await chromium.launch({ headless: false }); const page = await browser.newPage(); await page.goto('http://example.com/form'); await page.fill('input[name=\"username\"]', 'testuser'); await page.fill('input[name=\"email\"]', 'test@example.com'); await page.click('button[type=\"submit\"]'); console.log('表单提交完成'); await browser.close();"
其他 helpers 函数
helpers.getPageStructure(page) - 获取结构化 JSON
返回 JSON 对象,适合程序化处理。
const structure = await helpers.getPageStructure(page);
console.log(JSON.stringify(structure, null, 2));
helpers.getPageText(page) - 获取纯文本内容
返回页面所有可见文本。
const text = await helpers.getPageText(page);
console.log(text);
常用 API
浏览器启动
// 可见模式(推荐调试)
const browser = await chromium.launch({ headless: false, slowMo: 100 });
// 无头模式(后台执行)
const browser = await chromium.launch({ headless: true });
页面导航
await page.goto('http://example.com');
await page.goto('http://example.com', { waitUntil: 'networkidle' });
元素定位与操作
// 输入文本
await page.fill('input[name="username"]', 'admin');
await page.fill('input[type="password"]', '123456');
// 点击
await page.click('button[type="submit"]');
await page.click('text=登录');
await page.click('.login-btn');
// 等待元素
await page.waitForSelector('.success-message');
await page.waitForURL('**/dashboard');
常用选择器
| 选择器类型 | 示例 |
|---|---|
| CSS | input[name="username"], .login-btn, #submit |
| 文本 | text=登录, button:has-text("提交") |
| 类型 | input[type="text"], input[type="password"] |
| 占位符 | input[placeholder*="账号"], input[placeholder*="密码"] |
截图(使用环境变量)
const dir = process.env.SCREENSHOT_DIR;
await page.screenshot({ path: `${dir}/screenshot.png` });
await page.screenshot({ path: `${dir}/full.png`, fullPage: true });
等待
await page.waitForTimeout(2000); // 等待2秒
await page.waitForLoadState('networkidle'); // 等待网络空闲
完整测试流程示例
执行一个完整的登录测试:
node run.js "const dir = process.env.SCREENSHOT_DIR; const browser = await chromium.launch({ headless: false, slowMo: 100 }); const page = await browser.newPage(); console.log('步骤1: 打开登录页'); await page.goto('http://192.168.150.114:8913/'); await page.screenshot({ path: dir + '/step1_open.png' }); console.log('步骤2: 输入账号'); await page.fill('input[type=\"text\"]', 'admin'); console.log('步骤3: 输入密码'); await page.fill('input[type=\"password\"]', 'admin123456'); await page.screenshot({ path: dir + '/step2_input.png' }); console.log('步骤4: 点击登录'); await page.click('button[type=\"submit\"]'); await page.waitForTimeout(2000); await page.screenshot({ path: dir + '/step3_result.png' }); console.log('登录结果 - 当前URL:', page.url()); await browser.close(); console.log('测试完成,截图保存在:', dir);"
注意事项
- 截图路径:必须使用
process.env.SCREENSHOT_DIR环境变量 - 代码格式:inline 代码用分号分隔语句,写在一行内
- 引号转义:字符串内的双引号需要转义
\" - browser.close():非持久化模式下执行完毕后务必关闭浏览器
- console.log():用于输出执行进度和结果
- headless: false:调试时使用可见模式,方便观察
持久化会话模式
对于需要跨多个步骤保持浏览器打开的场景(如自动化测试用例),使用 session_id 参数:
⚠️ 核心规则(必须严格遵守)
- session_id 必须完全一致:整个测试流程中所有步骤必须使用完全相同的 session_id 字符串,否则会创建新浏览器导致状态丢失!
- ✅ 正确:所有步骤都用
session_id="case_11" - ❌ 错误:第一步用
case_11,第二步用case-11,第三步用test-case-11(这会创建3个不同的浏览器!)
- ✅ 正确:所有步骤都用
- 直接使用
page变量:无需chromium.launch(),系统自动管理 - 不要调用
browser.close():浏览器由系统管理,空闲 15 分钟自动关闭
持久化模式示例
步骤 1:打开页面
execute_skill_script(
skill_name="playwright-skill",
command='node run.js "await page.goto(\'http://example.com\'); console.log(page.url());"',
session_id="test-case-001"
)
步骤 2:填写表单(复用同一浏览器)
execute_skill_script(
skill_name="playwright-skill",
command='node run.js "await page.fill(\'input[name=username]\', \'admin\'); await page.fill(\'input[name=password]\', \'123456\');"',
session_id="test-case-001"
)
步骤 3:点击登录(继续复用)
execute_skill_script(
skill_name="playwright-skill",
command='node run.js "await page.click(\'button[type=submit]\'); await page.waitForTimeout(2000); console.log(\'登录后URL:\', page.url());"',
session_id="test-case-001"
)
持久化 vs 非持久化对比
| 特性 | 非持久化(无 session_id) | 持久化(有 session_id) |
|---|---|---|
| 浏览器生命周期 | 代码手动管理 | 系统自动管理 |
| 启动方式 | chromium.launch() |
直接使用 page |
| 关闭方式 | browser.close() |
自动关闭(15分钟空闲) |
| 跨步骤状态 | 不保持 | 保持(登录态、cookie等) |
| 适用场景 | 单步操作 | 多步骤测试用例 |
先判断是否适合
作者设计意图
作者的方法与取舍
边界和复核