Tests that rewrite themselves.
A year with a self-maintaining suite.
A year running tests that repaired their own selectors and assertions: where it saved us real time, and where it quietly lied.
We ran a self-healing end-to-end suite in production for a full year, selectors that re-anchored themselves when the UI shifted, assertions that regenerated when the expected output changed shape. It earned its keep. It also nearly let a real regression ship, twice. Here's what almost went wrong, and the guardrail that's kept it from happening since.
01 · What was actually eating the maintenance budget
Before self-healing, our test-maintenance time broke down almost the same way every sprint: not new test authoring, not genuine logic bugs, but brittle selectors and copy changes. A button's data-testid moved, a label went from "Submit" to "Confirm order," a div got wrapped in another div for a styling reason nobody told QA about. None of that is a bug. All of it turns a test suite red.
By our own count, that category was consuming close to a third of our total QA engineering hours in a given month, and it was the least interesting third by a wide margin.
02 · Where it genuinely earned its keep
Letting the suite re-anchor a moved selector, or accept a label change that clearly maps to the same underlying element, removed almost that entire category. The pipeline stayed green for the right reason: the feature still worked, the test just had to relearn where to look. Engineers stopped opening pull requests specifically to fix a locator, which was, honestly, nobody's favorite kind of pull request to review either.
“A test suite that heals its own selectors gives you back the time you were spending proving the UI moved. It does not, by itself, know the difference between the UI moving and the UI breaking.”
03 · The two times it almost lied to us
Both incidents had the same shape. A change shipped that altered actual behavior, not just presentation, and the assertion, configured to tolerate "reasonable" drift, adjusted itself to match the new (wrong) output instead of failing. The test stayed green. The bug shipped. In the first case, a discount calculation started rounding in the customer's favor by a cent on certain totals, and the assertion silently widened its tolerance to match. It surfaced two weeks later, from a finance reconciliation report, not from QA.
$ ci run --suite=checkout --self-heal=onlocator drift detected: [data-cta=confirm]confidence 0.94 → auto-healed, loggedassertion drift detected: expect(total).toBeCloseTo(...)confidence 0.71 → auto-healed, NOT flaggedsuite: PASS (47/47)# the second heal is the one that should have paged someone.
The second incident was subtler and worse: a permissions check quietly stopped firing on one API path after a refactor, and the assertion that expected a 403 response healed itself to expect the 200 it was now actually getting. The test suite, functioning exactly as designed, had learned to expect the security hole. That is the moment we stopped thinking of self-healing as a maintenance feature and started thinking of it as something that needed its own oversight.
04 · The guardrails that made it trustworthy again
- 01Heal locators freely. Never heal assertions silently. A moved button is presentation. A changed expected value is behavior. Those two categories need entirely different levels of trust, and treating them the same was our core mistake.
- 02Every assertion-level self-edit requires a human diff before merge. Not a notification. A required review, the same weight as a code change, because that's what it functionally is.
- 03Track a silent-heal rate as its own metric. Not just pass rate. How often the suite is quietly adjusting itself is a health signal in its own right, and a rising rate is worth investigating even when everything is green.
- 04Keep a canary set that is never allowed to self-heal. A small set of your highest-stakes assertions, security checks, financial calculations, run in strict mode permanently. If they fail, they fail loudly, full stop, no exceptions.
// the ledger, honestly: self-healing bought back roughly a third of our maintenance time and cost us two incidents before the guardrails existed. after the guardrails, it's kept the time savings and hasn't cost us a third.
05 · Would we do it again
Yes, with the guardrails, and not a day before them. The lesson wasn't that self-healing tests are dangerous. It's that any automation confident enough to edit its own success criteria needs a harder boundary around what it's allowed to decide alone than we gave it on day one. The risk was never the technology. It was the unmonitored trust we handed it before we'd earned the right to.
$ end of file · written by flux/dk · 2026-08-03