AI-powered self-healing locators for Playwright Python tests
Project description
playwright-self-healing
AI-powered self-healing locators for Playwright Python tests using Claude API.
When your Playwright locators fail, Claude automatically analyzes screenshots and HTML to find working locators and caches them for future use.
Features
- Automatic Healing: When a locator fails, Claude Vision analyzes the page and finds the element
- YAML Cache: Working locators are cached to avoid repeated API calls
- Rate Limiting: Max 3 Claude API calls per test session (configurable)
- Screenshot Caching: 30-second TTL to avoid repeated captures
- Zero Code Changes: Simple decorator pattern - wrap your Page and you're done
- pytest-playwright Compatible: Works seamlessly with existing test suites
Installation
pip install playwright-self-healing
Quick Start
from playwright.sync_api import sync_playwright, expect # Use expect as normal!
from playwright_self_healing import SelfHealingPage
import os
# Enable self-healing (explicit opt-in for security)
os.environ["ENABLE_SELF_HEALING"] = "true"
# Set your Claude API key
os.environ["ANTHROPIC_API_KEY"] = "sk-ant-..."
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
# Wrap page with self-healing
sh_page = SelfHealingPage(page)
# Use like normal Playwright - healing happens automatically
sh_page.goto("https://example.com")
sh_page.get_by_role("button", name="Submit").click()
# expect() works automatically with SelfHealingLocators - no changes needed!
heading = sh_page.locator("h1")
expect(heading).to_be_visible() # ✅ Just works!
browser.close()
Security Notice
⚠️ IMPORTANT: Self-healing sends page screenshots and HTML to Anthropic's API for analysis.
- Explicit opt-in required: Set
ENABLE_SELF_HEALING=trueto activate - Data transmitted: Screenshots and HTML DOM are sent to Anthropic's Claude API
- Sensitive data: Avoid using on pages with PII, credentials, tokens, or confidential information
- Test environments only: Recommended for staging/test environments, not production
This library requires explicit opt-in to ensure you're aware of data transmission to external APIs.
How It Works
- You use a locator:
sh_page.get_by_role("button", name="Submit").click() - If it fails (TimeoutError), the library:
- Checks the YAML cache for a working locator
- If not cached, captures a screenshot
- Sends screenshot + HTML to Claude API
- Claude analyzes and returns a working locator
- Tests the new locator
- Caches it in
.cache/locators.yaml - Retries your operation with the healed locator
- Next time, uses the cached locator (no API call)
Configuration
All configuration via environment variables:
# Required
export ENABLE_SELF_HEALING="true" # Explicit opt-in (security)
export ANTHROPIC_API_KEY="sk-ant-..."
# Optional (defaults shown)
export CLAUDE_MODEL="claude-sonnet-4.5"
export SELF_HEALING_MAX_RETRIES="3"
export SCREENSHOT_CACHE_TTL="30"
export SELF_HEALING_CACHE_DIR=".cache"
export SELF_HEALING_DEBUG="false"
Pytest Integration
# conftest.py
import pytest
from playwright.sync_api import Page
from playwright_self_healing import SelfHealingPage
@pytest.fixture
def sh_page(page: Page):
return SelfHealingPage(page)
# test_example.py
from playwright.sync_api import expect # ✅ Works as-is, no changes needed!
def test_login(sh_page):
sh_page.goto("https://example.com/login")
sh_page.get_by_label("Email").fill("test@example.com")
sh_page.get_by_role("button", name="Login").click()
# expect() automatically works with SelfHealingLocators
welcome_message = sh_page.get_by_text("Welcome")
expect(welcome_message).to_be_visible() # ✅ Just works!
Zero Code Changes: The library automatically patches Playwright's expect() function to handle SelfHealingLocators. You can continue using from playwright.sync_api import expect in all your existing code - no changes needed!
Cost Estimates
- Claude API: ~$0.01-0.05 per healed locator
- Max 3 API calls per session = ~$0.15 max per test run
- Cached locators cost nothing on subsequent runs
Examples
See the examples/ directory:
basic_usage.py- Simple standalone examplepytest_integration.py- pytest-playwright integrationadvanced_config.py- Configuration and statistics
API Reference
SelfHealingPage
Main class that wraps a Playwright Page.
from playwright_self_healing import SelfHealingPage
sh_page = SelfHealingPage(page, context="Optional page context")
Methods (same as Playwright Page):
get_by_role(role, **kwargs)- Get element by role (with healing)get_by_label(text, **kwargs)- Get element by label (with healing)get_by_text(text, **kwargs)- Get element by text (with healing)get_by_placeholder(text, **kwargs)- Get element by placeholder (with healing)locator(selector)- Get element by CSS (with healing)goto(url),reload(),title(), etc. - All standard Page methods
Additional methods:
get_healing_stats()- Returns dictionary with cache/rate limiter stats
SelfHealingLocator
Locators returned by SelfHealingPage methods support all standard Playwright Locator operations:
Actions:
click(),fill(),type(),clear()- Text input and clickscheck(),uncheck(),set_checked()- Checkbox operationsselect_option()- Select dropdown optionshover(),focus(),blur()- Focus and hover operationspress()- Keyboard inputset_input_files()- File uploadstap()- Touch interactionsdrag_to()- Drag and drop
Queries:
is_visible(),is_hidden()- Visibility checksis_enabled(),is_disabled()- Enablement checksis_editable(),is_checked()- State checkstext_content(),inner_text(),inner_html()- Content extractionall_inner_texts(),all_text_contents()- Batch text extractionget_attribute(),input_value()- Attribute accessbounding_box()- Element position/sizecount()- Number of matching elements
Chaining:
.first,.last- Access first/last matching element (properties)nth(index)- Access specific element by indexall()- Get all matching elements as a listfilter()- Filter matched elementslocator()- Create sub-locatoror_()- Chain locators with OR logic
Other:
wait_for()- Wait for element statescreenshot()- Capture element screenshotevaluate()- Execute JavaScriptdispatch_event()- Dispatch custom eventsscroll_into_view_if_needed()- Scroll element into view
All locator operations support self-healing - if any operation fails, Claude will attempt to find the element automatically.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
ENABLE_SELF_HEALING |
Yes | false |
Explicit opt-in to enable self-healing (security) |
ANTHROPIC_API_KEY |
Yes | - | Your Claude API key |
CLAUDE_MODEL |
No | claude-sonnet-4.5 |
Claude model to use |
SELF_HEALING_MAX_RETRIES |
No | 3 |
Max API calls per session |
SCREENSHOT_CACHE_TTL |
No | 30 |
Screenshot cache duration (seconds) |
SELF_HEALING_CACHE_DIR |
No | .cache |
Directory for locator cache |
SELF_HEALING_DEBUG |
No | false |
Enable debug logging |
Cache Format
Healed locators are stored in .cache/locators.yaml:
get_by_role(button, name=Submit):
locator: "page.get_by_role('button', name='Submit')"
last_updated: "2025-12-24T10:30:00Z"
original_locator: "page.get_by_role('button', name='Submit')"
heal_count: 1
Limitations
- Rate limiting: Max 3 Claude API calls per test session (configurable)
- Timeout: If Claude fails, the original exception is re-raised
- Cost: Each API call costs ~$0.01-0.05 (see Claude pricing)
- Python only: Currently supports Playwright Python only (not Node.js)
Development
# Clone repository
git clone https://github.com/yourusername/playwright-self-healing.git
cd playwright-self-healing
# Install dependencies
pip install -r requirements-dev.txt
# Run tests
pytest
# Format code
black .
# Run linter
flake8 playwright_self_healing/
Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for your changes
- Run the test suite
- Submit a pull request
License
MIT License - see LICENSE for details.
Credits
Built with:
- Playwright for browser automation
- Anthropic Claude for AI-powered element finding
- PyYAML for cache storage
Support
- Issues: GitHub Issues
- Documentation: README.md and
docs/ - Examples:
examples/
Made with ❤️ for the Playwright testing community.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file playwright_self_healing-0.2.0.tar.gz.
File metadata
- Download URL: playwright_self_healing-0.2.0.tar.gz
- Upload date:
- Size: 27.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a689ef0bb11ad8ec92c22c7ee37c3257326c8963f4a81beb350e84c28a64351d
|
|
| MD5 |
5d043e68679baf7eb05142cd8124bb31
|
|
| BLAKE2b-256 |
cee32269d70e3b2db7b2267b11b16b82fe425f54fba1202eeead93ef2b9545d9
|
File details
Details for the file playwright_self_healing-0.2.0-py3-none-any.whl.
File metadata
- Download URL: playwright_self_healing-0.2.0-py3-none-any.whl
- Upload date:
- Size: 28.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad290414125bf42ae9b37d0473e496f7c7244eb3307e1c1def25aac5dafc60ba
|
|
| MD5 |
d0ee51efe895e3446f8567728433a18e
|
|
| BLAKE2b-256 |
a868c383d6f43951cc392b6d75da7d3d0bfcd67050af88857978dcd328a33199
|