Skip to content

primathontech/auto-heal-locator

Repository files navigation

Auto-Heal Locators

A self-healing locator system for Playwright that automatically detects broken selectors at runtime, finds alternative locators using CSS and text strategies, and keeps your tests running even when the UI changes. Includes a Healenium-style scoring engine, a lightweight ML model for re-ranking candidates, a self-hosted web dashboard with multi-project support, and full CLI tooling.


Table of Contents


How It Works

The healing engine operates per-action, not per-test. Every Playwright action (click, fill, hover, etc.) is wrapped in a try-catch. When a locator fails, the system follows this flow:

hp.click('#broken-selector')
        │
        ▼
  Playwright throws error
        │
        ▼
  Failure Classifier
  ├── Non-healable? (assertion, visibility, API error) → rethrow immediately
  └── Healable? (locator not found, timeout, strict mode) → continue ▼
        │
        ▼
  Capture DOM Snapshot (full page HTML, URL, title)
        │
        ▼
  Generate Candidates
  ├── History Store → past successful heals for this locator
  ├── CSS Strategy  → IDs, data-testid, roles, aria-labels, names, placeholders
  └── Text Strategy → text=, :has-text(), role-based, label-based selectors
        │
        ▼
  Rank Candidates (history success count → similarity score → confidence)
        │
        ▼
  Verify Top 10 Candidates Against Live Page
  ├── Does locator.count() === 1?  (unique match)
  └── Retry after 200ms delay?     (stability check)
        │
        ▼
  ┌─ Candidate verified ──→ Execute action with healed locator → Record in history
  └─ No candidate works ──→ Throw original error with healing context

The system does not compare against a stored snapshot of the old element. Instead, it searches the current live DOM for alternative ways to locate elements, ranks them by similarity to the original selector, and verifies each against the real page.


Folder Structure

auto-heal-locators/
├── package.json                    # Project config, bin entry, scripts
├── tsconfig.json                   # TypeScript config (ES2020, CommonJS, strict)
├── README.md                       # This file
│
├── src/                            # Source code (TypeScript)
│   ├── engine/                     # Core healing logic
│   │   ├── failureClassifier.ts    # Module 1: Classifies errors as healable/non-healable
│   │   ├── healingEngine.ts        # Module 5: Orchestrates candidate generation, ranking, verification
│   │   └── locatorStrategies.ts    # Module 4: CSS and Text locator generation strategies
│   │
│   ├── context/                    # Failure context data structures
│   │   └── failureContext.ts       # Module 2: DomSnapshot, SourceLocation, HealingResult types
│   │
│   ├── adapter/                    # Playwright integration
│   │   └── playwrightAdapter.ts    # Module 3: HealingPage wrapper, per-action healing for 9 actions
│   │
│   ├── history/                    # Healing history persistence
│   │   └── historyStore.ts         # Module 6: File-based JSON store, lookup/record success/failure
│   │
│   ├── config/                     # Configuration management
│   │   └── defaultConfig.ts        # Module 7a: Central config with env var overrides
│   │
│   ├── cli/                        # Command-line interface
│   │   └── index.ts                # Module 7b: run, report, history, dashboard, register commands
│   │
│   ├── report/                     # Report generation
│   │   ├── jsonReporter.ts         # Module 8: JSON reports with full healing details
│   │   └── htmlReporter.ts         # Module 9: Styled HTML reports with summary cards
│   │
│   ├── patch/                      # Source code patching
│   │   ├── diffGenerator.ts        # Module 10a: Unified diff file generation
│   │   └── patchApplier.ts         # Module 10b: 5-gate safety system for auto-patching test files
│   │
│   ├── scoring/                    # Healenium-style scoring engine
│   │   ├── nodeModel.ts            # DOM node model (tag, id, classes, text, attributes)
│   │   ├── lcsDistance.ts           # LCS path distance, heuristic node distance, Jaccard similarity
│   │   └── scoringEngine.ts        # 6-level detail cascade selector generation, combined scoring
│   │
│   ├── ml/                         # Machine learning components
│   │   ├── featureExtractor.ts     # 16-feature extraction from candidates
│   │   └── mlModel.ts              # Logistic regression with online learning, 60/40 blend re-ranking
│   │
│   ├── registry/                   # Multi-project management
│   │   └── projectRegistry.ts      # Global project registry at ~/.auto-heal/projects.json
│   │
│   └── dashboard/                  # Self-hosted web dashboard
│       └── server/
│           └── dashboardServer.ts  # HTTP server with embedded SPA, multi-project API routes
│
├── dist/                           # Compiled JavaScript output (generated by tsc)
│
├── types/                          # Type stubs for compilation
│   ├── node/index.d.ts             # Node.js type stubs (fs, path, http, os, child_process)
│   └── playwright/index.d.ts       # Playwright type stubs (Page, Locator, Browser, ElementHandle)
│
└── examples/
    └── playwright/
        └── sample.spec.ts          # Example test file

Requirements

  • Node.js >= 16.x
  • Playwright >= 1.30.0 (@playwright/test)
  • TypeScript >= 5.x (dev dependency, included)
  • Operating System: macOS, Linux, or Windows

