A Chrome extension for QA engineers — ultra CSS/XPath inspector with smart selectors, aliases, scopes, interaction recording, and framework-ready exports for Playwright and Cypress.
- One-click element inspection from the side panel — hover any element to see ranked selector options
- Smart selector engine — generates testid, id, role, aria-label, placeholder, class, CSS path, XPath, and text selectors — each scored 0-100 by stability and uniqueness
- Role-based selectors — detects implicit ARIA roles from HTML tags (button, link, heading, textbox, etc.) combined with accessible name
- Placeholder selectors — captures
placeholderattribute for inputs and textareas - Partial class matching —
[class*="product-card"]for BEM/semantic class fragments, skipping utility classes (Tailwind, state) - Contains text —
//tag[contains(normalize-space(.), "...")]for partial text matching on longer content - Missing testid tip — warns when an element lacks a
data-testidattribute - Preferred type picker — set your default selector type (AUTO / TESTID / ROLE / ARIA / PLACE / ID / CSS / XPATH / TEXT) — auto-selects on every click
- RAW — raw selector values as-is
- PW (Playwright) —
page.getByTestId(...),page.getByRole(...),page.getByLabel(...),page.getByPlaceholder(...),page.getByText(...),page.locator(...) - CY (Cypress) —
cy.get(...),cy.contains(...),cy.xpath(...),cy.get('[placeholder="..."]') - Global switcher in the header — applies to Inspect, Library, and Recordings views
- Copy button always copies the formatted string, ready to paste into test code
- Scopes — organise elements into named scopes (Login Page, Header, Product List, etc.) with nesting
- Scope container selector — optional DOM selector on a scope (e.g.
[data-testid="product-card"]); exports chain through it:page.locator('[data-testid="card"]').getByTestId('buy-btn') - Aliases — human-readable names mapped to selectors (e.g.
login-button->[data-testid="login-btn"]) - Search — filter elements by alias, description, selector value, or tags
- Inline editing — rename alias, update description, change tags, switch active selector
- Scope tree — recursive sidebar with color-coded icons, delete (orphans elements, doesn't delete them)
- Interaction capture — records clicks, inputs, keypresses, navigation with full ranked selector options per step
- Live feed — real-time interaction stream while recording
- Per-step editing — rename alias, choose active selector from ranked dropdown, exclude/remove steps
- Export as test scripts — download as Playwright
.spec.tsor Cypress.cy.jsdirectly from a recording
- 6 export formats: JSON (scoped), YAML (scoped), JSON (flat map), YAML (flat map), Playwright (TypeScript), Cypress (JavaScript)
- Preferred selector type override — when exporting framework formats, force a specific type (e.g. always use testid) with fallback
- Scope container chaining — framework exports chain selectors through the scope's container selector
- Preview — preview export content before downloading
- Import — paste JSON or YAML to import scopes and elements back into the library
inspectorbooster/
├── extension/ # Chrome MV3 extension
│ ├── src/
│ │ ├── background/ # Service worker — message routing, tab state, panel port management
│ │ ├── content/ # isolated.ts (chrome bridge + overlay) + main.ts (selector engine + recording)
│ │ ├── db/ # IndexedDB via idb — scopes, elements, recordings stores
│ │ ├── lib/ # export.ts (serializers) + format-selector.ts (PW/CY formatters)
│ │ ├── panel/ # Side panel UI — InspectorView, LibraryView, RecordingView, ExportDialog
│ │ ├── popup/ # Extension popup — quick status + open panel
│ │ ├── store/ # Zustand stores — inspector (port/state), library (view/prefs)
│ │ └── types/ # All shared TypeScript types
│ ├── public/icons/ # Extension icons (SVG + PNG)
│ └── manifest.json # MV3 manifest with sidePanel permission
├── e2e/ # Playwright e2e tests
│ ├── app/ # Test page (localhost:7777) with known selectors
│ ├── fixtures/ # Extension fixture (launchPersistentContext + --load-extension)
│ ├── pages/ # Page objects — PanelPage, PopupPage
│ └── tests/ # 76 tests: inspector, library, recording, export, popup
├── .github/workflows/ # PR checks, E2E, Release
├── lefthook.yml # Pre-commit hooks (typecheck + build + structlint)
└── .structlint.yaml # Project structure validation
cd extension && npm install && npm run buildThen load the extension:
- Open
chrome://extensions - Enable Developer mode
- Load unpacked -> select
extension/dist/ - Click the extension icon or open the side panel
# Watch mode — extension rebuilds on change
cd extension && npm run dev
# Run e2e tests (headed, parallel)
cd e2e && npm install && npx playwright install chromium --with-deps
npx playwright test76 Playwright tests covering:
| Suite | Tests | What it covers |
|---|---|---|
| Inspector | 20 | Inspect mode, display modes (RAW/PW/CY), preferred type picker, role/placeholder selectors, content script communication |
| Library | 10 | Empty state, seeding, search, scopes, element cards, display mode in cards, scope container |
| Recording | 22 | Start/stop/discard, live feed, saved recordings, alias/exclude/remove, selector dropdown, PW/CY export |
| Export | 17 | All 6 formats, framework options, preferred type override, scope container chaining, preview, import |
| Popup | 5 | Header, tagline, button, hints, idle indicators |
# Run all tests
cd e2e && npx playwright test
# Run specific suite
npx playwright test -g "library"
# Headed mode with UI
npx playwright test --headed --uiThe content script generates selectors ranked by stability score:
| Strategy | Type | Score (unique/non-unique) | Example |
|---|---|---|---|
| data-testid | testid |
98 / 78 | [data-testid="login-btn"] |
| #id | id |
92 / 52 | #login-btn |
| Role + name | role |
88 / 65 | role=button[name="Sign In"] |
| aria-label | aria |
83 / 56 | button[aria-label="Close"] |
| placeholder | placeholder |
75 / 55 | input[placeholder="Search..."] |
| Class chain | css |
72 / 30-65 | button.btn.btn-primary |
| CSS path | css |
62 / 35 | #login-form > div > button |
| Partial class | css |
58 / 38 | [class*="product-card"] |
| Text (exact) | text |
44 | //button[normalize-space(.)="Sign In"] |
| Text (contains) | text |
40 | //button[contains(normalize-space(.), "Add to")] |
| Absolute XPath | xpath |
28 | //html/body/div[1]/form/button[1] |
| Layer | Tech |
|---|---|
| Extension | Chrome MV3, ISOLATED + MAIN world content scripts bridged via window.postMessage |
| Selector engine | Custom — testid, role, aria, placeholder, class, CSS path, XPath, text (exact + contains) |
| UI | React 18, Zustand, TanStack Query v5, Tailwind CSS |
| Storage | IndexedDB via idb (scopes, elements, recordings) |
| Export | JSON, YAML (js-yaml), Playwright TS, Cypress JS |
| Bundler | Vite + vite-plugin-web-extension |
| Testing | Playwright e2e (76 tests, parallel, headed) |
| CI/CD | GitHub Actions — PR checks, E2E, Release (releaseforge + reviewforge + structlint) |
| Hooks | Lefthook — pre-commit (typecheck + build + structlint), commit-msg (conventional commits) |
MIT