7.9 Webapp Testing Skill - Web 应用测试工具包
概述
Webapp Testing Skill 提供了一套使用 Playwright 与本地 Web 应用交互和测试的工具包。它支持验证前端功能、调试 UI 行为、捕获浏览器截图以及查看浏览器日志。
核心功能
- 验证前端功能
- 调试 UI 行为
- 捕获浏览器截图
- 查看浏览器控制台日志
- 自动化测试流程
技术基础
这个 Skill 基于 Playwright——一个现代化的浏览器自动化库,支持:
- Chromium、Firefox、WebKit
- 同步和异步 API
- 自动等待机制
- 截图和视频录制
决策树:选择方法
用户任务 --> 是静态 HTML 吗?
|
+-- 是 --> 直接读取 HTML 文件识别选择器
| |
| +-- 成功 --> 使用选择器编写 Playwright 脚本
| |
| +-- 失败/不完整 --> 按动态应用处理(见下)
|
+-- 否(动态 webapp)--> 服务器已运行吗?
|
+-- 否 --> 运行: python scripts/with_server.py --help
| 然后使用辅助脚本 + 编写简化的 Playwright 脚本
|
+-- 是 --> 侦察-然后-行动模式:
1. 导航并等待 networkidle
2. 截图或检查 DOM
3. 从渲染状态识别选择器
4. 使用发现的选择器执行操作辅助脚本
with_server.py - 服务器生命周期管理
这个脚本自动管理服务器的启动、就绪检测和清理工作。
重要提示:始终先运行 --help 查看用法,不要先阅读源代码。这些脚本作为黑盒工具使用,避免污染上下文窗口。
单服务器模式
bash
python scripts/with_server.py \
--server "npm run dev" \
--port 5173 \
-- python your_automation.py多服务器模式
当需要同时运行后端和前端时:
bash
python scripts/with_server.py \
--server "cd backend && python server.py" --port 3000 \
--server "cd frontend && npm run dev" --port 5173 \
-- python your_automation.py脚本工作原理
+---------------+ +----------------+ +---------------+ +---------------+
| 启动服务器 | --> | 等待端口就绪 | --> | 运行自动化 | --> | 清理服务器 |
+---------------+ +----------------+ +---------------+ +---------------+
| subprocess | | socket 轮询 | | subprocess | | terminate() |
| Popen() | | 超时 30s | | run() | | wait() |
+---------------+ +----------------+ +---------------+ +---------------+核心模式:侦察-然后-行动
对于动态 Web 应用,采用"侦察-然后-行动"模式:
Step 1: 检查渲染后的 DOM
python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto('http://localhost:5173')
page.wait_for_load_state('networkidle') # 关键:等待 JS 执行完毕
# 方法 1:截图查看
page.screenshot(path='/tmp/inspect.png', full_page=True)
# 方法 2:获取页面内容
content = page.content()
# 方法 3:查找特定元素
buttons = page.locator('button').all()
browser.close()Step 2: 从检查结果识别选择器
分析截图或 DOM 内容,确定:
- 按钮的文本或类名
- 输入框的 name 或 id
- 链接的 href 或文本
Step 3: 使用发现的选择器执行操作
python
page.click('text=Submit')
page.fill('#username', 'testuser')
page.select_option('select#country', 'China')常用选择器
Playwright 支持多种选择器语法:
| 选择器类型 | 语法 | 示例 |
|---|---|---|
| 文本选择器 | text= | page.click('text=登录') |
| CSS 选择器 | CSS | page.click('.btn-primary') |
| ID 选择器 | #id | page.fill('#email', 'test@example.com') |
| 角色选择器 | role= | page.click('role=button[name="提交"]') |
| Placeholder | placeholder= | page.fill('placeholder=请输入密码', '123456') |
示例代码
示例 1:元素发现
发现页面上的按钮、链接和输入框:
python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# 导航并等待页面完全加载
page.goto('http://localhost:5173')
page.wait_for_load_state('networkidle')
# 发现所有按钮
buttons = page.locator('button').all()
print(f"找到 {len(buttons)} 个按钮:")
for i, button in enumerate(buttons):
text = button.inner_text() if button.is_visible() else "[隐藏]"
print(f" [{i}] {text}")
# 发现链接
links = page.locator('a[href]').all()
print(f"\n找到 {len(links)} 个链接:")
for link in links[:5]: # 显示前 5 个
text = link.inner_text().strip()
href = link.get_attribute('href')
print(f" - {text} -> {href}")
# 发现输入框
inputs = page.locator('input, textarea, select').all()
print(f"\n找到 {len(inputs)} 个输入框:")
for input_elem in inputs:
name = input_elem.get_attribute('name') or \
input_elem.get_attribute('id') or "[未命名]"
input_type = input_elem.get_attribute('type') or 'text'
print(f" - {name} ({input_type})")
# 截图保存
page.screenshot(path='/tmp/page_discovery.png', full_page=True)
print("\n截图已保存到 /tmp/page_discovery.png")
browser.close()示例 2:控制台日志捕获
捕获浏览器自动化过程中的控制台日志:
python
from playwright.sync_api import sync_playwright
url = 'http://localhost:5173'
console_logs = []
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={'width': 1920, 'height': 1080})
# 设置控制台日志捕获
def handle_console_message(msg):
console_logs.append(f"[{msg.type}] {msg.text}")
print(f"Console: [{msg.type}] {msg.text}")
page.on("console", handle_console_message)
# 导航到页面
page.goto(url)
page.wait_for_load_state('networkidle')
# 与页面交互(触发控制台日志)
page.click('text=Dashboard')
page.wait_for_timeout(1000)
browser.close()
# 保存控制台日志到文件
with open('/tmp/console.log', 'w') as f:
f.write('\n'.join(console_logs))
print(f"\n捕获了 {len(console_logs)} 条控制台消息")示例 3:静态 HTML 自动化
使用 file:// URL 自动化本地 HTML 文件:
python
from playwright.sync_api import sync_playwright
import os
html_file_path = os.path.abspath('path/to/your/file.html')
file_url = f'file://{html_file_path}'
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={'width': 1920, 'height': 1080})
# 导航到本地 HTML 文件
page.goto(file_url)
# 截图
page.screenshot(path='/tmp/static_page.png', full_page=True)
# 与元素交互
page.click('text=Click Me')
page.fill('#name', 'John Doe')
page.fill('#email', 'john@example.com')
# 提交表单
page.click('button[type="submit"]')
page.wait_for_timeout(500)
# 最终截图
page.screenshot(path='/tmp/after_submit.png', full_page=True)
browser.close()
print("静态 HTML 自动化完成!")常见陷阱与最佳实践
常见陷阱
| 错误做法 | 正确做法 |
|---|---|
| 在动态应用上检查 DOM 前不等待 | 先等待 networkidle 再检查 |
| 使用硬编码延迟 | 使用智能等待 wait_for_selector() |
| 不关闭浏览器 | 始终在完成后 browser.close() |
最佳实践
使用打包脚本作为黑盒
- 先运行
--help查看用法 - 直接调用,不读取源码
- 避免污染上下文窗口
- 先运行
使用同步 API
python# 推荐 from playwright.sync_api import sync_playwright with sync_playwright() as p: # ...始终关闭浏览器
pythontry: # 自动化逻辑 finally: browser.close()使用描述性选择器
python# 好 page.click('text=提交订单') page.fill('input[name="email"]', 'test@example.com') # 避免 page.click('div > div > button:nth-child(3)')添加适当的等待
pythonpage.wait_for_load_state('networkidle') page.wait_for_selector('#dynamic-content') page.wait_for_timeout(500) # 仅在必要时使用
完整工作流示例
测试一个带后端的 React 应用:
bash
# Step 1: 准备自动化脚本
cat > test_app.py << 'EOF'
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# 访问前端
page.goto('http://localhost:5173')
page.wait_for_load_state('networkidle')
# 登录测试
page.fill('#username', 'testuser')
page.fill('#password', 'password123')
page.click('text=登录')
# 等待登录完成
page.wait_for_selector('.dashboard')
# 截图验证
page.screenshot(path='/tmp/dashboard.png')
print("登录成功,仪表板截图已保存")
browser.close()
EOF
# Step 2: 使用 with_server.py 运行测试
python scripts/with_server.py \
--server "cd backend && python server.py" --port 3000 \
--server "cd frontend && npm run dev" --port 5173 \
-- python test_app.py总结
Webapp Testing Skill 提供了一套完整的 Web 应用测试工具链:
核心工具:
- Playwright Python API
with_server.py服务器管理脚本
核心模式:
- 侦察-然后-行动(Reconnaissance-then-action)
- 等待 networkidle 后再操作
关键原则:
- 始终先等待页面完全加载
- 使用描述性选择器
- 打包脚本作为黑盒使用
- 始终关闭浏览器
参考示例:
element_discovery.py- 元素发现static_html_automation.py- 静态 HTML 自动化console_logging.py- 控制台日志捕获
这个 Skill 是 Web Artifacts Builder 的完美补充——先用 Web Artifacts Builder 创建应用,再用 Webapp Testing 验证功能。