Installation

# Clone or copy the project
cd auto-heal-locators

# Install dependencies
npm install

# Build the TypeScript source
npm run build

# (Optional) Link globally for the auto-heal CLI command
npm link

After npm link, you can use auto-heal from any directory:

auto-heal dashboard
auto-heal register
auto-heal projects

Quick Start

1. Link into your test project

From your Playwright test project:

npm install ../auto-heal-locators    # or the path to auto-heal-locators

2. Create the integration files

Create core/healing/healingSetup.js in your project:

const path = require('path');
const { HealingEngine } = require('auto-heal-locators/dist/engine/healingEngine');
const { HistoryStore } = require('auto-heal-locators/dist/history/historyStore');
const { HealingPage } = require('auto-heal-locators/dist/adapter/playwrightAdapter');
const { loadConfig } = require('auto-heal-locators/dist/config/defaultConfig');
const { autoRegister } = require('auto-heal-locators/dist/registry/projectRegistry');

let _engine = null, _config = null, _historyStore = null;

function initHealing() {
    if (_engine) return { config: _config, engine: _engine, historyStore: _historyStore };

    const projectRoot = path.resolve(__dirname, '..', '..');

    _config = loadConfig({
        historyFilePath: path.join(projectRoot, '.auto-heal', 'history.json'),
        reportDir: path.join(projectRoot, '.auto-heal', 'reports'),
        verbose: true,
    });

    _historyStore = new HistoryStore(_config.historyFilePath);
    _engine = new HealingEngine(_historyStore);

    // Auto-register in global project registry
    try { autoRegister(projectRoot); } catch {}

    console.log('[auto-heal] Healing engine initialized');
    return { config: _config, engine: _engine, historyStore: _historyStore };
}

function createHealingPage(page, options = {}) {
    const { engine } = initHealing();
    return new HealingPage(page, engine, { verbose: true, ...options });
}

module.exports = { initHealing, createHealingPage };

Create core/healing/healingFixture.js:

const base = require('@playwright/test');
const { createHealingPage } = require('./healingSetup');

const test = base.test.extend({
    hp: async ({ page }, use) => {
        const healingPage = createHealingPage(page);
        await use(healingPage);
    },
});

module.exports = { test, expect: base.expect };

3. Write tests using hp

const { test, expect } = require('./core/healing/healingFixture');

test('my test with healing', async ({ page, hp }) => {
    await page.goto('https://example.com');

    // Use hp instead of page for actions you want healed
    await hp.click('#submit-button');     // If #submit-button breaks, healing kicks in
    await hp.fill('#email-input', 'test@example.com');
    await hp.hover('.nav-menu-item');

    // Use page directly for assertions (these should NOT be healed)
    await expect(page.locator('.success-message')).toBeVisible();
});

4. Run and view results

# Run the tests
npx playwright test my-test.spec.js

# Launch the dashboard
npm run heal:dashboard
# or
auto-heal dashboard

CLI Reference

After building, use via node dist/cli/index.js <command> or auto-heal <command> (if npm linked).

Command Description
dashboard Start the web dashboard at http://localhost:4040
dashboard --port 5050 Start on a custom port
dashboard --project <id> Open with a specific project selected
register Register the current directory as a project
register --name "My App" Register with a custom display name
unregister Remove the current project from the registry
projects List all registered projects with entry counts
run <testFile> Run a Playwright test with healing env vars set
report Generate JSON + HTML reports from history
history Display healing history in terminal
clear-history Delete all healing history
help Show usage information

Dashboard

