@ia-qa/self-healing 1.7.4 → 1.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -14
- package/package.json +16 -2
package/README.md
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ia-qa-heal — self-healing selectors for E2E tests
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ia-qa/self-healing)
|
|
4
|
+

|
|
5
|
+

|
|
2
6
|
|
|
3
7
|
Your E2E tests break because a selector moved, not because the app is wrong. This finds the
|
|
4
8
|
element again and rewrites the test.
|
|
5
9
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
**The verdict is deterministic — no model decides whether your build passes.** When the repair
|
|
11
|
+
is not provable, the tool refuses to guess and tells you why, rather than quietly rewriting a
|
|
12
|
+
test into a green lie.
|
|
9
13
|
|
|
10
14
|
**It runs entirely on your machine.** It brings its own headless Chromium, so it sees
|
|
11
15
|
`localhost`, staging, or an app behind a VPN, and **nothing ever leaves the machine**.
|
|
12
16
|
|
|
17
|
+
Framework-agnostic — Playwright, Cypress, Selenium; JS/TS, Python, Java. Ships a **CLI**, a
|
|
18
|
+
**local MCP server** for AI agents, and an accessibility-tree page mapper.
|
|
19
|
+
|
|
13
20
|
> **New here?** The [step-by-step tutorial](https://www.ia-qa.com/devtools/selector-drift/tutorial)
|
|
14
21
|
> walks the whole thing with no jargon (same text as `TUTORIAL.md`, shipped in this package).
|
|
15
22
|
> This README is the short reference.
|
|
@@ -19,33 +26,61 @@ deterministic: no model decides whether your build passes.
|
|
|
19
26
|
[](https://www.ia-qa.com/media/heal-demo.mp4)
|
|
20
27
|
|
|
21
28
|
`ia-qa-heal run` runs your suite, watches it break, diffs the live app against your baseline,
|
|
22
|
-
rewrites the dead selectors
|
|
23
|
-
|
|
29
|
+
rewrites the dead selectors, then **re-runs the suite to verify** and exits on that verdict.
|
|
30
|
+
Nothing is committed. By default a selector is replaced by the element's new selector, in the
|
|
31
|
+
style your suite already uses — CSS stays CSS. The demo adds `--locators`, which rewrites to
|
|
32
|
+
`getByRole(…, { exact: true })` where that is provably safe: a locator immune to the *next*
|
|
33
|
+
layout change.
|
|
24
34
|
|
|
25
35
|
▶ **[The full 49-second version](https://www.ia-qa.com/media/heal-demo.mp4)** also covers what
|
|
26
36
|
deterministic healing *refuses* to guess, the MCP server answering an agent, and the HTML
|
|
27
37
|
report `--report` writes for a PR.
|
|
28
38
|
|
|
29
|
-
## Install
|
|
39
|
+
## Install
|
|
30
40
|
|
|
31
41
|
```bash
|
|
32
42
|
npm i -D @ia-qa/self-healing
|
|
33
|
-
npx ia-qa-heal init # interactive: writes .ia-qa/config.json
|
|
34
43
|
```
|
|
35
44
|
|
|
36
|
-
|
|
45
|
+
**Four commands to your first verdict** — no baseline needed, nothing is rewritten:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx ia-qa-heal init # interactive: writes .ia-qa/config.json
|
|
49
|
+
npx ia-qa-heal ingest # inventory the selectors and names your tests use
|
|
50
|
+
npx ia-qa-heal map # capture the app, and bind your selectors to it
|
|
51
|
+
npx ia-qa-heal audit # does my suite still name things that exist?
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`audit` is read-only and advisory (exit 0 unless `--strict`) — it answers on day one, before
|
|
55
|
+
you have any history to compare against.
|
|
56
|
+
|
|
57
|
+
**Then one command, for good:**
|
|
37
58
|
|
|
38
59
|
```bash
|
|
39
|
-
npx ia-qa-heal
|
|
40
|
-
npx ia-qa-heal map # capture the app, and bind your selectors to it
|
|
41
|
-
npx ia-qa-heal baseline # promote that capture to "this is how it should be"
|
|
60
|
+
npx ia-qa-heal baseline # lock today's UI as the reference — once
|
|
42
61
|
# … someone changes the UI …
|
|
62
|
+
npx ia-qa-heal run # runs your suite → diffs → fixes → re-runs to verify
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`run` is the whole loop in one verb: it runs your suite, watches it break, diffs the live app
|
|
66
|
+
against the baseline, rewrites the dead selectors, then **re-runs the suite to verify** and
|
|
67
|
+
exits on that verdict. Nothing is committed.
|
|
68
|
+
|
|
69
|
+
<details>
|
|
70
|
+
<summary>Prefer the steps unbundled — <code>map</code> → <code>diff</code> → <code>fix</code></summary>
|
|
71
|
+
|
|
72
|
+
```bash
|
|
43
73
|
npx ia-qa-heal map
|
|
44
|
-
npx ia-qa-heal diff # PASS / FIX / BLOCK
|
|
74
|
+
npx ia-qa-heal diff # PASS / FIX / BLOCK — this is the CI gate
|
|
45
75
|
npx ia-qa-heal fix --dry-run
|
|
46
76
|
npx ia-qa-heal fix
|
|
47
77
|
```
|
|
48
78
|
|
|
79
|
+
Use this when your suite is slow (`run` runs it twice), or when CI already captures with
|
|
80
|
+
`IAQA_CAPTURE=1` — then `diff` alone costs nothing extra.
|
|
81
|
+
|
|
82
|
+
</details>
|
|
83
|
+
|
|
49
84
|
`ingest` comes **first**, and it is not optional if your tests locate by CSS: it is what lets
|
|
50
85
|
`map` bind the strings your tests write to real elements. Re-run it when your test files
|
|
51
86
|
change — `map` says so when they have. Commit `.ia-qa/` (except `session.json`): the baseline
|
|
@@ -122,7 +157,21 @@ What `fix` **refuses** is the point of the tool:
|
|
|
122
157
|
| `unattributable` | `getByText`, `cy.contains`, `getByTitle`… name a **string, not an element**. Nothing proves the test meant the renamed button rather than a heading that never moved, so editing one would break a *passing* test |
|
|
123
158
|
|
|
124
159
|
`--locators` rewrites to `getByRole(role, { name })` instead of a fresher CSS path, where that
|
|
125
|
-
is provably safe — a selector that survives the next layout change.
|
|
160
|
+
is provably safe — a selector that survives the next layout change. Without it, a CSS selector
|
|
161
|
+
is replaced by a CSS selector: the tool does not impose a locator style on your suite.
|
|
162
|
+
|
|
163
|
+
### At runtime, if you want it — `aiClick` / `aiFill`
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { aiClick } from '@ia-qa/self-healing';
|
|
167
|
+
await aiClick(page, 'button#login');
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
If the normal action times out, these read the page contract, re-scan the live page, retry on
|
|
171
|
+
the element that semantically matches, and log a loud warning that the test needs updating.
|
|
172
|
+
Useful to keep a suite green while you triage — but it is a **stopgap, not the loop**: healing
|
|
173
|
+
in memory hides the drift instead of putting it in a pull request. The verbs above edit your
|
|
174
|
+
files so a human reviews the change.
|
|
126
175
|
|
|
127
176
|
## Page Objects written in CSS
|
|
128
177
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ia-qa/self-healing",
|
|
3
|
-
"version": "1.7.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.7.6",
|
|
4
|
+
"description": "Your Playwright, Cypress or Selenium tests break when a selector moves — this finds the element again and rewrites the test. Deterministic: no LLM decides whether your build passes. Runs entirely on your machine, with a local MCP server for agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"self-healing",
|
|
7
7
|
"selectors",
|
|
8
|
+
"broken-selectors",
|
|
9
|
+
"selector-drift",
|
|
10
|
+
"locators",
|
|
11
|
+
"flaky-tests",
|
|
12
|
+
"flaky",
|
|
8
13
|
"e2e",
|
|
14
|
+
"e2e-testing",
|
|
9
15
|
"testing",
|
|
16
|
+
"test-automation",
|
|
10
17
|
"qa",
|
|
11
18
|
"playwright",
|
|
12
19
|
"cypress",
|
|
@@ -20,6 +27,13 @@
|
|
|
20
27
|
"license": "MIT",
|
|
21
28
|
"author": "Jean-Christophe Jamet",
|
|
22
29
|
"homepage": "https://www.ia-qa.com",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/JcJamet/ia-qa-heal.git"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/JcJamet/ia-qa-heal/issues"
|
|
36
|
+
},
|
|
23
37
|
"type": "commonjs",
|
|
24
38
|
"main": "dist/index.js",
|
|
25
39
|
"types": "dist/index.d.ts",
|