mcpField
W
webapp-testing

webapp-testing

github.com/oimiragieo测试与质量4444 次安装17 周前更新
代码仓库

关于 webapp-testing

webapp-testing 是使用 Playwright 的 Python API 测试本地 Web 应用的技能。它为静态文件和运行中的应用提供流程,可检查交互、截图并查看控制台错误。

主要功能

  1. 01使用 Playwright Python 测试本地 Web 应用
  2. 02为静态或动态应用选择测试方式
  3. 03验证前端行为与交互
  4. 04截图并检查控制台错误
  5. 05生成自动化测试脚本

适用场景

  1. 01检查表单和导航流程
  2. 02调试 UI 渲染或行为
  3. 03截取截图用于视觉回归
  4. 04查找浏览器控制台中的 JavaScript 错误

MCP 相关

该技能介绍了通过 Puppeteer MCP 服务进行可选的浏览器自动化,并说明导航、截图、点击、输入表单、选择、悬停和页面求值等工具。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/oimiragieo/agent-studio --skill webapp-testing

安装后在 Claude Code 中输入/webapp-testing确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

commands/
webapp-testing.md
hooks/
post-execute.cjs
pre-execute.cjs
references/
research-requirements.md
rules/
webapp-testing.md
schemas/
input.schema.json
output.schema.json
scripts/
main.cjs
templates/
implementation-template.md

详细介绍

Web Application Testing Skill

改编自 Anthropic 官方技能仓库的 Web 应用测试工具包。提供使用 Python 版 Playwright 测试本地 Web 应用的系统化方法,涵盖前端验证、UI 调试、截图捕获和浏览器控制台日志分析。 - 使用 Playwright(Python)测试本地 Web 应用 - 验证前端功能 - 调试和检查 UI 行为 - 在关键交互点捕获浏览器截图 - 查看浏览器控制台日志并检测错误 - 测试静态 HTML 文件(直接读取 + 选择器识别) - 使用服务器生命周期管理测试动态 Web 应用 - 生成自动化测试脚本 - 发现元素并识别 CSS 选择器 - 管理页面加载状态(networkidle、domcontentloaded、load)

概述

此技能将 Anthropic 的 webapp-testing 技能改编为 agent-studio 框架。它提供了一种在本地测试 Web 应用的系统化方法,并根据被测 Web 内容的类型选择合适的策略。

源代码仓库:https://github.com/anthropics/skills 许可证:MIT 工具:Playwright(Python API)

适用场景

  • 验证 Web 应用的前端功能时
  • 调试 UI 行为或视觉渲染问题时
  • 捕获截图以进行视觉回归测试时
  • 检查浏览器控制台中的 JavaScript 错误时
  • 测试表单提交、导航流程和交互元素时
  • 为 Web 应用生成自动化测试脚本时

铁律

NEVER INSPECT DOM BEFORE WAITING FOR NETWORKIDLE ON DYNAMIC APPS

动态 Web 应用会异步加载内容。在页面稳定之前检查 DOM,会导致结果不准确或不完整。在动态应用上检查渲染内容之前,务必调用 page.wait_for_load_state('networkidle')。

决策树:选择合适的方法

Is the target a static HTML file?
  YES → Approach A: Direct Read
  NO → Is there a running dev server?
    YES → Approach B: Reconnaissance-then-Action
    NO → Approach C: Helper Script First
方法 A:静态 HTML 文件

对于不需要服务器的静态 HTML 文件:

  1. 直接读取 HTML 文件
  2. 确定目标元素的 CSS 选择器
  3. 编写 Playwright 脚本打开文件并验证内容
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto(f"file://{abs_path_to_html}")

    # Verify content
    title = page.title()
    assert title == "Expected Title"

    # Check element exists
    element = page.query_selector("h1.main-heading")
    assert element is not None

    # Capture screenshot
    page.screenshot(path="screenshot.png")
    browser.close()
方法 B:运行中的服务器(先侦察,再操作)

