跳转到内容

Web 应用测试 (webapp-testing)

webapp-testing 是使用 Playwright 进行 Web 应用测试的技能。它的核心是:自动化测试本地 Web 应用,验证前端功能,调试 UI 行为。

作为开发者,你可能遇到过:

  • “想自动化测试 Web 应用但不知道怎么写”
  • “需要测试前端交互但不想手动”
  • “想截图但不知道怎么做”

webapp-testing 就是解决这些的。

手动测试 vs 自动化测试:
手动:
- 耗时
- 易出错
- 重复性工作
自动化:
- 快速
- 可靠
- 可重复
测试的价值:
- 开发时发现 bug
- 减少回归问题
- 提高代码质量
- 加快迭代速度
用户任务
是静态 HTML?
├─ 是 → 直接读取 HTML 找选择器
│ ├─ 成功 → 用选择器写 Playwright 脚本
│ └─ 失败 → 当作动态处理
└─ 否(动态 Web 应用)
服务器已运行?
├─ 否 → 用 with_server.py 启动服务器
│ 然后写简化 Playwright 脚本
└─ 是 → 侦察-行动模式:
1. 导航并等待 networkidle
2. 截图或检查 DOM
3. 从渲染结果识别选择器
4. 用发现的选择器执行操作
Terminal window
python scripts/with_server.py \
--server "npm run dev" \
--port 5173 \
-- python your_automation.py
Terminal window
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
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')
# 关键:等待 JS 执行完成
page.wait_for_load_state('networkidle')
# ... 你的自动化逻辑
browser.close()
# 截图
page.screenshot(path='/tmp/inspect.png', full_page=True)
# 获取页面内容
content = page.content()
# 获取所有按钮
buttons = page.locator('button').all()
从检查结果中选择器:
常见选择器:
- CSS 选择器:#id, .class, tag
- XPath://div[@class='xxx']
- 文本选择器:page.get_by_text('登录')
- 角色选择器:page.get_by_role('button')
# 点击按钮
page.locator('#submit-btn').click()
# 输入文字
page.locator('input[name="email"]').fill('test@example.com')
# 等待元素
page.wait_for_selector('.result')
# 断言
assert page.locator('.success').is_visible()
错误示例:
page.goto('http://localhost:5173')
content = page.content() # 太早了!
正确示例:
page.goto('http://localhost:5173')
page.wait_for_load_state('networkidle') # 等待 JS 执行
content = page.content() # 现在 DOM 完整了
错误:
page.locator('#root > div > div:nth-child(3) > button')
更好:
page.get_by_role('button', name='提交')
page.get_by_text('登录')
page.locator('.submit-btn').first
from playwright.sync_api import sync_playwright
def test_form_submission():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# 导航
page.goto('http://localhost:5173/form')
page.wait_for_load_state('networkidle')
# 填写表单
page.get_by_label('用户名').fill('testuser')
page.get_by_label('邮箱').fill('test@example.com')
page.get_by_label('密码').fill('password123')
# 提交
page.get_by_role('button', name='提交').click()
# 验证成功
page.wait_for_selector('.success-message')
assert '提交成功' in page.locator('.success-message').text_content()
browser.close()
def test_navigation():
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.get_by_role('link', name='关于').click()
# 验证页面跳转
assert '关于' in page.title()
browser.close()
def test_screenshot():
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.screenshot(path='screenshot.png')
# 后续可以对比 screenshot
# ...
browser.close()
# 打印页面 URL
print(page.url)
# 打印页面标题
print(page.title())
# 打印控制台日志
page.on('console', lambda msg: print(f'Console: {msg.text}'))
# 打印网络请求
page.on('request', lambda req: print(f'Request: {req.url}'))
# 有头模式(可以看到浏览器)
browser = p.chromium.launch(headless=False)
# 等待调试
page.pause()
try:
page.goto('http://localhost:5173')
page.wait_for_load_state('networkidle')
except Exception as e:
# 截图保存错误状态
page.screenshot(path='error.png')
print(f'Error: {e}')
raise
# 1. 角色选择器(最可靠)
page.get_by_role('button', name='提交')
page.get_by_role('link', name='关于')
# 2. 文本选择器
page.get_by_text('登录')
# 3. 标签选择器
page.get_by_label('用户名')
page.get_by_placeholder('请输入')
# 不推荐:脆弱的 CSS 选择器
page.locator('#root > div > button')
# 不推荐:nth-child
page.locator('div:nth-child(3)')
  • 服务器已启动?
  • 端口正确?
  • 页面加载完成?
  • 等待 networkidle?
  • 使用可靠的选择器?
  • 有适当的断言?
  • 清理测试数据?
  • 关闭浏览器?
  • 保存截图/日志?

核心命令

wait_for_load_state(‘networkidle’)

角色 > 文本 > 标签 > CSS

调试

page.screenshot() page.pause()

模式

侦察 → 识别 → 执行

  • frontend-design - 前端设计
  • web-artifacts-builder - Web 产物构建

查看源文件: GitHub原始文件