К основному содержанию
скилл CX Codex

webapp-testing · bobmatnyc — скилл для Claude Code: что делает и как установить

Справочник по тестированию веб-приложений через Playwright. Подсказывает агенту стабильные селекторы, стратегии ожидания и работу с формами.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add bobmatnyc/claude-mpm-skills --skill webapp-testing -a claude-code
Открыть на GitHub

Что делает webapp-testing

Скилл даёт ИИ-агенту набор паттернов для автоматизации браузера с помощью Playwright на Python. Внутри собраны готовые примеры селекторов, перехвата состояний сети вроде networkidle, проверок видимости и сценариев заполнения форм.

По иерархии надёжности автор ставит атрибуты data-testid и role на первое место, а XPath советует избегать из-за ломкости тестов. В руководстве также описаны встроенные механизмы авто-ожидания Playwright, загрузка файлов через set_input_files и эмуляция сочетаний клавиш.

Для применения этих шаблонов в проекте потребуется сам Playwright и настроенное тестовое окружение.

Какие задачи решает

  • подобрать надёжные селекторы data-testid и role для элементов интерфейса
  • настроить ожидание сетевого покоя networkidle или появления модального окна
  • автоматизировать отправку форм с выпадающими списками и загрузкой файлов
  • написать проверки видимости и текста через expect в Playwright

Примеры запросов агенту

  • Напиши тест на Playwright для формы логина с проверкой появления ошибки
  • Подбери стабильные селекторы role и data-testid для модального окна подтверждения
  • Добавь в тест загрузку файла через set_input_files и ожидание ответа сети

Как установить webapp-testing

1Через Skills CLI (Vercel)

npx skills add bobmatnyc/claude-mpm-skills --skill webapp-testing -a claude-code

2Вручную: положить файлы

~/.claude/skills/webapp-testing/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/webapp-testing/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о webapp-testing

Как установить webapp-testing в Claude Code?

Выполните в терминале команду npx skills add bobmatnyc/claude-mpm-skills --skill webapp-testing -a claude-code.

Что даёт этот скилл агенту?

Он передаёт языковой модели правила работы с Playwright. Агент начинает предпочитать семантические селекторы и штатное авто-ожидание вместо случайных задержек wait_for_timeout.

Какие селекторы скилл считает наименее надёжными?

Худшим вариантом в иерархии назван XPath. Классы CSS также считаются менее стабильными, так как часто меняются при обновлении стилей.

Исходный текст

SKILL.md · MIT
---
name: webapp-testing
description: "Comprehensive web application testing patterns with Playwright selectors, wait strategies, and best practices"
user-invocable: false
disable-model-invocation: true
progressive_disclosure:
  entry_point:
    summary: "Comprehensive web application testing patterns with Playwright selectors, wait strategies, and best practices"
    when_to_use: "When writing tests, implementing webapp-testing-patterns, or ensuring code quality."
    quick_start: "1. Review the core concepts below. 2. Apply patterns to your use case. 3. Follow best practices for implementation."
---
# Playwright Patterns Reference

Complete guide to Playwright automation patterns, selectors, and best practices.

## Table of Contents