当开发服务器已在运行时:

  1. 侦察:导航到应用并了解页面结构
  2. 等待稳定:page.wait_for_load_state('networkidle')
  3. 检查:查询元素、读取内容、检查控制台日志
  4. 操作:与表单、按钮和导航进行交互
  5. 验证:断言预期结果
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()

    # Capture console messages
    console_messages = []
    page.on("console", lambda msg: console_messages.append(
        f"[{msg.type}] {msg.text}"
    ))

    # Navigate and wait for stability
    page.goto("http://localhost:3000")
    page.wait_for_load_state("networkidle")

    # Discover page structure
    headings = page.query_selector_all("h1, h2, h3")
    buttons = page.query_selector_all("button")
    forms = page.query_selector_all("form")
    links = page.query_selector_all("a[href]")

    # Print discovered elements
    for h in headings:
        print(f"Heading: {h.text_content()}")
    for btn in buttons:
        print(f"Button: {btn.text_content()}")

    # Screenshot before interaction
    page.screenshot(path="before-interaction.png")

    # Interact with form
    page.fill("input[name='email']", "[email protected]")
    page.fill("input[name='password']", "testpass123")
    page.click("button[type='submit']")
    page.wait_for_load_state("networkidle")

    # Screenshot after interaction
    page.screenshot(path="after-interaction.png")

    # Check for console errors
    errors = [m for m in console_messages if "[error]" in m.lower()]
    if errors:
        print(f"Console errors found: {errors}")

    browser.close()
方法 C:没有运行中的服务器(辅助脚本)

当 Web 应用需要启动服务器时:

import subprocess
import time
from playwright.sync_api import sync_playwright

# Start the server
server_proc = subprocess.Popen(
    ["npm", "run", "dev"],
    cwd="/path/to/project",
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    shell=False  # Security: always shell=False
)

# Wait for server to be ready
time.sleep(5)  # Or use a health check loop

try:
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto("http://localhost:3000")
        page.wait_for_load_state("networkidle")

        # Run tests...
        page.screenshot(path="test-result.png")
        browser.close()
finally:
    server_proc.terminate()
    server_proc.wait()

常见测试模式

模式 1:视觉回归检查
# Take baseline screenshot
page.screenshot(path="baseline.png", full_page=True)

# After changes, take comparison screenshot
page.screenshot(path="current.png", full_page=True)

# Compare (use image diff library)
模式 2:表单验证测试
# Test empty submission
page.click("button[type='submit']")
error_msgs = page.query_selector_all(".error-message")
assert len(error_msgs) > 0, "Expected validation errors for empty form"

# Test invalid email
page.fill("input[type='email']", "not-an-email")
page.click("button[type='submit']")
email_error = page.query_selector("input[type='email']:invalid")
assert email_error is not None
模式 3:导航流程测试
# Test navigation links
nav_links = page.query_selector_all("nav a")
for link in nav_links:
    href = link.get_attribute("href")
    link.click()
    page.wait_for_load_state("networkidle")
    assert page.url.endswith(href), f"Expected URL to end with {href}"
    page.go_back()
    page.wait_for_load_state("networkidle")
模式 4:响应式设计测试
viewports = [
    {"width": 375, "height": 812, "name": "mobile"},
    {"width": 768, "height": 1024, "name": "tablet"},
    {"width": 1920, "height": 1080, "name": "desktop"},
]

for vp in viewports:
    page.set_viewport_size({"width": vp["width"], "height": vp["height"]})
    page.wait_for_load_state("networkidle")
    page.screenshot(path=f"responsive-{vp['name']}.png")

关键注意事项

  1. 不要在 networkidle 之前检查 DOM:动态应用会异步加载内容。过早检查会导致结果不完整。
  2. 不要使用 shell=True:启动服务器进程时,出于安全考虑,务必使用 shell=False 和数组参数。
  3. 不要硬编码等待时间:使用 page.wait_for_selector() 或 page.wait_for_load_state(),而不是 time.sleep()。
  4. 不要忽略控制台错误:务必捕获并报告浏览器控制台错误——它们代表实际问题。
  5. 不要忘记清理:务必在 finally 块中终止服务器进程。

前置条件

确保已安装 Playwright:

pip install playwright
playwright install chromium

与 Agent-Studio 集成

推荐工作流
  1. 使用 webapp-testing 验证前端行为
  2. 将截图证据提供给 code-reviewer 进行视觉审查
  3. 使用 tdd 技能根据发现的模式生成测试套件
  4. 使用 accessibility 技能验证 WCAG 合规性
