webapp-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Web 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
undefined
bash
undefined

Install 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

  1. Read files directly to find selectors
  2. Then automate with Playwright
  1. 直接读取文件查找选择器
  2. 使用Playwright进行自动化操作

Dynamic Webapps

动态Web应用

  1. Check if server runs
  2. If not, start with helper script
  3. Perform reconnaissance (screenshots/DOM)
  4. Then automate
  1. 检查服务器是否运行
  2. 若未运行,通过辅助脚本启动
  3. 执行侦察操作(截图/DOM分析)
  4. 进行自动化操作

Running Servers

运行中的服务器

  1. Perform reconnaissance first
  2. Take screenshots
  3. Inspect DOM
  4. Then automate
  1. 先执行侦察操作
  2. 捕获截图
  3. 检查DOM
  4. 进行自动化操作

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
undefined
python
undefined

Fill 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")
undefined
page.wait_for_url("**/dashboard")
undefined

Screenshots

截图

python
undefined
python
undefined

Full 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")
undefined
page.screenshot(path="viewport.png")
undefined

Console Logs

控制台日志

python
undefined
python
undefined

Capture 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']}")
undefined
for msg in console_messages: print(f"[{msg['type']}] {msg['text']}")
undefined

Network Monitoring

网络监控

python
undefined
python
undefined

Capture 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']}")
undefined
for req in requests: print(f"{req['method']} {req['url']}")
undefined

Server Management

服务器管理

Start Server Before Testing

测试前启动服务器

python
import subprocess
import time
from playwright.sync_api import sync_playwright
python
import subprocess
import time
from playwright.sync_api import sync_playwright

Start 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()
undefined
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()
undefined

Check 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 False
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 False

Testing Patterns

测试模式

Assertion Examples

断言示例

python
from playwright.sync_api import expect
python
from playwright.sync_api import expect

Text 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")
undefined
expect(page).to_have_url("http://localhost:3000/dashboard")
undefined

Test 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 output
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 output

Usage

Usage

capture_page_state("http://localhost:3000", "tests/snapshots/")
undefined
capture_page_state("http://localhost:3000", "tests/snapshots/")
undefined

Example 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_response
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_response

Debugging

调试

Slow Motion

慢动作执行

python
browser = p.chromium.launch(slow_mo=500)  # 500ms delay between actions
python
browser = p.chromium.launch(slow_mo=500)  # 500ms delay between actions

Headed Mode

有头模式

python
browser = p.chromium.launch(headless=False)  # See the browser
python
browser = p.chromium.launch(headless=False)  # See the browser

Pause Execution

暂停执行

python
page.pause()  # Opens Playwright Inspector
python
page.pause()  # Opens Playwright Inspector

Trace 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

undefined
undefined

Best Practices

最佳实践

Do

建议做法

  1. Wait appropriately using
    networkidle
    for dynamic content
  2. Select elements by text, role, or data-testid over CSS
  3. Handle async operations with proper waits
  4. Clean up browsers and pages after tests
  5. Use fixtures for browser instance reuse
  6. Capture console logs for debugging
  1. 针对动态内容,使用
    networkidle
    进行合理等待
  2. 优先通过文本、角色或data-testid选择元素,而非CSS选择器
  3. 为异步操作设置正确的等待逻辑
  4. 测试完成后清理浏览器与页面资源
  5. 使用fixtures复用浏览器实例
  6. 捕获控制台日志用于调试

Don't

避免做法

  1. Use arbitrary
    time.sleep()
    for waits
  2. Rely on fragile CSS selectors
  3. Skip error handling in test cleanup
  4. Run tests without checking server status
  5. Ignore network errors during testing
  1. 使用任意
    time.sleep()
    进行等待
  2. 依赖脆弱的CSS选择器
  3. 在测试清理环节跳过错误处理
  4. 未检查服务器状态就运行测试
  5. 忽略测试过程中的网络错误

Error Handling

错误处理

Common Errors

常见错误

ErrorCauseSolution
TimeoutError
Element not found in timeUse explicit waits or increase timeout
Page closed
Browser closed prematurelyCheck cleanup order in fixtures
Connection refused
Server not runningStart server before tests
Element not visible
Hidden by CSS/JSWait for visibility state
Target closed
Navigation during actionWait for navigation to complete
错误原因解决方案
TimeoutError
元素未在指定时间内找到使用显式等待或增加超时时间
Page closed
浏览器提前关闭检查fixtures中的清理顺序
Connection refused
服务器未运行测试前启动服务器
Element not visible
元素被CSS/JS隐藏等待元素进入可见状态
Target closed
操作过程中发生页面跳转等待页面跳转完成后再执行操作

Debugging Tips

调试技巧

python
undefined
python
undefined

Increase 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())
undefined
print(page.content())
undefined

Execution 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

指标

MetricTargetDescription
Test Duration<10s per testIndividual test execution time
Flakiness Rate<2%Tests passing consistently
Screenshot Match100%Visual regression accuracy
Network Coverage>90%API endpoints tested
指标目标值描述
测试时长单测试<10秒单个测试的执行时间
不稳定率<2%测试通过率的稳定性
截图匹配度100%视觉回归测试的准确性
网络覆盖率>90%已测试的API端点占比

Dependencies

依赖

bash
pip install playwright pytest requests
playwright install chromium
bash
pip install playwright pytest requests
playwright install chromium

Related 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使用模式、服务器管理、调试工具等内容