# How to Test Local Web Applications with Playwright Using Claude Skills

> Learn to test local web applications with Playwright. Discover the Webapp-Testing skill for reliable browser automation and server lifecycle management.

- Repository: [Composio/awesome-claude-skills](https://github.com/composiohq/awesome-claude-skills)
- Tags: how-to-guide
- Published: 2026-08-30

---

**The Webapp-Testing skill from the ComposioHQ/awesome-claude-skills repository provides a two-layer architecture combining automated server lifecycle management with Playwright browser automation to test locally hosted web applications reliably.**

The ComposioHQ/awesome-claude-skills repository includes a specialized Webapp-Testing skill designed to eliminate the friction of manually orchestrating development servers before running browser tests. This skill leverages a clean separation between server management and test logic, allowing you to test local web applications with Playwright using Claude Skills without complex setup scripts or manual process coordination.

## Understanding the Webapp-Testing Skill Architecture

According to the source code in [`webapp-testing/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/webapp-testing/SKILL.md), the skill implements a deliberate architectural split into two distinct layers that keep automation scripts focused and maintainable.

### Server Management Layer

The **Server Management Layer** resides in [`webapp-testing/scripts/with_server.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/webapp-testing/scripts/with_server.py). This helper script acts as a black-box orchestrator that handles the complete lifecycle of one or more development servers. It starts the server processes, polls until the configured ports become available, and then executes your Playwright automation script. This design ensures your test code assumes the server is already running, eliminating the need for complex startup logic within the automation script itself.

### Playwright Automation Layer

The **Playwright Automation Layer** contains only browser interaction logic using the synchronous Playwright API. Because the server management is handled externally, these scripts remain compact and focused solely on navigation, DOM interaction, and assertions. The skill ships with multiple example scripts in `webapp-testing/examples/` that demonstrate common patterns including DOM inspection, selector discovery, and console log capture.

## Running Tests Against Local Development Servers

The [`with_server.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/with_server.py) script supports both single and multi-server configurations, making it suitable for testing simple static sites or complex full-stack applications with separate backend and frontend processes.

### Single Server Setup

For applications with a single development server, pass the server command and port to the helper script, followed by your Playwright automation file:

```bash
python scripts/with_server.py --server "npm run dev" --port 5173 -- python your_automation.py

```

The script waits until port 5173 accepts connections before executing [`your_automation.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/your_automation.py), ensuring the local web application is fully initialized before Playwright attempts to connect.

### Multi-Server Backend and Frontend

For applications requiring multiple services (such as a backend API and a frontend dev server), specify multiple `--server` and `--port` pairs:

```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

```

This pattern, as implemented in [`webapp-testing/scripts/with_server.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/webapp-testing/scripts/with_server.py), starts both servers concurrently and waits for all specified ports to become available before launching the test suite.

## Writing Reliable Playwright Automation Scripts

The skill enforces several architectural patterns to ensure test stability and reduce flakiness when testing local web applications.

### The Reconnaissance-Then-Action Pattern

The [`webapp-testing/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/webapp-testing/SKILL.md) documentation emphasizes a **Reconnaissance-Then-Action** workflow for dynamic applications. First wait for `networkidle`, capture screenshots or DOM content, and then derive reliable selectors before performing actions. This pattern prevents selector instability that occurs when inspecting the DOM before the application has fully hydrated.

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    
    # Navigate to the locally-served app

    page.goto("http://localhost:5173")
    page.wait_for_load_state("networkidle")  # Critical for dynamic apps

    
    # Action phase: interact with stable elements

    page.click('text="Submit"')
    page.screenshot(path="tmp/final.png", full_page=True)
    
    browser.close()

```

### Element Discovery and Selector Extraction

For complex applications where selectors are unknown, the skill provides [`webapp-testing/examples/element_discovery.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/webapp-testing/examples/element_discovery.py). This script demonstrates the discovery phase of the pattern, capturing screenshots and enumerating available elements before automation:

```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:5173")
    page.wait_for_load_state("networkidle")

    # Reconnaissance: capture visual state

    page.screenshot(path="/tmp/inspect.png", full_page=True)
    
    # Enumerate interactive elements

    buttons = page.locator("button").all()
    print("Found buttons:", [b.text_content() for b in buttons])
    
    browser.close()

```

## Key Architectural Patterns from the Source Code

Several design decisions in the ComposioHQ/awesome-claude-skills repository optimize the skill for LLM-assisted development and reliable test execution:

- **Black-box helper scripts**: The [`with_server.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/with_server.py) utility is designed to operate as a black box invoked via command line. Run `python scripts/with_server.py --help` to view options. This keeps the LLM context window focused on test logic rather than server management code.

- **Synchronous Playwright API**: All examples in `webapp-testing/examples/` use `sync_playwright()` rather than the asynchronous API. This synchronous style simplifies script generation in the Claude environment and reduces complexity for single-threaded test scenarios.

- **Decision tree workflow**: The [`SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/SKILL.md) file includes a decision tree that guides users from static HTML testing to dynamic application testing, explicitly recommending when to use the server helper versus pure Playwright scripts.

- **Best-practice enforcement**: The skill enforces headless Chromium launches, explicit waits using `wait_for_load_state('networkidle')` and `wait_for_selector()`, and mandatory browser cleanup via `browser.close()` to prevent resource leaks.

## Summary

- The **Webapp-Testing skill** uses a two-layer architecture separating server lifecycle management from browser automation logic.
- The **[`with_server.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/with_server.py) helper** handles single or multi-server startup, waiting for ports to become available before executing Playwright scripts.
- All examples use the **synchronous Playwright API** (`sync_playwright()`) for compatibility with Claude-generated code.
- The **Reconnaissance-Then-Action pattern** requires waiting for `networkidle` before inspecting DOM elements to ensure selector stability.
- Example scripts in `webapp-testing/examples/` demonstrate element discovery, console logging, and static HTML automation patterns.

## Frequently Asked Questions

### How do I test a local web application with Playwright if it requires a running development server?

Use the [`with_server.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/with_server.py) helper script from the Webapp-Testing skill. Execute your test command prefixed with the helper that starts your dev server: `python scripts/with_server.py --server "npm run dev" --port 5173 -- python test_script.py`. The helper manages the server lifecycle automatically, ensuring the port is ready before your Playwright script runs.

### Why does the skill use synchronous Playwright instead of async?

The skill intentionally uses `sync_playwright()` because synchronous code is easier to generate and debug within the Claude environment. According to [`webapp-testing/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/webapp-testing/SKILL.md), the synchronous API eliminates the complexity of `async/await` syntax while providing identical browser control capabilities for most testing scenarios.

### What is the Reconnaissance-Then-Action pattern in webapp testing?

This pattern requires waiting for the `networkidle` load state after navigation, then capturing screenshots or DOM snapshots before attempting to interact with elements. As documented in the skill's decision tree, this prevents flaky tests caused by attempting to click elements that haven't fully rendered or hydrated in dynamic JavaScript applications.

### How do I discover reliable selectors for a local web application I didn't build?

Use the [`element_discovery.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/element_discovery.py) example from `webapp-testing/examples/`. This script waits for `networkidle`, captures a full-page screenshot to `/tmp/inspect.png`, and programmatically lists all button elements with their text content. This reconnaissance phase allows you to identify stable text-based or structural selectors before writing your final automation script.