- [Selectors](#selectors)
- [Wait Strategies](#wait-strategies)
- [Element Interactions](#element-interactions)
- [Assertions](#assertions)
- [Test Organization](#test-organization)
- [Network Interception](#network-interception)
- [Screenshots and Videos](#screenshots-and-videos)
- [Debugging](#debugging)
- [Parallel Execution](#parallel-execution)

## Selectors

### Text Selectors
Most readable and maintainable approach when text is unique:

```python
page.click('text=Login')
page.click('text="Sign Up"')  # Exact match
page.click('text=/log.*in/i')  # Regex, case-insensitive
```

### Role-Based Selectors
Semantic selectors based on ARIA roles:

```python
page.click('role=button[name="Submit"]')
page.fill('role=textbox[name="Email"]', '[email protected]')
page.click('role=link[name="Learn more"]')
page.check('role=checkbox[name="Accept terms"]')
```

### CSS Selectors
Traditional CSS selectors for precise targeting:

```python
page.click('#submit-button')
page.fill('.email-input', '[email protected]')
page.click('button.primary')
page.click('nav > ul > li:first-child')
```

### XPath Selectors
For complex DOM navigation:

```python
page.click('xpath=//button[contains(text(), "Submit")]')
page.click('xpath=//div[@class="modal"]//button[@type="submit"]')
```

### Data Attributes
Best practice for test-specific selectors:

```python
page.click('[data-testid="submit-btn"]')
page.fill('[data-test="email-input"]', '[email protected]')
```

### Chaining Selectors
Combine selectors for precision:

```python
page.locator('div.modal').locator('button.submit').click()
page.locator('role=dialog').locator('text=Confirm').click()
```

### Selector Best Practices

**Priority order (most stable to least stable):**
1. `data-testid` attributes (most stable)
2. `role=` selectors (semantic, accessible)
3. `text=` selectors (readable, but text may change)
4. `id` attributes (stable if not dynamic)
5. CSS classes (less stable, may change with styling)
6. XPath (fragile, avoid if possible)

## Wait Strategies

### Load State Waits
Essential for dynamic applications:

```python
# Wait for network to be idle (most common)
page.goto('http://localhost:3000')
page.wait_for_load_state('networkidle')

# Wait for DOM to be ready
page.wait_for_load_state('domcontentloaded')

# Wait for full load including images
page.wait_for_load_state('load')
```

### Element Waits
Wait for specific elements before interacting:

```python
# Wait for element to be visible
page.wait_for_selector('button.submit', state='visible')

# Wait for element to be hidden
page.wait_for_selector('.loading-spinner', state='hidden')

# Wait for element to exist in DOM (may not be visible)
page.wait_for_selector('.modal', state='attached')

# Wait for element to be removed from DOM
page.wait_for_selector('.error-message', state='detached')
```

### Timeout Waits
Fixed time delays (use sparingly):

```python
# Wait for animations to complete
page.wait_for_timeout(500)

# Wait for delayed content (better to use wait_for_selector)
page.wait_for_timeout(2000)
```

### Custom Wait Conditions
Wait for JavaScript conditions:

```python
# Wait for custom JavaScript condition
page.wait_for_function('() => document.querySelector(".data").innerText !== "Loading..."')

# Wait for variable to be set
page.wait_for_function('() => window.appReady === true')
```

### Auto-Waiting
Playwright automatically waits for elements to be actionable:

```python
# These automatically wait for element to be:
# - Visible
# - Stable (not animating)
# - Enabled (not disabled)
# - Not obscured by other elements
page.click('button.submit')  # Auto-waits
page.fill('input.email', '[email protected]')  # Auto-waits
```

## Element Interactions

### Clicking
```python
# Basic click
page.click('button.submit')

# Click with options
page.click('button.submit', button='right')  # Right-click
page.click('button.submit', click_count=2)  # Double-click
page.click('button.submit', modifiers=['Control'])  # Ctrl+click

# Force click (bypass actionability checks)
page.click('button.submit', force=True)
```

### Filling Forms
```python
# Text inputs
page.fill('input[name="email"]', '[email protected]')
page.type('input[name="search"]', 'query', delay=100)  # Type with delay

# Clear then fill
page.fill('input[name="email"]', '')
page.fill('input[name="email"]', '[email protected]')

# Press keys
page.press('input[name="search"]', 'Enter')
page.press('input[name="text"]', 'Control+A')
```

### Dropdowns and Selects
```python
# Select by label
page.select_option('select[name="country"]', label='United States')

# Select by value
page.select_option('select[name="country"]', value='us')

# Select by index
page.select_option('select[name="country"]', index=2)

# Select multiple options
page.select_option('select[multiple]', ['option1', 'option2'])
```

### Checkboxes and Radio Buttons
```python
# Check a checkbox
page.check('input[type="checkbox"]')

# Uncheck a checkbox
page.uncheck('input[type="checkbox"]')

# Check a radio button
page.check('input[value="option1"]')

# Toggle checkbox
if page.is_checked('input[type="checkbox"]'):
    page.uncheck('input[type="checkbox"]')
else:
    page.check('input[type="checkbox"]')
```

### File Uploads
```python
# Upload single file
page.set_input_files('input[type="file"]', '/path/to/file.pdf')

# Upload multiple files
page.set_input_files('input[type="file"]', ['/path/to/file1.pdf', '/path/to/file2.pdf'])

# Clear file input
page.set_input_files('input[type="file"]', [])
```

### Hover and Focus
```python
# Hover over element
page.hover('button.tooltip-trigger')

# Focus element
page.focus('input[name="email"]')

# Blur element
page.evaluate('document.activeElement.blur()')
```

## Assertions

### Element Visibility
```python
from playwright.sync_api import expect

# Expect element to be visible
expect(page.locator('button.submit')).to_be_visible()

# Expect element to be hidden
expect(page.locator('.error-message')).to_be_hidden()
```

### Text Content
```python
# Expect exact text
expect(page.locator('.title')).to_have_text('Welcome')

# Expect partial text
expect(page.locator('.message')).to_contain_text('success')

# Expect text matching pattern
expect(page.locator('.code')).to_have_text(re.compile(r'\d{6}'))
```

### Element State
```python
# Expect element to be enabled/disabled
expect(page.locator('button.submit')).to_be_enabled()
expect(page.locator('button.submit')).to_be_disabled()

# Expect checkbox to be checked
expect(page.locator('input[type="checkbox"]')).to_be_checked()

# Expect element to be editable
expect(page.locator('input[name="email"]')).to_be_editable()
```

### Attributes and Values
```python
# Expect attribute value
expect(page.locator('img')).to_have_attribute('src', '/logo.png')

# Expect CSS class
expect(page.locator('button')).to_have_class('btn-primary')

# Expect input value
expect(page.locator('input[name="email"]')).to_have_value('[email protected]')
```

### Count and Collections
```python
# Expect specific count
expect(page.locator('li')).to_have_count(5)

# Get all elements and assert
items = page.locator('li').all()
assert len(items) == 5
```

## Test Organization

### Basic Test Structure
```python
from playwright.sync_api import sync_playwright

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

    # Test logic here
    page.goto('http://localhost:3000')
    page.wait_for_load_state('networkidle')

    browser.close()
```

### Using Pytest (Recommended)
```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(headless=True)
        yield browser
        browser.close()

@pytest.fixture
def page(browser):
    page = browser.new_page()
    yield page
    page.close()

def test_login(page):
    page.goto('http://localhost:3000')
    page.fill('input[name="email"]', '[email protected]')
    page.fill('input[name="password"]', 'password123')
    page.click('button[type="submit"]')
    expect(page.locator('.welcome-message')).to_be_visible()
```

### Test Grouping with Describe Blocks
```python
class TestAuthentication:
    def test_successful_login(self, page):
        # Test successful login
        pass

    def test_failed_login(self, page):
        # Test failed login
        pass

    def test_logout(self, page):
        # Test logout
        pass
```

### Setup and Teardown
```python
@pytest.fixture(autouse=True)
def setup_and_teardown(page):
    # Setup - runs before each test
    page.goto('http://localhost:3000')
    page.wait_for_load_state('networkidle')

    yield  # Test runs here

    # Teardown - runs after each test
    page.evaluate('localStorage.clear()')
```

## Network Interception

### Mock API Responses
```python
# Intercept and mock API response
def handle_route(route):
    route.fulfill(
        status=200,
        body='{"success": true, "data": "mocked"}',
        headers={'Content-Type': 'application/json'}
    )

page.route('**/api/data', handle_route)
page.goto('http://localhost:3000')
```

### Block Resources
```python
# Block images and stylesheets for faster tests
page.route('**/*.{png,jpg,jpeg,gif,svg,css}', lambda route: route.abort())
```

### Wait for Network Responses
```python
# Wait for specific API call
with page.expect_response('**/api/users') as response_info:
    page.click('button.load-users')
response = response_info.value
assert response.status == 200
```

## Screenshots and Videos

### Screenshots
```python
# Full page screenshot
page.screenshot(path='/tmp/screenshot.png', full_page=True)

# Element screenshot
page.locator('.modal').screenshot(path='/tmp/modal.png')

# Screenshot with custom dimensions
page.set_viewport_size({'width': 1920, 'height': 1080})
page.screenshot(path='/tmp/desktop.png')
```

### Video Recording
```python
browser = p.chromium.launch(headless=True)
context = browser.new_context(record_video_dir='/tmp/videos/')
page = context.new_page()

# Perform actions...

context.close()  # Video saved on close
```

## Debugging

### Pause Execution
```python
page.pause()  # Opens Playwright Inspector
```

### Console Logs
```python
def handle_console(msg):
    print(f"[{msg.type}] {msg.text}")

page.on("console", handle_console)
```

### Slow Motion
```python
browser = p.chromium.launch(headless=False, slow_mo=1000)  # 1 second delay
```

### Verbose Logging
```python
# Set DEBUG environment variable
# DEBUG=pw:api python test.py
```

## Parallel Execution

### Pytest Parallel
```bash
# Install pytest-xdist
pip install pytest-xdist

# Run tests in parallel
pytest -n auto  # Auto-detect CPU cores
pytest -n 4     # Run with 4 workers
```

### Browser Context Isolation
```python
# Each test gets isolated context (cookies, localStorage, etc.)
@pytest.fixture
def context(browser):
    context = browser.new_context()
    yield context
    context.close()

@pytest.fixture
def page(context):
    return context.new_page()
```

© bobmatnyc · MIT · bobmatnyc/claude-mpm-skills

Похожие скиллы

Все скиллы по теме «Тесты и QA» →

Сначала — webapp-testing от других авторов.

webapp-testing официальный anthropics Скилл запускает проверки локальных веб-приложений через Playwright: помогает отлаживать UI, делать скриншоты и смотреть логи браузера. 186 758установок improve-codebase-architecture Matt Pocock Скилл ищет архитектурные узкие места в кодовой базе и показывает варианты углубления модулей в HTML-отчёте. Подойдёт для ревью перед рефакторингом. 1 163 035установок design-taste-frontend Leonxlnx Скилл задаёт арт-дирекцию для публичных страниц и рабочих экранов, а затем проверяет результат в браузере по скриншотам. Нужен, когда интерфейс выглядит шаблонным или недоработанным. CX Codex +1 678 700установок tdd Matt Pocock Скилл управляет циклом красный-зелёный в TDD: проверяет, что тесты пишутся до кода, держит их на уровне публичных интерфейсов и не завязывает на внутреннюю структуру. 1 141 062установок skill-creator официальный anthropics Помогает создать новый скилл, доработать существующий и проверить результат через тестовые промпты и оценки. 414 180установок agent-browser vercel-labs Скилл управляет браузером через CLI: открывает страницы, заполняет формы, нажимает кнопки и проверяет веб-приложения. Подходит для задач, где агенту нужно действовать в интерфейсе. CX Codex +1 1 200 000установок prototype Matt Pocock Создаёт временный прототип, чтобы проверить логику, модель состояния или вид интерфейса до работы над основным кодом. 986 201установок

Из того же набора125

local-llm-ops Скилл для работы с локальными моделями через Ollama на Apple Silicon: поднимает сервис, тянет модели, запускает чат и бенчмарки. CX Codex +1 448установок golang-testing-strategies Скилл для написания тестов на Go: табличные тесты, testify, gomock, бенчмарки и покрытие в CI. Пригодится, когда нужно навести порядок в тестовом наборе проекта. CX Codex +1 443установок sveltekit Скилл подсказывает агенту, как устроен SvelteKit: файловый роутинг, load-функции, form actions и адаптеры для деплоя. CX Codex +1 441установок wordpress-advanced-architecture Скилл по продвинутой разработке под WordPress: свои REST-маршруты, команды WP-CLI, кэширование транзиентами и объектным кэшем. CX Codex +1 441установок golang-http-frameworks Скилл помогает проектировать REST API на Go, настраивать роутинг и выбирать между net/http, Chi, Gin, Echo или Fiber. Пригодится при сборке эндпоинтов, валидации данных и тестах через httptest. CX Codex +1 440установок digitalocean-management Скилл для Claude, Codex и Cursor, который помогает настроить мониторинг, проверки доступности и проекты в DigitalOcean. Пригодится, когда нужно собрать наблюдаемость и алерты по дроплетам и кластерам. CX Codex +1 438установок flask Скилл подкладывает агенту готовые шаблоны Flask: фабрика приложения, блюпринты, обработка запросов и ответов. Пригодится, когда пишешь REST API или микросервис на Python. CX Codex +1 437установок hono-rpc Скилл объясняет, как связать сервер и клиент Hono через типы TypeScript: экспорт AppType и клиент hc без кодогенерации. CX Codex +1 437установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой