Click by description, not selectors.
A Playwright extension for semantic element targeting. Write resilient tests that survive website redesigns.
npm install semantic-playwright playwrightimport { test } from '@playwright/test';
import { semantic } from 'semantic-playwright';
test('login flow', async ({ page }) => {
await page.goto('https://example.com/login');
const s = semantic(page);
// Click and fill by description - no CSS selectors needed
await s.fill('email input', 'user@example.com');
await s.fill('password field', 'secret123');
await s.click('sign in button');
// Wait for success
await s.waitFor('welcome message');
});Modern web UIs change constantly. CSS selectors like #main-nav > ul > li:nth-child(3) > a.btn-primary break the moment a designer moves a button. This library provides self-healing locators that target elements by their semantic purpose.
// Fragile - breaks on redesign
await page.click('#nav-signin-btn');
// Resilient - survives redesign
await s.click('sign in button');The semantic engine classifies DOM elements using multiple signals:
- ARIA roles:
role="button",role="navigation" - Semantic HTML:
<nav>,<main>,<button>,<form> - Text content: "Sign In", "Submit", "Search"
- Class patterns:
btn,nav,form-input - Context: Element inside
<nav>likely navigation-related
No LLM required. Pure heuristic matching. Fast, local, privacy-preserving.
Wrap a Playwright page with semantic methods:
const s = semantic(page);Click an element by description:
await s.click('submit button');
await s.click('login', { purposeHint: 'action' });Fill a form field by description:
await s.fill('email input', 'test@example.com');
await s.fill('search box', 'playwright');Get a Playwright Locator for chaining:
const btn = await s.locator('checkout button');
await btn.hover();
await btn.click();Analyze page structure:
const { elements, summary } = await s.analyze();
console.log(summary);
// { navigation: 12, action: 8, form: 5, content: 20, data: 3, unknown: 0 }Find elements by category:
const buttons = await s.query('action');
const searchInputs = await s.query('form', 'search');Find all matching elements with scores:
const matches = await s.findAll('submit');
for (const { locator, score, text } of matches) {
console.log(`${text}: ${score}`);
}Wait for element to appear:
await s.waitFor('success notification', { timeout: 10000 });| Category | Description | Examples |
|---|---|---|
navigation |
Navigation elements | Nav bars, menus, breadcrumbs |
action |
Interactive actions | Buttons, CTAs, links styled as buttons |
form |
Form inputs | Text fields, selects, checkboxes |
content |
Main content | Articles, headings, paragraphs |
data |
Data display | Tables, lists, grids |
interface SemanticOptions {
purposeHint?: 'navigation' | 'action' | 'form' | 'content' | 'data';
timeout?: number; // Default: 5000ms
minScore?: number; // Default: 20
}src/
├── index.ts # Main API - SemanticPage wrapper
├── semantic-mapper.ts # Classification engine & JS generators
Key design decisions:
- Scripts execute in browser context via
page.evaluate() - Classification is entirely heuristic-based (no external calls)
- Selectors generated are full CSS paths for reliability
- Scoring system prefers exact matches, falls back gracefully
npm install
npm run build
npm testTests should use real websites to validate resilience:
- Test against sites that redesign frequently
- Snapshot selectors, verify semantic descriptions still work after updates
- Compare failure rates: CSS selectors vs semantic descriptions
- Core semantic classification engine
-
semantic()page wrapper -
click(),fill(),locator()methods -
analyze()andquery()methods -
findAll()andwaitFor()methods
- Playwright Test fixtures (
useSemanticPage) - Custom matchers (
expect(s).toHaveElement('login button')) - Confidence thresholds configuration
- Debug mode with match explanations
- Learning/correction persistence
- Domain-specific overrides
- Screenshot-on-failure with element highlighting
- Playwright Reporter integration
- Comprehensive test suite
- Performance benchmarks
- Documentation site
- VS Code extension for selector conversion
This library is inspired by and aims to improve upon:
- Browser-Use: AI agent browser automation (requires LLM)
- Healenium: Self-healing Selenium (Java-focused)
- Test.ai: AI-powered testing (SaaS, expensive)
Our differentiator: No LLM required. Fast, local, free.
MIT