Self-healing locators
How SDODS recovers from a broken locator, scores alternatives, records every heal and proposes fixes.
When healing kicks in, how candidates are built from the context you declare, how they are scored, what is recorded, and how repeated heals turn into page-object patches.
Declare context
readonly submit = this.heal.locator(this.page.locator('#login-button'), {
role: 'button', name: 'Login', testId: 'login-button', description: 'login button',
});Resolution
Worst case adds about 4.5 seconds, not the 30-plus seconds of naive fallback chains. Negative assertions are never healed.
heal:
enabled: true
primaryTimeoutMs: 3000
probeTimeoutMs: 1500
minScore: 0.6
actions: [click, fill, select, assert, hover, check]What is recorded
Every heal is attached to the scenario (sdods/heal/<step>/<n>), appended to heal.jsonl in the run directory, annotated on the test, and logged with the suggested rewrite. With a database, heals feed heal_events and locator_stats.
bun run sdods heal report --last
bun run sdods heal report -p demo-shop --write-historyHealing in CI
Healing must never silently hide a regression. On your machine a heal is a convenience: the
locator drifted, the step carried on, and the warning tells you to update the page object. In CI
the same heal means the application changed under the suite, and a green check that hides that is
worse than a red one. So when CI is set (or ci: true in the env yaml), heal.ciMode decides:
heal.ciMode | In CI |
|---|---|
warn (default) | heals and carries on, then lists every heal: a ::warning annotation per locator on GitHub Actions, a table in the job summary, and a warning line on any other CI |
fail | fails the step with HEAL_BLOCKED_IN_CI, naming the locator that would have healed it, and records the event |
off | no healing: the primary locator works or the step fails with Playwright's own error |
heal:
ciMode: fail # release gates: a drifted locator blocks the releasewarn is the default because a team adopting SDODS should not have its pipeline turn red the day
it enables healing; the annotation still puts every heal in front of the person reading the run.
Use fail for release gates. Outside CI ciMode has no effect.
From heal to fix
After three identical successful heals of the same locator, insights produce a page-object patch proposal, deterministically when the page object uses heal.locator, otherwise through the healer agent. Review and accept it like any other proposal.