互补技能
技能关系
tdd根据 webapp-testing 的发现生成测试套件
accessibility功能测试后的 WCAG 合规性验证
frontend-expert为测试设计提供 UI/UX 模式指导
chrome-browser另一种浏览器自动化方式
test-generator根据测试模式生成测试代码

铁律

  1. 绝不在 NETWORKIDLE 之前检查 DOM — 动态 Web 应用会异步加载内容。在页面稳定之前检查 DOM,会产生错误或不完整的结果。
  2. 启动服务进程时绝不使用 shell=True — 始终使用 shell=False 和数组参数(SE-01 安全要求)。
  3. 始终捕获控制台错误 — 浏览器控制台错误表明存在实际问题;绝不能在测试报告中忽略它们。
  4. 始终在 finally 块中终止服务进程 — 泄漏的服务进程会破坏后续测试运行并消耗资源。
  5. 绝不硬编码等待时间 — 使用 page.wait_for_selector() 或 page.wait_for_load_state(),而不是 time.sleep()。

反模式

反模式失败原因正确做法
在 networkidle 之前检查 DOM动态内容尚未加载;断言会产生假阴性检查前始终调用 page.wait_for_load_state('networkidle')
使用 time.sleep() 等待不稳定 — 在慢速机器上等待太短,在快速机器上等待太长使用显式等待:wait_for_selector、wait_for_load_state
忽略浏览器控制台错误未检测到实际的 JS 错误;测试通过,但应用已损坏每次测试运行都始终捕获并报告控制台错误
为服务进程使用 shell=True命令注入漏洞始终使用 shell=False 和列表参数
不清理服务进程后续运行时出现端口冲突和资源泄漏使用 try/finally 确保调用 server_proc.terminate()

Puppeteer MCP 浏览器自动化

如果要使用不依赖 Python、原生支持 Agent 的浏览器自动化,请使用来自 modelcontextprotocol/servers 的 Puppeteer MCP 服务:

设置

在 mcpServers 下添加到 .claude/settings.json:

"puppeteer": {
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-puppeteer"]
}
MCP 工具参考
工具用途
puppeteer_navigate导航到 URL 并等待页面加载
puppeteer_screenshot截取屏幕截图(整页或元素)
puppeteer_click点击 CSS 选择器
puppeteer_fill用指定值填写表单输入项
puppeteer_select按值选择下拉选项
puppeteer_hover将鼠标悬停在元素上
puppeteer_evaluate在浏览器上下文中执行 JavaScript
使用模式
// Navigate and capture state
mcp__puppeteer__puppeteer_navigate({ url: 'http://localhost:3000' });
mcp__puppeteer__puppeteer_screenshot({ name: 'initial-state', fullPage: true });

// Interact with forms
mcp__puppeteer__puppeteer_fill({ selector: 'input[name="email"]', value: '[email protected]' });
mcp__puppeteer__puppeteer_click({ selector: 'button[type="submit"]' });
mcp__puppeteer__puppeteer_screenshot({ name: 'after-submit' });

// Evaluate page state
mcp__puppeteer__puppeteer_evaluate({
  script:
    'JSON.stringify({ title: document.title, errors: [...document.querySelectorAll(".error")].map(e => e.textContent) })',
});
何时使用 Puppeteer MCP,何时使用 Playwright Python
场景使用
在 Agent 工作流中快速验证页面Puppeteer MCP
包含断言的复杂测试套件Playwright Python
截取截图作为证据Puppeteer MCP
表单交互和导航两者均可
CI 测试自动化Playwright Python
嵌入 Agent 的浏览器检查Puppeteer MCP

Memory Protocol(强制要求)

开始前:

阅读 .claude/context/memory/learnings.md

检查以下内容:

  • 项目中现有的测试脚本或 Playwright 配置
  • 先前会话中已知的页面选择器
  • 先前发现的控制台错误或不稳定的测试模式

完成后:

  • 发现的测试模式 -> .claude/context/memory/learnings.md
  • 测试不稳定或浏览器问题 -> .claude/context/memory/issues.md
  • 关于测试策略的决策 -> .claude/context/memory/decisions.md

假设任务可能中断:如果没有记录在记忆中,就说明它没有发生。

评论

支持 Markdown