Click by description, not selectors.
A Playwright extension for semantic element targeting. Write resilient tests that survive website redesigns.
npm install semantic-playwright playwright
import { 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