The dashboard is a self-hosted web application with no external dependencies (embedded SPA using Node's built-in http module).

Features:

  • Overview page: Total events, healed count, failed count, success rate, ML model status, timeline chart, strategy breakdown donut chart, top healed locators table
  • Healing History page: Full table of all healing events with original locator, healed locator, strategy used, success/failure counts, timestamps
  • ML Model page: Model status (active/training), training example count, learning rate, feature importance bar chart with positive/negative weights
  • Reports page: List of generated JSON reports with view links
  • Project Switcher: Dropdown in the sidebar to switch between registered projects (see Multi-Project Support below)

Launch:

# From your test project (using convenience script)
npm run heal:dashboard

# From anywhere (if auto-heal is npm linked)
auto-heal dashboard

# From the auto-heal-locators directory
npm run dashboard

Configuration

All settings have sensible defaults and can be overridden via environment variables, CLI flags, or the loadConfig() function.

Setting Default Env Variable CLI Flag
Healing enabled true AUTO_HEAL_ENABLED=false
Auto-apply patches false AUTO_HEAL_APPLY=true --auto-apply
Verbose logging false AUTO_HEAL_VERBOSE=true --verbose
Locator timeout 5000ms AUTO_HEAL_TIMEOUT=5000 --timeout
Max candidates 10 AUTO_HEAL_MAX_CANDIDATES=10
History file path {cwd}/.auto-heal/history.json AUTO_HEAL_HISTORY_PATH --history-file
Report directory {cwd}/.auto-heal/reports AUTO_HEAL_REPORT_DIR --report-dir

Healing Trigger Rules

Not every test failure should be healed. The failure classifier enforces strict rules:

Healable (healing is attempted):

  • "No element found for selector" — locator doesn't match anything
  • "Timeout waiting for selector" — element never appeared
  • "Strict mode violation" — locator matched multiple elements

Non-healable (error rethrown immediately):

  • Assertion failures (expect(...).toBe(...))
  • Visibility/interaction failures ("element not visible", "not interactable")
  • API/network errors
  • Navigation failures
  • Authentication errors
  • JavaScript evaluation errors

Non-healable patterns are checked first to prevent false positives. The system will never try to "heal" a legitimate test failure.


Auto-Apply Safety Gates

When AUTO_HEAL_APPLY=true, the patch applier can rewrite your test file to replace the broken locator with the healed one. This goes through 5 mandatory safety gates:

  1. The healed locator must resolve successfully on the live page
  2. The healed locator must pass a retry verification (200ms delay, re-check)
  3. A .bak backup of the original file must be created
  4. A .diff file must be generated showing the exact change
  5. The AUTO_HEAL_APPLY environment variable must be explicitly set to true

If any gate fails, patching is skipped and the test continues with runtime healing only.


Scoring Engine and ML Model

Healenium-Style Scoring (always active)

The scoring engine uses a weighted heuristic to compare DOM nodes:

Attribute Weight
Tag name 25%
ID 25%
CSS classes 15%
Inner text 10%
Other attributes 15%
DOM index 10%

It also computes LCS (Longest Common Subsequence) path distance between the original element's DOM path and each candidate's path. The combined score is pathScore * 0.6 + nodeScore * 0.4.

The scoring engine generates selectors using a 6-level detail cascade:

  1. TAG#id
  2. TAG.class
  3. TAG[data-testid]
  4. TAG.class:nth-of-type(n)
  5. TAG[attr1][attr2][attr3]
  6. Full XPath (last resort)

ML Model (activates after 20 training examples)

A logistic regression model is trained online on each healing outcome. It extracts 16 features from each candidate:

pathScore, nodeScore, combinedScore, sameTag, hasId, hasTestId, hasRole, classOverlap, attrOverlap, textSimilarity, depthDifference, indexDifference, historySuccessRate, historyUsageCount, detailLevel, isXPath

Until 20 examples are collected, the system uses rule-based scoring only. After that, the ML model re-ranks candidates with a 60/40 blend (ML prediction / original score). Model weights persist to .auto-heal/model.json.


Multi-Project Support

The system supports multiple projects through a global registry at ~/.auto-heal/projects.json.

Registering projects:

# From inside your project directory
auto-heal register --name "My E2E Tests"

# Projects also auto-register on first test run (via healingSetup.js)

Listing projects:

auto-heal projects

Dashboard with project switcher:

When multiple projects are registered, the dashboard shows a dropdown in the sidebar to switch between them. Each project's healing history, stats, timeline, and reports are completely segregated.

# Launch — automatically detects all registered projects
auto-heal dashboard

# Open with a specific project pre-selected
auto-heal dashboard --project my-e2e-tests

Removing a project:

cd /path/to/project
auto-heal unregister

History and Reports

History File

Located at {project}/.auto-heal/history.json. Contains all healing events:

{
  "version": 1,
  "entries": [
    {
      "originalLocator": "#submit-btn",
      "healedLocator": "button[name=\"submit\"]",
      "domFingerprint": "a3f8c2...",
      "strategy": "css-name",
      "successCount": 3,
      "failureCount": 0,
      "lastUsed": "2026-02-06T10:30:00.000Z"
    }
  ]
}

Reports

Generated in {project}/.auto-heal/reports/ in both JSON and HTML formats. Each report includes the test file, line number, action type, original and healed locators, strategy used, whether the patch was applied, and timestamp.

# Generate reports from history
auto-heal report

# Reports are also auto-generated after test runs via the CLI
auto-heal run tests/my-test.spec.js

Environment Variables

Variable Values Description
AUTO_HEAL_ENABLED true / false Enable or disable healing entirely
AUTO_HEAL_APPLY true / false Enable auto-patching of test source files
AUTO_HEAL_VERBOSE true / false Enable detailed logging of healing attempts
AUTO_HEAL_TIMEOUT milliseconds Locator resolution timeout
AUTO_HEAL_MAX_CANDIDATES number Max candidates to try per failure
AUTO_HEAL_HISTORY_PATH file path Override the history file location
AUTO_HEAL_REPORT_DIR directory path Override the report output directory

Supported Healing Actions

The HealingPage wrapper supports per-action healing for these Playwright methods:

Method Signature
click hp.click(selector, options?)
fill hp.fill(selector, value, options?)
type hp.type(selector, text, options?)
hover hp.hover(selector, options?)
check hp.check(selector, options?)
uncheck hp.uncheck(selector, options?)
focus hp.focus(selector, options?)
press hp.press(selector, key, options?)
selectOption hp.selectOption(selector, values, options?)

For non-healed operations (navigation, assertions, waiting), use the page object directly or access it via hp.rawPage.


License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors