From fls
Write Playwright E2E tests for user flows and browser interactions. Use when testing HTMX, user journeys, or when the user mentions E2E, Playwright, or browser testing.
npx claudepluginhub preludetech/django-craftThis skill is limited to using the following tools:
This Skill helps write end-to-end tests for browser-required behavior.
Generates Playwright end-to-end browser tests for web app user flows. Activates on 'write browser tests', 'playwright test', 'e2e test', 'test the UI' requests.
Executes E2E tests with Playwright: run existing tests, record sessions, generate tests from URLs/descriptions, verify features. Supports TypeScript and Go/HTMX apps.
Guides writing, debugging, and configuring Playwright E2E tests for Next.js, FastAPI, Django, NestJS, Express, React apps. Covers locators, auth reuse, visual regression, accessibility, CI sharding.
Share bugs, ideas, or general feedback.
This Skill helps write end-to-end tests for browser-required behavior.
Use this Skill when:
Use Playwright for:
Use pytest instead for:
Rule: If it can be tested with pytest, test it with pytest. Playwright is for browser-required behavior only.
# Install
uv add --dev playwright
playwright install
# Run tests
pytest tests/e2e/
pytest tests/e2e/test_enrollment.py
import pytest
from django.urls import reverse
@pytest.mark.playwright
def test_user_enrollment_flow(page, live_server):
"""Test user can enroll in a course."""
# Navigate
url = reverse('courses:list')
page.goto(f"{live_server.url}{url}")
# Interact
page.click('text="Enroll"')
page.wait_for_selector('.success-message')
# Assert
assert page.is_visible('text="Enrolled"')
@pytest.mark.playwrightpage and live_server fixturesreverse() for URLs, never hardcodetext="Submit") over CSS selectorswait_for_selector() for dynamic/HTMX contenttests/e2e/wait_for_selector() for dynamic content'text="Enroll"' not '.btn-enroll'reverse('app:view') not '/app/view/'# Prefer text content
page.click('text="Submit"')
# Use role when appropriate
page.click('role=button[name="Submit"]')
# Avoid brittle CSS selectors
page.click('.form > .btn-submit') # BAD
# Wait for HTMX swap
page.click('button[hx-get="/more"]')
page.wait_for_selector('#content .new-item')
# Check dynamic updates
assert page.locator('.item').count() == 5
tests/
└── e2e/
├── conftest.py # Playwright fixtures
├── test_enrollment.py # Enrollment flows
└── test_course_nav.py # Course navigation
page, live_server vs. client, userUse Playwright to complement pytest, not replace it.