| name | playwright |
| description | Use Playwright for browser automation and end-to-end testing. Invoke when writing e2e tests, browser automation, or testing web UI interactions. |
| allowed-tools | Bash(uv:*, npx:*, pytest:*), Read, Write, Edit, Glob, Grep |
Playwright Usage Guide
Installation
For this Python project, use pytest-playwright:
uv add --dev pytest-playwright
uv run playwright install
Running Tests
uv run pytest tests/e2e/
uv run pytest tests/e2e/ --headed
uv run pytest tests/e2e/test_blog.py::test_homepage -v
uv run pytest tests/e2e/ --headed --slowmo=500
uv run pytest tests/e2e/ --html=report.html
Test Structure
Create e2e tests in tests/e2e/ directory:
import pytest
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from playwright.sync_api import Page
@pytest.fixture(scope="session")
def browser_context_args(browser_context_args):
return {
**browser_context_args,
"viewport": {"width": 1280, "height": 720},
}
@pytest.fixture
def live_server(live_server):
"""Provide Django live server for e2e tests."""
return live_server
import pytest
from playwright.sync_api import Page, expect
def test_homepage_loads(page: Page, live_server):
page.goto(live_server.url)
expect(page).to_have_title("...")
def test_blog_navigation(page: Page, live_server):
page.goto(f"{live_server.url}/blog/")
page.click("text=Read more")
expect(page.locator("h1")).to_be_visible()
Common Patterns
Page Object Model
class BlogPage:
def __init__(self, page: Page):
self.page = page
self.post_links = page.locator(".post-link")
self.search_input = page.locator("[data-testid=search]")
def navigate(self, base_url: str):
self.page.goto(f"{base_url}/blog/")
def search(self, query: str):
self.search_input.fill(query)
self.search_input.press("Enter")
Screenshots and Tracing
def test_with_screenshot(page: Page, live_server):
page.goto(live_server.url)
page.screenshot(path="screenshot.png")
@pytest.fixture(scope="function")
def page(context):
context.tracing.start(screenshots=True, snapshots=True)
page = context.new_page()
yield page
context.tracing.stop(path="trace.zip")
Waiting for Elements
page.wait_for_selector(".loading", state="hidden")
with page.expect_navigation():
page.click("a.nav-link")
page.wait_for_load_state("networkidle")
Debugging
uv run playwright codegen http://localhost:8000
PWDEBUG=1 uv run pytest tests/e2e/test_blog.py -v
uv run playwright show-trace trace.zip
Configuration
Add to pyproject.toml:
[tool.pytest.ini_options]
markers = [
"e2e: end-to-end tests (require browser)",
]
Run e2e tests separately:
uv run pytest -m e2e