Back to skills
SkillHub ClubShip Full StackFull StackFrontendTesting

webapp-testing

使用 Playwright 与本地 Web 应用程序交互及进行测试的工具包。支持验证前端功能、调试 UI 行为、捕获浏览器截图以及查看浏览器日志。

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
271
Hot score
98
Updated
March 20, 2026
Overall rating
C4.7
Composite score
4.7
Best-practice grade
B77.6

Install command

npx @skill-hub/cli install leastbit-claude-skills-zh-cn-webapp-testing

Repository

LeastBit/Claude_skills_zh-CN

Skill path: skills/webapp-testing

使用 Playwright 与本地 Web 应用程序交互及进行测试的工具包。支持验证前端功能、调试 UI 行为、捕获浏览器截图以及查看浏览器日志。

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack, Frontend, Testing.

Target audience: everyone.

License: 完整条款见 LICENSE.txt.

Original source

Catalog source: SkillHub Club.

Repository owner: LeastBit.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install webapp-testing into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/LeastBit/Claude_skills_zh-CN before adding webapp-testing to shared team environments
  • Use webapp-testing for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: webapp-testing
description: 使用 Playwright 与本地 Web 应用程序交互及进行测试的工具包。支持验证前端功能、调试 UI 行为、捕获浏览器截图以及查看浏览器日志。
license: 完整条款见 LICENSE.txt
---

# Web 应用程序测试

要测试本地 Web 应用程序,请编写原生的 Python Playwright 脚本。

**可用的辅助脚本**:
- `scripts/with_server.py` - 管理服务器生命周期(支持多服务器)

**务必先运行带有 `--help` 参数的脚本**以查看用法。除非您在尝试运行脚本后发现绝对需要自定义解决方案,否则不要阅读源码。这些脚本可能非常庞大,从而污染您的上下文窗口。它们旨在作为黑盒脚本直接调用,而不是摄入到您的上下文窗口中。

## 决策树:选择您的方法

```
用户任务 → 是静态 HTML 吗?
    ├─ 是 → 直接读取 HTML 文件以识别选择器 (selectors)
    │         ├─ 成功 → 使用选择器编写 Playwright 脚本
    │         └─ 失败/不完整 → 视为动态(见下文)
    │
    └─ 否 (动态 Web 应用) → 服务器是否已在运行?
        ├─ 否 → 运行:python scripts/with_server.py --help
        │        然后使用辅助工具 + 编写简化的 Playwright 脚本
        │
        └─ 是 → 侦察并行动:
            1. 导航并等待 networkidle
            2. 截图或检查 DOM
            3. 从渲染状态中识别选择器 (selectors)
            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
```

要创建自动化脚本,仅需包含 Playwright 逻辑(服务器由程序自动管理):
```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True) # 始终以无头模式启动 chromium
    page = browser.new_page()
    page.goto('http://localhost:5173') # 服务器已在运行并就绪
    page.wait_for_load_state('networkidle') # 关键:等待 JS 执行
    # ... 您的自动化逻辑
    browser.close()
```

## 侦察并行动模式

1. **检查渲染后的 DOM**:
   ```python
   page.screenshot(path='/tmp/inspect.png', full_page=True)
   content = page.content()
   page.locator('button').all()
   ```

2. **从检查结果中识别选择器 (selectors)**

3. **使用发现的选择器执行操作**

## 常见陷阱

❌ **不要**在动态应用等待 `networkidle` 之前检查 DOM
✅ **务必**在检查前等待 `page.wait_for_load_state('networkidle')`

## 最佳实践

- **将捆绑脚本视为黑盒** - 要完成一项任务,请考虑 `scripts/` 中可用的脚本之一是否有所帮助。这些脚本可以可靠地处理常见的复杂工作流,而不会弄乱上下文窗口。使用 `--help` 查看用法,然后直接调用。
- 对同步脚本使用 `sync_playwright()`
- 完成后务必关闭浏览器
- 使用描述性的选择器:`text=`、`role=`、CSS 选择器或 ID
- 添加适当的等待:`page.wait_for_selector()` 或 `page.wait_for_timeout()`

