webapp-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWeb Application Testing Skill
Web应用测试技能包
Version: 1.1.0 Category: Development Last Updated: 2026-01-02
版本: 1.1.0 分类: 开发 最后更新时间: 2026-01-02
Overview
概述
This toolkit enables testing local web applications using Playwright with Python for frontend verification, UI debugging, screenshot capture, and browser automation.
本工具包支持使用Python结合Playwright对本地Web应用进行测试,包括前端验证、UI调试、截图捕获以及浏览器自动化操作。
Quick Start
快速开始
bash
undefinedbash
undefinedInstall dependencies
Install dependencies
pip install playwright pytest requests
playwright install chromium
```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:3000")
# Take screenshot
page.screenshot(path="screenshot.png")
# Get page content
content = page.content()
print(content)
browser.close()pip install playwright pytest requests
playwright install chromium
```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:3000")
# Take screenshot
page.screenshot(path="screenshot.png")
# Get page content
content = page.content()
print(content)
browser.close()When to Use
适用场景
- Verifying frontend functionality after code changes
- Debugging UI behavior and layout issues
- Capturing screenshots for documentation
- Viewing browser console logs for errors
- Automating repetitive web interactions
- End-to-end testing of web applications
- Validating form submissions and user flows
- 代码变更后验证前端功能
- 调试UI行为与布局问题
- 为文档捕获截图
- 查看浏览器控制台日志排查错误
- 自动化重复的Web交互操作
- Web应用的端到端测试
- 验证表单提交与用户流程
Decision Tree
决策树
Static HTML
静态HTML
- Read files directly to find selectors
- Then automate with Playwright
- 直接读取文件查找选择器
- 使用Playwright进行自动化操作
Dynamic Webapps
动态Web应用
- Check if server runs
- If not, start with helper script
- Perform reconnaissance (screenshots/DOM)
- Then automate
- 检查服务器是否运行
- 若未运行,通过辅助脚本启动
- 执行侦察操作(截图/DOM分析)
- 进行自动化操作
Running Servers
运行中的服务器
- Perform reconnaissance first
- Take screenshots
- Inspect DOM
- Then automate
- 先执行侦察操作
- 捕获截图
- 检查DOM
- 进行自动化操作
Core Patterns
核心模式
Wait for Dynamic Content
等待动态内容
python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("http://localhost:3000")
# CRITICAL: Wait for JS to execute
page.wait_for_load_state("networkidle")
# Now safe to interact
content = page.content()
browser.close()python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("http://localhost:3000")
# CRITICAL: Wait for JS to execute
page.wait_for_load_state("networkidle")
# Now safe to interact
content = page.content()
browser.close()Element Selection
元素选择
By Text:
python
page.get_by_text("Submit").click()
page.get_by_text("Welcome", exact=False).wait_for()By Role:
python
page.get_by_role("button", name="Submit").click()
page.get_by_role("textbox", name="Email").fill("test@example.com")
page.get_by_role("link", name="Home").click()By CSS Selector:
python
page.locator(".btn-primary").click()
page.locator("#email-input").fill("test@example.com")
page.locator("[data-testid='submit']").click()By ID:
python
page.locator("#submit-button").click()按文本选择:
python
page.get_by_text("Submit").click()
page.get_by_text("Welcome", exact=False).wait_for()按角色选择:
python
page.get_by_role("button", name="Submit").click()
page.get_by_role("textbox", name="Email").fill("test@example.com")
page.get_by_role("link", name="Home").click()按CSS选择器选择:
python
page.locator(".btn-primary").click()
page.locator("#email-input").fill("test@example.com")
page.locator("[data-testid='submit']").click()按ID选择:
python
page.locator("#submit-button").click()Form Interaction
表单交互
python
undefinedpython
undefinedFill form
Fill form
page.locator("#username").fill("testuser")
page.locator("#password").fill("password123")
page.locator("#remember").check()
page.get_by_role("button", name="Login").click()
page.locator("#username").fill("testuser")
page.locator("#password").fill("password123")
page.locator("#remember").check()
page.get_by_role("button", name="Login").click()
Wait for navigation
Wait for navigation
page.wait_for_url("**/dashboard")
undefinedpage.wait_for_url("**/dashboard")
undefinedScreenshots
截图
python
undefinedpython
undefinedFull page
Full page
page.screenshot(path="full.png", full_page=True)
page.screenshot(path="full.png", full_page=True)
Element only
Element only
page.locator(".main-content").screenshot(path="element.png")
page.locator(".main-content").screenshot(path="element.png")
Viewport only
Viewport only
page.screenshot(path="viewport.png")
undefinedpage.screenshot(path="viewport.png")
undefinedConsole Logs
控制台日志
python
undefinedpython
undefinedCapture console output
Capture console output
console_messages = []
def handle_console(msg):
console_messages.append({
"type": msg.type,
"text": msg.text
})
page.on("console", handle_console)
page.goto("http://localhost:3000")
console_messages = []
def handle_console(msg):
console_messages.append({
"type": msg.type,
"text": msg.text
})
page.on("console", handle_console)
page.goto("http://localhost:3000")
Print captured logs
Print captured logs
for msg in console_messages:
print(f"[{msg['type']}] {msg['text']}")
undefinedfor msg in console_messages:
print(f"[{msg['type']}] {msg['text']}")
undefinedNetwork Monitoring
网络监控
python
undefinedpython
undefinedCapture requests
Capture requests
requests = []
def handle_request(request):
requests.append({
"url": request.url,
"method": request.method
})
page.on("request", handle_request)
page.goto("http://localhost:3000")
requests = []
def handle_request(request):
requests.append({
"url": request.url,
"method": request.method
})
page.on("request", handle_request)
page.goto("http://localhost:3000")
Print captured requests
Print captured requests
for req in requests:
print(f"{req['method']} {req['url']}")
undefinedfor req in requests:
print(f"{req['method']} {req['url']}")
undefinedServer Management
服务器管理
Start Server Before Testing
测试前启动服务器
python
import subprocess
import time
from playwright.sync_api import sync_playwrightpython
import subprocess
import time
from playwright.sync_api import sync_playwrightStart server
Start server
server = subprocess.Popen(
["npm", "run", "dev"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
server = subprocess.Popen(
["npm", "run", "dev"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
Wait for server to start
Wait for server to start
time.sleep(3)
try:
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("http://localhost:3000")
# ... test code ...
browser.close()
finally:
server.terminate()
undefinedtime.sleep(3)
try:
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("http://localhost:3000")
# ... test code ...
browser.close()
finally:
server.terminate()
undefinedCheck Server Status
检查服务器状态
python
import requests
def is_server_running(url="http://localhost:3000"):
try:
response = requests.get(url, timeout=2)
return response.status_code == 200
except:
return Falsepython
import requests
def is_server_running(url="http://localhost:3000"):
try:
response = requests.get(url, timeout=2)
return response.status_code == 200
except:
return FalseTesting Patterns
测试模式
Assertion Examples
断言示例
python
from playwright.sync_api import expectpython
from playwright.sync_api import expectText content
Text content
expect(page.locator("h1")).to_have_text("Welcome")
expect(page.locator("h1")).to_have_text("Welcome")
Visibility
Visibility
expect(page.locator(".modal")).to_be_visible()
expect(page.locator(".loading")).to_be_hidden()
expect(page.locator(".modal")).to_be_visible()
expect(page.locator(".loading")).to_be_hidden()
Input values
Input values
expect(page.locator("#email")).to_have_value("test@example.com")
expect(page.locator("#email")).to_have_value("test@example.com")
Count
Count
expect(page.locator(".item")).to_have_count(5)
expect(page.locator(".item")).to_have_count(5)
URL
URL
expect(page).to_have_url("http://localhost:3000/dashboard")
undefinedexpect(page).to_have_url("http://localhost:3000/dashboard")
undefinedTest Structure
测试结构
python
import pytest
from playwright.sync_api import sync_playwright
@pytest.fixture(scope="session")
def browser():
with sync_playwright() as p:
browser = p.chromium.launch()
yield browser
browser.close()
@pytest.fixture
def page(browser):
page = browser.new_page()
yield page
page.close()
def test_homepage(page):
page.goto("http://localhost:3000")
assert page.title() == "My App"
def test_login(page):
page.goto("http://localhost:3000/login")
page.fill("#username", "testuser")
page.fill("#password", "password")
page.click("button[type='submit']")
page.wait_for_url("**/dashboard")python
import pytest
from playwright.sync_api import sync_playwright
@pytest.fixture(scope="session")
def browser():
with sync_playwright() as p:
browser = p.chromium.launch()
yield browser
browser.close()
@pytest.fixture
def page(browser):
page = browser.new_page()
yield page
page.close()
def test_homepage(page):
page.goto("http://localhost:3000")
assert page.title() == "My App"
def test_login(page):
page.goto("http://localhost:3000/login")
page.fill("#username", "testuser")
page.fill("#password", "password")
page.click("button[type='submit']")
page.wait_for_url("**/dashboard")Usage Examples
使用示例
Example 1: Screenshot Comparison Testing
示例1:截图对比测试
python
from playwright.sync_api import sync_playwright
from pathlib import Path
def capture_page_state(url: str, output_dir: str):
"""Capture full page screenshot and HTML content."""
output = Path(output_dir)
output.mkdir(parents=True, exist_ok=True)
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto(url)
page.wait_for_load_state("networkidle")
# Screenshot
page.screenshot(path=str(output / "screenshot.png"), full_page=True)
# HTML content
(output / "content.html").write_text(page.content())
browser.close()
return outputpython
from playwright.sync_api import sync_playwright
from pathlib import Path
def capture_page_state(url: str, output_dir: str):
"""Capture full page screenshot and HTML content."""
output = Path(output_dir)
output.mkdir(parents=True, exist_ok=True)
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto(url)
page.wait_for_load_state("networkidle")
# Screenshot
page.screenshot(path=str(output / "screenshot.png"), full_page=True)
# HTML content
(output / "content.html").write_text(page.content())
browser.close()
return outputUsage
Usage
capture_page_state("http://localhost:3000", "tests/snapshots/")
undefinedcapture_page_state("http://localhost:3000", "tests/snapshots/")
undefinedExample 2: Form Automation
示例2:表单自动化
python
def submit_contact_form(page, name, email, message):
"""Submit a contact form and verify success."""
page.goto("http://localhost:3000/contact")
# Fill form fields
page.fill("[name='name']", name)
page.fill("[name='email']", email)
page.fill("[name='message']", message)
# Submit
page.click("button[type='submit']")
# Wait for success message
page.wait_for_selector(".success-message")
return page.locator(".success-message").text_content()python
def submit_contact_form(page, name, email, message):
"""Submit a contact form and verify success."""
page.goto("http://localhost:3000/contact")
# Fill form fields
page.fill("[name='name']", name)
page.fill("[name='email']", email)
page.fill("[name='message']", message)
# Submit
page.click("button[type='submit']")
# Wait for success message
page.wait_for_selector(".success-message")
return page.locator(".success-message").text_content()Example 3: API Response Verification
示例3:API响应验证
python
def verify_api_call(page, endpoint_pattern):
"""Intercept and verify API calls."""
api_response = None
def handle_response(response):
nonlocal api_response
if endpoint_pattern in response.url:
api_response = response.json()
page.on("response", handle_response)
page.goto("http://localhost:3000/dashboard")
page.wait_for_load_state("networkidle")
return api_responsepython
def verify_api_call(page, endpoint_pattern):
"""Intercept and verify API calls."""
api_response = None
def handle_response(response):
nonlocal api_response
if endpoint_pattern in response.url:
api_response = response.json()
page.on("response", handle_response)
page.goto("http://localhost:3000/dashboard")
page.wait_for_load_state("networkidle")
return api_responseDebugging
调试
Slow Motion
慢动作执行
python
browser = p.chromium.launch(slow_mo=500) # 500ms delay between actionspython
browser = p.chromium.launch(slow_mo=500) # 500ms delay between actionsHeaded Mode
有头模式
python
browser = p.chromium.launch(headless=False) # See the browserpython
browser = p.chromium.launch(headless=False) # See the browserPause Execution
暂停执行
python
page.pause() # Opens Playwright Inspectorpython
page.pause() # Opens Playwright InspectorTrace Recording
追踪记录
python
context = browser.new_context()
context.tracing.start(screenshots=True, snapshots=True)
page = context.new_page()python
context = browser.new_context()
context.tracing.start(screenshots=True, snapshots=True)
page = context.new_page()... test code ...
... test code ...
context.tracing.stop(path="trace.zip")
context.tracing.stop(path="trace.zip")
View with: playwright show-trace trace.zip
View with: playwright show-trace trace.zip
undefinedundefinedBest Practices
最佳实践
Do
建议做法
- Wait appropriately using for dynamic content
networkidle - Select elements by text, role, or data-testid over CSS
- Handle async operations with proper waits
- Clean up browsers and pages after tests
- Use fixtures for browser instance reuse
- Capture console logs for debugging
- 针对动态内容,使用进行合理等待
networkidle - 优先通过文本、角色或data-testid选择元素,而非CSS选择器
- 为异步操作设置正确的等待逻辑
- 测试完成后清理浏览器与页面资源
- 使用fixtures复用浏览器实例
- 捕获控制台日志用于调试
Don't
避免做法
- Use arbitrary for waits
time.sleep() - Rely on fragile CSS selectors
- Skip error handling in test cleanup
- Run tests without checking server status
- Ignore network errors during testing
- 使用任意进行等待
time.sleep() - 依赖脆弱的CSS选择器
- 在测试清理环节跳过错误处理
- 未检查服务器状态就运行测试
- 忽略测试过程中的网络错误
Error Handling
错误处理
Common Errors
常见错误
| Error | Cause | Solution |
|---|---|---|
| Element not found in time | Use explicit waits or increase timeout |
| Browser closed prematurely | Check cleanup order in fixtures |
| Server not running | Start server before tests |
| Hidden by CSS/JS | Wait for visibility state |
| Navigation during action | Wait for navigation to complete |
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 元素未在指定时间内找到 | 使用显式等待或增加超时时间 |
| 浏览器提前关闭 | 检查fixtures中的清理顺序 |
| 服务器未运行 | 测试前启动服务器 |
| 元素被CSS/JS隐藏 | 等待元素进入可见状态 |
| 操作过程中发生页面跳转 | 等待页面跳转完成后再执行操作 |
Debugging Tips
调试技巧
python
undefinedpython
undefinedIncrease default timeout
Increase default timeout
page.set_default_timeout(60000) # 60 seconds
page.set_default_timeout(60000) # 60 seconds
Take screenshot on failure
Take screenshot on failure
try:
page.click("#submit")
except Exception as e:
page.screenshot(path="error_screenshot.png")
raise
try:
page.click("#submit")
except Exception as e:
page.screenshot(path="error_screenshot.png")
raise
Print page HTML for debugging
Print page HTML for debugging
print(page.content())
undefinedprint(page.content())
undefinedExecution Checklist
执行检查清单
- Playwright and chromium installed
- Server running before tests
- Proper wait states for dynamic content
- Screenshots captured for visual verification
- Console logs monitored for errors
- Network requests validated
- Fixtures clean up browser resources
- Error screenshots captured on failure
- Tests run in both headed and headless modes
- 已安装Playwright和Chromium
- 测试前已启动服务器
- 为动态内容设置了正确的等待状态
- 已捕获截图用于视觉验证
- 已监控控制台日志排查错误
- 已验证网络请求
- Fixtures已正确清理浏览器资源
- 发生错误时已捕获截图
- 已在有头和无头模式下运行测试
Metrics
指标
| Metric | Target | Description |
|---|---|---|
| Test Duration | <10s per test | Individual test execution time |
| Flakiness Rate | <2% | Tests passing consistently |
| Screenshot Match | 100% | Visual regression accuracy |
| Network Coverage | >90% | API endpoints tested |
| 指标 | 目标值 | 描述 |
|---|---|---|
| 测试时长 | 单测试<10秒 | 单个测试的执行时间 |
| 不稳定率 | <2% | 测试通过率的稳定性 |
| 截图匹配度 | 100% | 视觉回归测试的准确性 |
| 网络覆盖率 | >90% | 已测试的API端点占比 |
Dependencies
依赖
bash
pip install playwright pytest requests
playwright install chromiumbash
pip install playwright pytest requests
playwright install chromiumRelated Skills
相关技能
- engineering-report-generator - Generate test reports
- data-pipeline-processor - Process test data
- parallel-file-processor - Batch screenshot processing
- engineering-report-generator - 生成测试报告
- data-pipeline-processor - 处理测试数据
- parallel-file-processor - 批量截图处理
Version History
版本历史
- 1.1.0 (2026-01-02): Upgraded to SKILL_TEMPLATE_v2 format with Quick Start, Usage Examples, Error Handling, Metrics, Execution Checklist
- 1.0.0 (2024-10-15): Initial release with Playwright patterns, server management, debugging tools
- 1.1.0(2026-01-02):升级为SKILL_TEMPLATE_v2格式,新增快速开始、使用示例、错误处理、指标、执行检查清单等内容
- 1.0.0(2024-10-15):初始版本,包含Playwright使用模式、服务器管理、调试工具等内容