## 参考文件

- **examples/** - 显示常见模式的示例:
  - `element_discovery.py` - 发现页面上的按钮、链接和输入框
  - `static_html_automation.py` - 对本地 HTML 使用 file:// URL
  - `console_logging.py` - 在自动化过程中捕获控制台日志 (console logs)


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### scripts/with_server.py

```python
#!/usr/bin/env python3
"""
启动一个或多个服务器,等待它们就绪,运行一个命令,然后进行清理。

用法:
    # 单个服务器
    python scripts/with_server.py --server "npm run dev" --port 5173 -- python automation.py
    python scripts/with_server.py --server "npm start" --port 3000 -- python test.py

    # 多个服务器
    python scripts/with_server.py \
      --server "cd backend && python server.py" --port 3000 \
      --server "cd frontend && npm run dev" --port 5173 \
      -- python test.py
"""

import subprocess
import socket
import time
import sys
import argparse

def is_server_ready(port, timeout=30):
    """通过轮询端口等待服务器就绪。"""
    start_time = time.time()
    while time.time() - start_time < timeout:
        try:
            with socket.create_connection(('localhost', port), timeout=1):
                return True
        except (socket.error, ConnectionRefusedError):
            time.sleep(0.5)
    return False


def main():
    parser = argparse.ArgumentParser(description='在启动一个或多个服务器的情况下运行命令')
    parser.add_argument('--server', action='append', dest='servers', required=True, help='服务器命令 (可重复)')
    parser.add_argument('--port', action='append', dest='ports', type=int, required=True, help='每个服务器对应的端口 (必须与 --server 数量一致)')
    parser.add_argument('--timeout', type=int, default=30, help='每台服务器的超时时间(以秒为单位,默认为 30)')
    parser.add_argument('command', nargs=argparse.REMAINDER, help='服务器就绪后运行的命令')

    args = parser.parse_args()

    # 如果存在 '--' 分隔符,则将其移除
    if args.command and args.command[0] == '--':
        args.command = args.command[1:]

    if not args.command:
        print("错误:未指定要运行的命令")
        sys.exit(1)

    # 解析服务器配置
    if len(args.servers) != len(args.ports):
        print("错误:--server 和 --port 参数的数量必须一致")
        sys.exit(1)

    servers = []
    for cmd, port in zip(args.servers, args.ports):
        servers.append({'cmd': cmd, 'port': port})

    server_processes = []

    try:
        # 启动所有服务器
        for i, server in enumerate(servers):
            print(f"正在启动服务器 {i+1}/{len(servers)}: {server['cmd']}")

            # 使用 shell=True 以支持包含 cd 和 && 的命令
            process = subprocess.Popen(
                server['cmd'],
                shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )
            server_processes.append(process)

            # 等待此服务器就绪
            print(f"正在等待端口 {server['port']} 上的服务器...")
            if not is_server_ready(server['port'], timeout=args.timeout):
                raise RuntimeError(f"服务器未能在 {args.timeout} 秒内于端口 {server['port']} 启动")

            print(f"端口 {server['port']} 上的服务器已就绪")

        print(f"\n所有 {len(servers)} 台服务器均已就绪")

        # 运行命令
        print(f"正在运行: {' '.join(args.command)}\n")
        result = subprocess.run(args.command)
        sys.exit(result.returncode)

    finally:
        # 清理所有服务器
        print(f"\n正在停止 {len(server_processes)} 台服务器...")
        for i, process in enumerate(server_processes):
            try:
                process.terminate()
                process.wait(timeout=5)
            except subprocess.TimeoutExpired:
                process.kill()
                process.wait()
            print(f"服务器 {i+1} 已停止")
        print("所有服务器已停止")


if __name__ == '__main__':
    main()

```

webapp-testing | SkillHub