@ia-qa/self-healing 0.1.0 → 0.2.0
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 +11 -5
- package/TUTORIAL.md +20 -2
- package/dist/browser/match.d.ts +36 -13
- package/dist/browser/match.js +117 -35
- package/dist/browser/match.js.map +1 -1
- package/dist/cli/diff.js +8 -1
- package/dist/cli/diff.js.map +1 -1
- package/dist/cli/fix.js +42 -3
- package/dist/cli/fix.js.map +1 -1
- package/dist/cli/index.js +3 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/config.js +12 -1
- package/dist/config.js.map +1 -1
- package/dist/fixEngine.d.ts +39 -1
- package/dist/fixEngine.js +123 -11
- package/dist/fixEngine.js.map +1 -1
- package/dist/mcp/server.js +15 -1
- package/dist/mcp/server.js.map +1 -1
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @ia-qa/self-healing
|
|
1
|
+
# @ia-qa/self-healing
|
|
2
2
|
|
|
3
3
|
Self-healing E2E toolkit: a **local MCP server** for AI agents, a guided **CLI**, an accessibility-tree page mapper, and runtime helpers (`aiClick` / `aiFill`) that recover from broken selectors. Framework- and language-agnostic (Cypress, Playwright, Selenium…; JS/TS, Python, Java…).
|
|
4
4
|
|
|
@@ -59,10 +59,14 @@ Only if all four fail does it error, listing the three fixes. `map_app` exposes
|
|
|
59
59
|
🔧 healable button "Se connecter" button#login-btn → button.btn-primary (exact name)
|
|
60
60
|
⛔ lost button "Supprimer le compte" button#delete → (no match)
|
|
61
61
|
```
|
|
62
|
-
Exit codes for pipelines: `0` = PASS or FIX, `1` = BLOCK (add `--strict` to fail on FIX too), `2` = bad input. Use `--json` for machine-readable output. Same diff engine as the web tool (`src/browser/match.js`).
|
|
62
|
+
Exit codes for pipelines: `0` = PASS or FIX, `1` = BLOCK — lost, ambiguous, or rebound (add `--strict` to fail on FIX too), `2` = bad input. Use `--json` for machine-readable output. Same diff engine as the web tool (`src/browser/match.js`).
|
|
63
63
|
|
|
64
|
-
Every element carries a **context** (nearest landmark + section heading) so two elements with the same role + accessible name (five "Delete" buttons) stay distinguishable. The diff classifies each baseline element as `ok`, `renamed` (
|
|
65
|
-
|
|
64
|
+
Every element carries a **context** (nearest landmark + section heading) so two elements with the same role + accessible name (five "Delete" buttons) stay distinguishable. The diff classifies each baseline element as `ok`, `renamed` (same element, new accessible name — a *content* drift to eyeball), `healable` (deterministic old→new rewrite), `ambiguous` (several equal matches — the tool **refuses to guess**, a human decides), or `lost` (no match).
|
|
65
|
+
|
|
66
|
+
Identity comes from the contract (role + accessible name), never from the selector string. A selector that still resolves only proves the *position* is still occupied: insert one button above a tab bar and every `nth-of-type` below it silently slides onto its neighbour. Any row where that happened is flagged `rebound` — the old selector resolves, but to a **different element**, so the suite is green while clicking the wrong thing. Rebound rows are rewritten like any other healable row, and they **BLOCK**: a `FIX` verdict exits `0`, which is exactly how this ships unnoticed.
|
|
67
|
+
4. **`ia-qa-heal fix <before.json> <after.json> <test-paths…>`** — the deterministic half. Applies **only** the `healable` rewrites to your test files, replacing the selector only where it appears as a quoted string literal (`'…'`/`"…"`/`` `…` ``, quote-safe for attribute selectors), across any framework/language. Every rewrite is applied in a single pass against the selector each occurrence had in the file, so a *permuted* set (`nth-of-type(1)→(2)`, `(2)→(3)`) can never chain and drag `(1)` to `(3)`. LOST / AMBIGUOUS / RENAMED are printed but never touched — they need judgment. It **edits the working tree and never commits**: review with `git diff`, then push or discard. `--dry-run` previews the plan. This is "prepare the ground, the human decides" as a command.
|
|
68
|
+
|
|
69
|
+
**`--locators`** rewrites to a Playwright role locator — `page.getByRole('button', { name: 'Validator' })` — instead of a selector, wherever role + accessible name identifies exactly one element. A repaired positional selector is only correct until the next insertion; a role locator is what the contract already means, so it does not drift at all. Applies to `.js`/`.ts` files and Playwright call shapes (`page.click('…')`, `page.locator('…')`, `page.fill('…', v)`, …); every other file and every element without an unambiguous role + name keeps the plain selector rewrite. `getByRole` is strict, so a locator is emitted only when it provably resolves to one element — otherwise the tool would trade a silent wrong click for a loud crash.
|
|
66
70
|
5. **Runtime healing** — in your Playwright tests:
|
|
67
71
|
```ts
|
|
68
72
|
import { aiClick, aiFill } from '@ia-qa/self-healing';
|
|
@@ -88,4 +92,6 @@ node dist/cli/index.js init
|
|
|
88
92
|
node dist/cli/index.js map
|
|
89
93
|
```
|
|
90
94
|
|
|
91
|
-
`playwright` is a peer dependency — the consuming test project provides it (`npx playwright install chromium` if needed).
|
|
95
|
+
`playwright` is a peer dependency — the consuming test project provides it (`npx playwright install chromium` if needed). This is deliberate: bundling our own copy would let a project on a different Playwright version end up with two installs and a browser-revision skew, which is exactly what the shared launcher exists to avoid.
|
|
96
|
+
|
|
97
|
+
`@aws-sdk/client-ssm` is an **optional** peer, needed only by the `aws-ssm` secret source. It is ~5 MB and imported lazily, so it is not a tax on installs that use the `env` source: `npm i @aws-sdk/client-ssm` if you want SSM, and the CLI tells you so if you pick it without.
|
package/TUTORIAL.md
CHANGED
|
@@ -257,6 +257,21 @@ npx ia-qa-heal fix .ia-qa/mapping/checkout.baseline.json .ia-qa/mapping/checkout
|
|
|
257
257
|
npx ia-qa-heal fix .ia-qa/mapping/checkout.baseline.json .ia-qa/mapping/checkout.json tests/
|
|
258
258
|
```
|
|
259
259
|
|
|
260
|
+
### Step 6.5b — Stop fixing the same test twice (`--locators`)
|
|
261
|
+
|
|
262
|
+
A repaired `nth-of-type(2)` is still an `nth-of-type(2)`: correct today, and wrong again the day someone inserts a button above it. If your suite is Playwright in `.js`/`.ts`, add `--locators`:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
npx ia-qa-heal fix before.json after.json tests/ --locators
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
```diff
|
|
269
|
+
- await page.click('#tabs > button:nth-of-type(2)');
|
|
270
|
+
+ await page.getByRole('button', { name: "Validator" }).click();
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
That is the same identity the contract has used all along — role + accessible name — written in a form Playwright understands. Nothing above it can shift it. Elements whose role + name is ambiguous (five "Delete" buttons) keep their selector rewrite: `getByRole` would match all five and throw, and trading a silent wrong click for a loud crash is not a fix.
|
|
274
|
+
|
|
260
275
|
### Step 6.6 — You review. You decide.
|
|
261
276
|
```bash
|
|
262
277
|
git diff # look at exactly what changed
|
|
@@ -274,19 +289,22 @@ You'll see one of three words. This is the whole product — learn these.
|
|
|
274
289
|
|---|---|---|
|
|
275
290
|
| ✅ **PASS** | Nothing moved. | Nothing. Go home. |
|
|
276
291
|
| 🔧 **FIX** | Selectors broke, but each has exactly one obvious replacement. | Run `fix`, review `git diff`, commit. |
|
|
277
|
-
| ⛔ **BLOCK** | Something is **lost** or **
|
|
292
|
+
| ⛔ **BLOCK** | Something is **lost**, **ambiguous**, or **rebound**. | Read below. A human is required. |
|
|
278
293
|
|
|
279
294
|
And per element:
|
|
280
295
|
|
|
281
296
|
| Status | Plain English | Auto-fixed? |
|
|
282
297
|
|---|---|---|
|
|
283
298
|
| **ok** | Unchanged. | — |
|
|
284
|
-
| **renamed** |
|
|
299
|
+
| **renamed** | Same element, new *label* ("Buy" → "Subscribe"). Your test still passes, and still clicks the right thing. | ❌ No — **look at it**. It might be a real product change your test should have caught. |
|
|
285
300
|
| **healable** | The selector moved; the same element is clearly still there. | ✅ Yes |
|
|
286
301
|
| **ambiguous** | Several elements match equally (five "Delete" buttons). | ❌ No — **the tool refuses to guess.** Healing the wrong one would make a broken test green. Add a `data-testid` to that element. |
|
|
287
302
|
| **lost** | Gone. Nothing matches. | ❌ No — the element was removed or renamed beyond recognition. Fix or delete the test. |
|
|
303
|
+
| **rebound** ⚠️ | Your selector still resolves — **onto a different element**. Insert one button above a tab bar and every `nth-of-type` below it slides onto its neighbour. | ✅ The rewrite is applied, but this **BLOCKs**: your suite has been green while clicking the wrong element, and no test failure was ever going to tell you. |
|
|
288
304
|
|
|
289
305
|
> 💡 **Why "ambiguous" refuses instead of picking:** a test that clicks the *wrong* Delete button and passes is worse than a test that fails. Failing is honest.
|
|
306
|
+
>
|
|
307
|
+
> 💡 **Why "rebound" blocks instead of just fixing:** it is that same failure, already shipped. A `FIX` verdict exits `0`, so treating a rebind as a routine fix would keep the pipeline green on a suite that is silently testing the wrong button. Positional selectors are what make this possible — a `data-testid` makes it impossible.
|
|
290
308
|
|
|
291
309
|
---
|
|
292
310
|
|
package/dist/browser/match.d.ts
CHANGED
|
@@ -51,25 +51,47 @@ export function matchElement(target: any, candidates: any): {
|
|
|
51
51
|
} | null;
|
|
52
52
|
/** Healer-facing shim: selector only when unambiguously matched, else null. */
|
|
53
53
|
export function heuristicMatch(target: any, candidates: any): any;
|
|
54
|
+
/**
|
|
55
|
+
* Does this selector still designate the *same* element after the DOM around it
|
|
56
|
+
* changes? Only the attribute-anchored shapes of `stableSelector`'s cascade do:
|
|
57
|
+
* `[data-testid="…"]`, `tag#id`, `tag[name="…"]`.
|
|
58
|
+
*
|
|
59
|
+
* Everything else is a structural path, and a structural path is *positional*:
|
|
60
|
+
* insert one sibling above the element and the very same selector string now
|
|
61
|
+
* resolves to its neighbour. "It still resolves" is therefore evidence about a
|
|
62
|
+
* position, never about identity — treating it as identity is how a diff comes to
|
|
63
|
+
* report a rebind as a harmless relabel.
|
|
64
|
+
*/
|
|
65
|
+
export function isIdentitySelector(selector: any): boolean;
|
|
54
66
|
/**
|
|
55
67
|
* Diff a baseline mapping against a current one and produce a CI-style verdict.
|
|
56
68
|
*
|
|
69
|
+
* Identity comes from the contract (role + accessible name), never from the
|
|
70
|
+
* selector string: see `isIdentitySelector`. A selector that still resolves only
|
|
71
|
+
* proves the *position* is still occupied — possibly by a different element.
|
|
72
|
+
*
|
|
57
73
|
* Per baseline element:
|
|
58
74
|
* - `ok` — selector still resolves and the accessible name is unchanged
|
|
59
|
-
* - `renamed` —
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* - `
|
|
75
|
+
* - `renamed` — the same element is still there, wearing a new label. Only
|
|
76
|
+
* claimed when the selector is identity-bearing, or when no other
|
|
77
|
+
* baseline element accounts for what now sits at that selector.
|
|
78
|
+
* The test still passes and clicks the right thing: content drift
|
|
79
|
+
* (i18n / copy) a human should eyeball, not a structural break.
|
|
80
|
+
* - `healable` — role + name (+ context) still identify exactly one element at a
|
|
81
|
+
* different selector → deterministic old→new rewrite
|
|
82
|
+
* - `ambiguous` — several elements match equally; healing would be a guess, so we
|
|
83
|
+
* refuse and hand it to a human
|
|
84
|
+
* - `lost` — nothing matches: the element is gone
|
|
85
|
+
* - `added` — element present now, accounted for by no baseline element
|
|
86
|
+
*
|
|
87
|
+
* Any row may carry `rebound: true`: the old selector still resolves, but onto a
|
|
88
|
+
* *different* element (`reboundTo`). That is the silent-failure case this tool
|
|
89
|
+
* exists to catch — the test is green today while clicking the wrong element — so
|
|
90
|
+
* it BLOCKs rather than merely asking for a fix: a FIX verdict exits 0 by default,
|
|
91
|
+
* which would let exactly this ship.
|
|
69
92
|
*
|
|
70
|
-
* Verdict (drives the CI exit code): BLOCK if anything is lost or
|
|
71
|
-
* FIX if anything is only healable
|
|
72
|
-
* the test still runs — but is surfaced for review).
|
|
93
|
+
* Verdict (drives the CI exit code): BLOCK if anything is lost, ambiguous or
|
|
94
|
+
* rebound; FIX if anything is only healable; else PASS.
|
|
73
95
|
*/
|
|
74
96
|
export function diffMappings(before: any, after: any): {
|
|
75
97
|
verdict: string;
|
|
@@ -80,6 +102,7 @@ export function diffMappings(before: any, after: any): {
|
|
|
80
102
|
healable: any;
|
|
81
103
|
ambiguous: any;
|
|
82
104
|
lost: any;
|
|
105
|
+
rebound: any;
|
|
83
106
|
added: any;
|
|
84
107
|
};
|
|
85
108
|
rows: any;
|
package/dist/browser/match.js
CHANGED
|
@@ -14,6 +14,7 @@ exports.normalize = normalize;
|
|
|
14
14
|
exports.diceSimilarity = diceSimilarity;
|
|
15
15
|
exports.matchElement = matchElement;
|
|
16
16
|
exports.heuristicMatch = heuristicMatch;
|
|
17
|
+
exports.isIdentitySelector = isIdentitySelector;
|
|
17
18
|
exports.diffMappings = diffMappings;
|
|
18
19
|
function normalize(s) {
|
|
19
20
|
return (s == null ? '' : String(s)).toLowerCase().trim().replace(/\s+/g, ' ');
|
|
@@ -106,62 +107,138 @@ function heuristicMatch(target, candidates) {
|
|
|
106
107
|
const match = matchElement(target, candidates);
|
|
107
108
|
return match && match.matched ? match.selector : null;
|
|
108
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Does this selector still designate the *same* element after the DOM around it
|
|
112
|
+
* changes? Only the attribute-anchored shapes of `stableSelector`'s cascade do:
|
|
113
|
+
* `[data-testid="…"]`, `tag#id`, `tag[name="…"]`.
|
|
114
|
+
*
|
|
115
|
+
* Everything else is a structural path, and a structural path is *positional*:
|
|
116
|
+
* insert one sibling above the element and the very same selector string now
|
|
117
|
+
* resolves to its neighbour. "It still resolves" is therefore evidence about a
|
|
118
|
+
* position, never about identity — treating it as identity is how a diff comes to
|
|
119
|
+
* report a rebind as a harmless relabel.
|
|
120
|
+
*/
|
|
121
|
+
function isIdentitySelector(selector) {
|
|
122
|
+
const s = (selector == null ? '' : String(selector)).trim();
|
|
123
|
+
if (/^\[data-test-?id="[^"]*"\]$/.test(s))
|
|
124
|
+
return true;
|
|
125
|
+
if (/^[a-z][a-z0-9-]*#[^\s>]+$/i.test(s))
|
|
126
|
+
return true;
|
|
127
|
+
if (/^[a-z][a-z0-9-]*\[name="[^"]*"\]$/i.test(s))
|
|
128
|
+
return true;
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
109
131
|
/**
|
|
110
132
|
* Diff a baseline mapping against a current one and produce a CI-style verdict.
|
|
111
133
|
*
|
|
134
|
+
* Identity comes from the contract (role + accessible name), never from the
|
|
135
|
+
* selector string: see `isIdentitySelector`. A selector that still resolves only
|
|
136
|
+
* proves the *position* is still occupied — possibly by a different element.
|
|
137
|
+
*
|
|
112
138
|
* Per baseline element:
|
|
113
139
|
* - `ok` — selector still resolves and the accessible name is unchanged
|
|
114
|
-
* - `renamed` —
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* - `
|
|
140
|
+
* - `renamed` — the same element is still there, wearing a new label. Only
|
|
141
|
+
* claimed when the selector is identity-bearing, or when no other
|
|
142
|
+
* baseline element accounts for what now sits at that selector.
|
|
143
|
+
* The test still passes and clicks the right thing: content drift
|
|
144
|
+
* (i18n / copy) a human should eyeball, not a structural break.
|
|
145
|
+
* - `healable` — role + name (+ context) still identify exactly one element at a
|
|
146
|
+
* different selector → deterministic old→new rewrite
|
|
147
|
+
* - `ambiguous` — several elements match equally; healing would be a guess, so we
|
|
148
|
+
* refuse and hand it to a human
|
|
149
|
+
* - `lost` — nothing matches: the element is gone
|
|
150
|
+
* - `added` — element present now, accounted for by no baseline element
|
|
151
|
+
*
|
|
152
|
+
* Any row may carry `rebound: true`: the old selector still resolves, but onto a
|
|
153
|
+
* *different* element (`reboundTo`). That is the silent-failure case this tool
|
|
154
|
+
* exists to catch — the test is green today while clicking the wrong element — so
|
|
155
|
+
* it BLOCKs rather than merely asking for a fix: a FIX verdict exits 0 by default,
|
|
156
|
+
* which would let exactly this ship.
|
|
124
157
|
*
|
|
125
|
-
* Verdict (drives the CI exit code): BLOCK if anything is lost or
|
|
126
|
-
* FIX if anything is only healable
|
|
127
|
-
* the test still runs — but is surfaced for review).
|
|
158
|
+
* Verdict (drives the CI exit code): BLOCK if anything is lost, ambiguous or
|
|
159
|
+
* rebound; FIX if anything is only healable; else PASS.
|
|
128
160
|
*/
|
|
129
161
|
function diffMappings(before, after) {
|
|
130
162
|
const beforeElements = (before && before.elements) || [];
|
|
131
163
|
const afterElements = (after && after.elements) || [];
|
|
132
164
|
const afterBySelector = new Map(afterElements.map((e) => [e.selector, e]));
|
|
133
|
-
const
|
|
134
|
-
const
|
|
165
|
+
const semanticCache = new Map();
|
|
166
|
+
const semanticFor = (i) => {
|
|
167
|
+
if (!semanticCache.has(i))
|
|
168
|
+
semanticCache.set(i, matchElement(beforeElements[i], afterElements));
|
|
169
|
+
return semanticCache.get(i);
|
|
170
|
+
};
|
|
171
|
+
// Which baseline element claims the element now sitting at a given selector?
|
|
172
|
+
// Built on demand: it only arbitrates the "positional selector resolves to a
|
|
173
|
+
// different name" case — was our element relabelled, or did the selector slide
|
|
174
|
+
// onto a neighbour that another baseline element already answers for?
|
|
175
|
+
let claims = null;
|
|
176
|
+
const claimant = (selector) => {
|
|
177
|
+
if (!claims) {
|
|
178
|
+
claims = new Map();
|
|
179
|
+
for (let i = 0; i < beforeElements.length; i++) {
|
|
180
|
+
const m = semanticFor(i);
|
|
181
|
+
if (m && m.matched && !claims.has(m.selector))
|
|
182
|
+
claims.set(m.selector, i);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return claims.get(selector);
|
|
186
|
+
};
|
|
187
|
+
const healable = (el, match, extra) => ({
|
|
188
|
+
status: 'healable',
|
|
189
|
+
role: el.role,
|
|
190
|
+
name: el.name,
|
|
191
|
+
selector: el.selector,
|
|
192
|
+
context: el.context,
|
|
193
|
+
healedSelector: match.selector,
|
|
194
|
+
healedName: match.name,
|
|
195
|
+
score: match.score,
|
|
196
|
+
matchType: match.matchType,
|
|
197
|
+
disambiguatedBy: match.disambiguatedBy,
|
|
198
|
+
...extra,
|
|
199
|
+
});
|
|
200
|
+
const rows = beforeElements.map((el, i) => {
|
|
135
201
|
const still = afterBySelector.get(el.selector);
|
|
202
|
+
if (still && normalize(still.name) === normalize(el.name)) {
|
|
203
|
+
return { status: 'ok', role: el.role, name: el.name, selector: el.selector, context: el.context };
|
|
204
|
+
}
|
|
205
|
+
const match = semanticFor(i);
|
|
136
206
|
if (still) {
|
|
137
|
-
|
|
138
|
-
|
|
207
|
+
// The selector resolves, but onto a different name. Relabelled, or rebound?
|
|
208
|
+
if (isIdentitySelector(el.selector)) {
|
|
209
|
+
return { status: 'renamed', role: el.role, name: el.name, selector: el.selector, context: el.context, newName: still.name };
|
|
139
210
|
}
|
|
211
|
+
const rebound = { rebound: true, reboundTo: still.name };
|
|
212
|
+
if (match && match.matched)
|
|
213
|
+
return healable(el, match, rebound);
|
|
214
|
+
if (match && match.ambiguous) {
|
|
215
|
+
return { status: 'ambiguous', role: el.role, name: el.name, selector: el.selector, context: el.context, candidateCount: match.count, ...rebound };
|
|
216
|
+
}
|
|
217
|
+
if (claimant(el.selector) !== undefined) {
|
|
218
|
+
return { status: 'lost', role: el.role, name: el.name, selector: el.selector, context: el.context, ...rebound };
|
|
219
|
+
}
|
|
220
|
+
// Nothing else answers for what sits here, and our element is nowhere else:
|
|
221
|
+
// the plain reading is that it was relabelled in place.
|
|
140
222
|
return { status: 'renamed', role: el.role, name: el.name, selector: el.selector, context: el.context, newName: still.name };
|
|
141
223
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
status: 'healable',
|
|
146
|
-
role: el.role,
|
|
147
|
-
name: el.name,
|
|
148
|
-
selector: el.selector,
|
|
149
|
-
context: el.context,
|
|
150
|
-
healedSelector: match.selector,
|
|
151
|
-
healedName: match.name,
|
|
152
|
-
score: match.score,
|
|
153
|
-
matchType: match.matchType,
|
|
154
|
-
disambiguatedBy: match.disambiguatedBy,
|
|
155
|
-
};
|
|
156
|
-
}
|
|
224
|
+
if (match && match.matched)
|
|
225
|
+
return healable(el, match);
|
|
157
226
|
if (match && match.ambiguous) {
|
|
158
227
|
return { status: 'ambiguous', role: el.role, name: el.name, selector: el.selector, context: el.context, candidateCount: match.count };
|
|
159
228
|
}
|
|
160
229
|
return { status: 'lost', role: el.role, name: el.name, selector: el.selector, context: el.context };
|
|
161
230
|
});
|
|
162
|
-
|
|
231
|
+
// An element is new when no baseline row accounts for it — by selector string
|
|
232
|
+
// for the ones that stayed put, by heal target for the ones that moved.
|
|
233
|
+
const accounted = new Set();
|
|
234
|
+
for (const r of rows) {
|
|
235
|
+
if (r.status === 'ok' || r.status === 'renamed')
|
|
236
|
+
accounted.add(r.selector);
|
|
237
|
+
else if (r.status === 'healable')
|
|
238
|
+
accounted.add(r.healedSelector);
|
|
239
|
+
}
|
|
163
240
|
const added = afterElements
|
|
164
|
-
.filter((el) => !
|
|
241
|
+
.filter((el) => !accounted.has(el.selector))
|
|
165
242
|
.map((el) => ({ status: 'added', role: el.role, name: el.name, selector: el.selector, context: el.context }));
|
|
166
243
|
const count = (s) => rows.filter((r) => r.status === s).length;
|
|
167
244
|
const counts = {
|
|
@@ -171,9 +248,14 @@ function diffMappings(before, after) {
|
|
|
171
248
|
healable: count('healable'),
|
|
172
249
|
ambiguous: count('ambiguous'),
|
|
173
250
|
lost: count('lost'),
|
|
251
|
+
rebound: rows.filter((r) => r.rebound).length,
|
|
174
252
|
added: added.length,
|
|
175
253
|
};
|
|
176
|
-
const verdict = counts.lost > 0 || counts.ambiguous > 0
|
|
254
|
+
const verdict = counts.lost > 0 || counts.ambiguous > 0 || counts.rebound > 0
|
|
255
|
+
? 'BLOCK'
|
|
256
|
+
: counts.healable > 0
|
|
257
|
+
? 'FIX'
|
|
258
|
+
: 'PASS';
|
|
177
259
|
return { verdict, counts, rows, added };
|
|
178
260
|
}
|
|
179
261
|
//# sourceMappingURL=match.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/browser/match.js"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAEH,8BAEC;AAGD,wCAmBC;AAeD,oCA2BC;AAoBD,wCAGC;
|
|
1
|
+
{"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/browser/match.js"],"names":[],"mappings":"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"}
|
package/dist/cli/diff.js
CHANGED
|
@@ -98,7 +98,7 @@ function printHuman(report, files) {
|
|
|
98
98
|
console.log(`\n${icon} ${verdict}`);
|
|
99
99
|
console.log(` ${path.basename(files[0])} → ${path.basename(files[1])} · ` +
|
|
100
100
|
`${counts.ok} ok · ${counts.renamed} renamed · ${counts.healable} healable · ` +
|
|
101
|
-
`${counts.ambiguous} ambiguous · ${counts.lost} lost · ${counts.added} new\n`);
|
|
101
|
+
`${counts.ambiguous} ambiguous · ${counts.lost} lost · ${counts.rebound} rebound · ${counts.added} new\n`);
|
|
102
102
|
const drift = rows.filter((r) => r.status !== 'ok');
|
|
103
103
|
for (const r of drift) {
|
|
104
104
|
if (r.status === 'healable') {
|
|
@@ -115,11 +115,18 @@ function printHuman(report, files) {
|
|
|
115
115
|
else {
|
|
116
116
|
console.log(` ⛔ lost ${label(r)}\n ${r.selector} → (no match)`);
|
|
117
117
|
}
|
|
118
|
+
if (r.rebound) {
|
|
119
|
+
console.log(` ⚠️ that selector now resolves to ${r.role} "${r.reboundTo}" — the test is green today and clicking the wrong element.`);
|
|
120
|
+
}
|
|
118
121
|
}
|
|
119
122
|
for (const r of added) {
|
|
120
123
|
console.log(` ➕ new ${label(r)}\n ${r.selector}`);
|
|
121
124
|
}
|
|
122
125
|
console.log('');
|
|
126
|
+
if (counts.rebound > 0) {
|
|
127
|
+
console.log(' ⚠️ Rebound selectors still resolve — onto a different element. Your suite passes while clicking the wrong');
|
|
128
|
+
console.log(' thing, which no test failure will tell you about. Positional selectors cause this; a data-testid prevents it.');
|
|
129
|
+
}
|
|
123
130
|
if (counts.lost > 0) {
|
|
124
131
|
console.log(' ⛔ Lost selectors have no match — self-healing cannot recover them; a human must fix or delete the test.');
|
|
125
132
|
}
|
package/dist/cli/diff.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/cli/diff.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,0BAsBC;AAvCD,uCAAyB;AACzB,2CAA6B;AAE7B,4CAAgD;AAEhD;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,OAAO,CAAC,IAAc;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAEtD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;QAC3F,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,IAAA,oBAAY,EAAC,QAAQ,EAAE,OAAO,CAAW,CAAC;IAEzD,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC;IACnF,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,kBAAkB,IAAI,IAAI,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,MAAmB,CAAC;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;IAC1C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,wBAAwB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,mDAAmD,CAAC,CAAC;QAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/cli/diff.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/fix.js
CHANGED
|
@@ -56,10 +56,11 @@ const fixEngine_1 = require("../fixEngine");
|
|
|
56
56
|
*/
|
|
57
57
|
async function runFix(args) {
|
|
58
58
|
const dryRun = args.includes('--dry-run');
|
|
59
|
+
const useLocators = args.includes('--locators');
|
|
59
60
|
const rest = args.filter((a) => !a.startsWith('--'));
|
|
60
61
|
const [beforeFile, afterFile, ...testPaths] = rest;
|
|
61
62
|
if (!beforeFile || !afterFile || testPaths.length === 0) {
|
|
62
|
-
console.error('Usage: ia-qa-heal fix <before.json> <after.json> <test-file-or-dir…> [--dry-run]');
|
|
63
|
+
console.error('Usage: ia-qa-heal fix <before.json> <after.json> <test-file-or-dir…> [--locators] [--dry-run]');
|
|
63
64
|
process.exitCode = 2;
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
@@ -67,6 +68,9 @@ async function runFix(args) {
|
|
|
67
68
|
const after = readMapping(afterFile);
|
|
68
69
|
const report = (0, match_1.diffMappings)(before, after);
|
|
69
70
|
const rewrites = (0, fixEngine_1.computeRewrites)(report.rows);
|
|
71
|
+
const locators = useLocators
|
|
72
|
+
? (0, fixEngine_1.computeLocatorRewrites)(report.rows, after.elements)
|
|
73
|
+
: undefined;
|
|
70
74
|
const files = (0, fixEngine_1.collectFiles)(testPaths, (p) => console.error(`⚠ Skipping "${p}" — not found.`));
|
|
71
75
|
if (files.length === 0) {
|
|
72
76
|
console.error(`No test files found under: ${testPaths.join(', ')}`);
|
|
@@ -74,8 +78,10 @@ async function runFix(args) {
|
|
|
74
78
|
return;
|
|
75
79
|
}
|
|
76
80
|
console.log(`\n🔧 ia-qa-heal fix — deterministic selector rewrite${dryRun ? ' (dry run)' : ''}`);
|
|
77
|
-
console.log(` ${rewrites.size} healable rewrite${rewrites.size === 1 ? '' : 's'} · ${files.length} file${files.length === 1 ? '' : 's'} scanned
|
|
78
|
-
|
|
81
|
+
console.log(` ${rewrites.size} healable rewrite${rewrites.size === 1 ? '' : 's'} · ${files.length} file${files.length === 1 ? '' : 's'} scanned` +
|
|
82
|
+
(locators ? ` · ${locators.size} expressible as getByRole locators` : '') +
|
|
83
|
+
'\n');
|
|
84
|
+
const result = (0, fixEngine_1.applyRewrites)(files, rewrites, dryRun, locators);
|
|
79
85
|
if (rewrites.size === 0) {
|
|
80
86
|
console.log(' No healable rewrites in this diff — nothing to apply.');
|
|
81
87
|
}
|
|
@@ -89,6 +95,8 @@ async function runFix(args) {
|
|
|
89
95
|
console.log(` ${r.count}× ${r.from} → ${r.to}`);
|
|
90
96
|
}
|
|
91
97
|
}
|
|
98
|
+
printRebound(report);
|
|
99
|
+
printStillPositional(report, locators);
|
|
92
100
|
printNeedsHuman(report);
|
|
93
101
|
console.log(`\n ${dryRun ? 'Would apply' : 'Applied'} ${result.totalReplacements} replacement${result.totalReplacements === 1 ? '' : 's'} in ${result.edits.length} file${result.edits.length === 1 ? '' : 's'}.` +
|
|
94
102
|
(dryRun ? ' (dry run — nothing written.)' : ''));
|
|
@@ -100,6 +108,37 @@ async function runFix(args) {
|
|
|
100
108
|
}
|
|
101
109
|
process.exitCode = 0;
|
|
102
110
|
}
|
|
111
|
+
function printRebound(report) {
|
|
112
|
+
const rebound = report.rows.filter((r) => r.rebound);
|
|
113
|
+
if (rebound.length === 0)
|
|
114
|
+
return;
|
|
115
|
+
console.log('\n ⚠️ Was silently wrong before this fix:');
|
|
116
|
+
for (const r of rebound) {
|
|
117
|
+
console.log(` ${r.selector} still resolved — onto ${r.role} "${r.reboundTo}", not ${r.role} "${r.name || '(no name)'}".`);
|
|
118
|
+
}
|
|
119
|
+
console.log(' Those tests passed while clicking the wrong element. Check what they asserted since the drift landed.');
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* A rewritten positional selector is correct today and fragile tomorrow: the next
|
|
123
|
+
* insertion above it slides it onto a neighbour again. Say so, and point at the
|
|
124
|
+
* way out — silence here would just reproduce the drift on a schedule.
|
|
125
|
+
*/
|
|
126
|
+
function printStillPositional(report, locators) {
|
|
127
|
+
const healable = report.rows.filter((r) => r.status === 'healable' && r.healedSelector);
|
|
128
|
+
const positional = healable.filter((r) => !(0, match_1.isIdentitySelector)(r.healedSelector) && !locators?.has(r.selector));
|
|
129
|
+
if (positional.length === 0)
|
|
130
|
+
return;
|
|
131
|
+
if (locators) {
|
|
132
|
+
console.log(`\n ℹ️ ${positional.length} rewrite${positional.length === 1 ? '' : 's'} stayed positional — no unambiguous role + name to anchor on:`);
|
|
133
|
+
for (const r of positional) {
|
|
134
|
+
console.log(` ${r.role} "${r.name || '(no name)'}" · ${r.healedSelector}`);
|
|
135
|
+
}
|
|
136
|
+
console.log(' A data-testid on those elements is the durable fix.');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
console.log(`\n ℹ️ ${positional.length} rewrite${positional.length === 1 ? '' : 's'} point at positional selectors, which the next inserted element will shift again.`);
|
|
140
|
+
console.log(' Re-run with --locators to emit getByRole(role, { name }) instead (Playwright, .js/.ts files).');
|
|
141
|
+
}
|
|
103
142
|
function printNeedsHuman(report) {
|
|
104
143
|
const flagged = report.rows.filter((r) => r.status === 'lost' || r.status === 'ambiguous' || r.status === 'renamed');
|
|
105
144
|
if (flagged.length === 0)
|
package/dist/cli/fix.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix.js","sourceRoot":"","sources":["../../src/cli/fix.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBA,
|
|
1
|
+
{"version":3,"file":"fix.js","sourceRoot":"","sources":["../../src/cli/fix.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/index.js
CHANGED
|
@@ -13,7 +13,9 @@ Usage:
|
|
|
13
13
|
ia-qa-heal diff <before> <after> Diff two mappings → PASS/FIX/BLOCK verdict (CI gate)
|
|
14
14
|
--strict fail on FIX too --json machine-readable output
|
|
15
15
|
ia-qa-heal fix <before> <after> <tests…> Apply the deterministic healable rewrites to your test files
|
|
16
|
-
--dry-run
|
|
16
|
+
--dry-run show the plan without writing. Never commits.
|
|
17
|
+
--locators emit getByRole(role, { name }) instead of selectors
|
|
18
|
+
(Playwright, .js/.ts) — immune to positional drift
|
|
17
19
|
ia-qa-heal help Show this help
|
|
18
20
|
`;
|
|
19
21
|
async function main() {
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AACA,iCAAiC;AACjC,+BAA+B;AAC/B,iCAAiC;AACjC,+BAA+B;AAE/B,MAAM,IAAI,GAAG
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AACA,iCAAiC;AACjC,+BAA+B;AAC/B,iCAAiC;AACjC,+BAA+B;AAE/B,MAAM,IAAI,GAAG;;;;;;;;;;;;CAYZ,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,EAAE,AAAD,EAAG,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,MAAM,IAAA,cAAO,GAAE,CAAC;YAChB,MAAM;QACR,KAAK,KAAK;YACR,MAAM,IAAA,YAAM,EAAC,GAAG,CAAC,CAAC;YAClB,MAAM;QACR,KAAK,MAAM;YACT,MAAM,IAAA,cAAO,EAAC,IAAI,CAAC,CAAC;YACpB,MAAM;QACR,KAAK,KAAK;YACR,MAAM,IAAA,YAAM,EAAC,IAAI,CAAC,CAAC;YACnB,MAAM;QACR,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI,CAAC;QACV,KAAK,SAAS;YACZ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,SAAS,IAAI,EAAE,CAAC,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -91,7 +91,18 @@ async function resolveSecret(ref) {
|
|
|
91
91
|
return value;
|
|
92
92
|
}
|
|
93
93
|
if (ref.source === 'aws-ssm') {
|
|
94
|
-
|
|
94
|
+
// Ships separately: the AWS SDK is ~5 MB and only the "aws-ssm" source needs
|
|
95
|
+
// it, so it is an optional peer rather than a tax on every install.
|
|
96
|
+
let ssm;
|
|
97
|
+
try {
|
|
98
|
+
ssm = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-ssm')));
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
throw new Error('The "aws-ssm" secret source needs the AWS SDK, which is not bundled to keep this package small.\n' +
|
|
102
|
+
' Install it in your project: npm i @aws-sdk/client-ssm\n' +
|
|
103
|
+
' Or switch this key to the "env" source in .ia-qa/config.json.');
|
|
104
|
+
}
|
|
105
|
+
const { SSMClient, GetParameterCommand } = ssm;
|
|
95
106
|
const client = new SSMClient(ref.region ? { region: ref.region } : {});
|
|
96
107
|
try {
|
|
97
108
|
const out = await client.send(new GetParameterCommand({ Name: ref.key, WithDecryption: true }));
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,gCAEC;AAED,gCAEC;AAED,kCAGC;AAED,gCAYC;AAED,gCAMC;AASD,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/fixEngine.d.ts
CHANGED
|
@@ -8,7 +8,32 @@ export interface DiffRowLike {
|
|
|
8
8
|
status: string;
|
|
9
9
|
selector?: string;
|
|
10
10
|
healedSelector?: string;
|
|
11
|
+
role?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
healedName?: string;
|
|
11
14
|
}
|
|
15
|
+
export interface LocatorTarget {
|
|
16
|
+
role: string;
|
|
17
|
+
name: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Which healable rewrites can be expressed as role + accessible name instead of a
|
|
21
|
+
* selector?
|
|
22
|
+
*
|
|
23
|
+
* A rewritten positional selector is still positional: it survives exactly until
|
|
24
|
+
* the next insertion. The contract already identifies elements by role + name, so
|
|
25
|
+
* where the test framework can express that directly, emitting it retires the
|
|
26
|
+
* whole class of drift rather than patching one instance of it.
|
|
27
|
+
*
|
|
28
|
+
* Only when it is provably safe: `getByRole` is strict, so the role + name must
|
|
29
|
+
* hit exactly one element in the *current* mapping, or the locator would throw on
|
|
30
|
+
* an ambiguous match. Anything that fails these tests keeps its selector rewrite.
|
|
31
|
+
*/
|
|
32
|
+
export declare function computeLocatorRewrites(rows: DiffRowLike[], afterElements: Array<{
|
|
33
|
+
role: string;
|
|
34
|
+
name: string;
|
|
35
|
+
}>): Map<string, LocatorTarget>;
|
|
36
|
+
export declare function locatorExpression(t: LocatorTarget): string;
|
|
12
37
|
export interface FileEdit {
|
|
13
38
|
file: string;
|
|
14
39
|
replacements: Array<{
|
|
@@ -29,12 +54,25 @@ export interface FixResult {
|
|
|
29
54
|
}
|
|
30
55
|
/** Map of old→new selector, taken ONLY from the healable rows. */
|
|
31
56
|
export declare function computeRewrites(rows: DiffRowLike[]): Map<string, string>;
|
|
57
|
+
/**
|
|
58
|
+
* Apply every rewrite to `text` in ONE pass.
|
|
59
|
+
*
|
|
60
|
+
* Applying them one after another would be wrong: the drift that shifts selectors
|
|
61
|
+
* usually *permutes* them (insert a row and `nth-of-type(1)→(2)`, `(2)→(3)`), so a
|
|
62
|
+
* second rewrite would land on the first one's output and turn `(1)` into `(3)`.
|
|
63
|
+
* We scan the source once and never re-examine what we emit, so each occurrence is
|
|
64
|
+
* rewritten exactly once, against the selector it had in the file.
|
|
65
|
+
*/
|
|
66
|
+
export declare function applyRewritesToText(text: string, rewrites: Map<string, string>, locators?: Map<string, LocatorTarget>): {
|
|
67
|
+
text: string;
|
|
68
|
+
replacements: FileEdit['replacements'];
|
|
69
|
+
};
|
|
32
70
|
/**
|
|
33
71
|
* Apply `rewrites` to every file in `files`. Replaces a selector only where it
|
|
34
72
|
* appears as a quoted string literal (`'…'`/`"…"`/`` `…` ``), quote-safe for
|
|
35
73
|
* attribute selectors. When `dryRun` is true, computes counts without writing.
|
|
36
74
|
*/
|
|
37
|
-
export declare function applyRewrites(files: string[], rewrites: Map<string, string>, dryRun: boolean): FixResult;
|
|
75
|
+
export declare function applyRewrites(files: string[], rewrites: Map<string, string>, dryRun: boolean, locators?: Map<string, LocatorTarget>): FixResult;
|
|
38
76
|
/**
|
|
39
77
|
* Replace `oldSel` with `newSel` only inside a matching pair of quotes.
|
|
40
78
|
* Quote-safe: if the source wraps the old selector in the same quote the new
|
package/dist/fixEngine.js
CHANGED
|
@@ -33,12 +33,62 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.computeLocatorRewrites = computeLocatorRewrites;
|
|
37
|
+
exports.locatorExpression = locatorExpression;
|
|
36
38
|
exports.computeRewrites = computeRewrites;
|
|
39
|
+
exports.applyRewritesToText = applyRewritesToText;
|
|
37
40
|
exports.applyRewrites = applyRewrites;
|
|
38
41
|
exports.replaceQuoted = replaceQuoted;
|
|
39
42
|
exports.collectFiles = collectFiles;
|
|
40
43
|
const fs = __importStar(require("fs"));
|
|
41
44
|
const path = __importStar(require("path"));
|
|
45
|
+
/** Roles `getByRole` can actually target — `extractInPage` also emits `generic`. */
|
|
46
|
+
const LOCATABLE_ROLES = new Set([
|
|
47
|
+
'button', 'link', 'textbox', 'checkbox', 'radio', 'combobox', 'tab', 'menuitem', 'slider',
|
|
48
|
+
]);
|
|
49
|
+
/** `accessibleName()` truncates at 120 chars, and a truncated name matches nothing. */
|
|
50
|
+
const NAME_MAX = 120;
|
|
51
|
+
const norm = (s) => (s == null ? '' : String(s)).toLowerCase().trim().replace(/\s+/g, ' ');
|
|
52
|
+
/**
|
|
53
|
+
* Which healable rewrites can be expressed as role + accessible name instead of a
|
|
54
|
+
* selector?
|
|
55
|
+
*
|
|
56
|
+
* A rewritten positional selector is still positional: it survives exactly until
|
|
57
|
+
* the next insertion. The contract already identifies elements by role + name, so
|
|
58
|
+
* where the test framework can express that directly, emitting it retires the
|
|
59
|
+
* whole class of drift rather than patching one instance of it.
|
|
60
|
+
*
|
|
61
|
+
* Only when it is provably safe: `getByRole` is strict, so the role + name must
|
|
62
|
+
* hit exactly one element in the *current* mapping, or the locator would throw on
|
|
63
|
+
* an ambiguous match. Anything that fails these tests keeps its selector rewrite.
|
|
64
|
+
*/
|
|
65
|
+
function computeLocatorRewrites(rows, afterElements) {
|
|
66
|
+
const out = new Map();
|
|
67
|
+
for (const r of rows) {
|
|
68
|
+
if (r.status !== 'healable' || !r.selector || !r.healedSelector)
|
|
69
|
+
continue;
|
|
70
|
+
const role = r.role;
|
|
71
|
+
const name = r.healedName || r.name;
|
|
72
|
+
if (!role || !LOCATABLE_ROLES.has(role))
|
|
73
|
+
continue;
|
|
74
|
+
if (!name || name.length >= NAME_MAX)
|
|
75
|
+
continue;
|
|
76
|
+
const hits = afterElements.filter((e) => e.role === role && norm(e.name) === norm(name));
|
|
77
|
+
if (hits.length !== 1)
|
|
78
|
+
continue;
|
|
79
|
+
out.set(r.selector, { role, name });
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
function locatorExpression(t) {
|
|
84
|
+
return `getByRole('${t.role}', { name: ${JSON.stringify(t.name)} })`;
|
|
85
|
+
}
|
|
86
|
+
/** Playwright shorthands that take a selector as their first argument. */
|
|
87
|
+
const PW_ACTIONS = [
|
|
88
|
+
'click', 'dblclick', 'fill', 'check', 'uncheck', 'hover', 'focus',
|
|
89
|
+
'press', 'type', 'selectOption', 'tap', 'clear', 'setInputFiles', 'textContent', 'inputValue', 'isVisible', 'isChecked', 'isEnabled', 'getAttribute', 'waitForSelector',
|
|
90
|
+
];
|
|
91
|
+
const JS_EXT = new Set(['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs']);
|
|
42
92
|
/** Map of old→new selector, taken ONLY from the healable rows. */
|
|
43
93
|
function computeRewrites(rows) {
|
|
44
94
|
const rewrites = new Map();
|
|
@@ -49,31 +99,93 @@ function computeRewrites(rows) {
|
|
|
49
99
|
}
|
|
50
100
|
return rewrites;
|
|
51
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Apply every rewrite to `text` in ONE pass.
|
|
104
|
+
*
|
|
105
|
+
* Applying them one after another would be wrong: the drift that shifts selectors
|
|
106
|
+
* usually *permutes* them (insert a row and `nth-of-type(1)→(2)`, `(2)→(3)`), so a
|
|
107
|
+
* second rewrite would land on the first one's output and turn `(1)` into `(3)`.
|
|
108
|
+
* We scan the source once and never re-examine what we emit, so each occurrence is
|
|
109
|
+
* rewritten exactly once, against the selector it had in the file.
|
|
110
|
+
*/
|
|
111
|
+
function applyRewritesToText(text, rewrites, locators) {
|
|
112
|
+
const pairs = [];
|
|
113
|
+
const variants = [];
|
|
114
|
+
// Locator needles swallow the whole call, so they are matched at the `.` — which
|
|
115
|
+
// the scan reaches before the quote the selector needle would match at. Earlier
|
|
116
|
+
// index wins, so an upgradable call becomes a locator and every other occurrence
|
|
117
|
+
// of the selector still gets its plain rewrite.
|
|
118
|
+
if (locators) {
|
|
119
|
+
for (const [from, target] of locators) {
|
|
120
|
+
const expr = locatorExpression(target);
|
|
121
|
+
const pair = pairs.push({ from, to: expr }) - 1;
|
|
122
|
+
for (const q of QUOTES) {
|
|
123
|
+
const lit = q + from + q;
|
|
124
|
+
variants.push({ needle: `.locator(${lit})`, replacement: `.${expr}`, pair });
|
|
125
|
+
for (const a of PW_ACTIONS) {
|
|
126
|
+
variants.push({ needle: `.${a}(${lit})`, replacement: `.${expr}.${a}()`, pair });
|
|
127
|
+
variants.push({ needle: `.${a}(${lit}, `, replacement: `.${expr}.${a}(`, pair });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const [from, to] of rewrites) {
|
|
133
|
+
const pair = pairs.push({ from, to }) - 1;
|
|
134
|
+
for (const q of QUOTES) {
|
|
135
|
+
const wrap = to.indexOf(q) === -1 ? q : QUOTES.find((c) => to.indexOf(c) === -1);
|
|
136
|
+
if (!wrap)
|
|
137
|
+
continue;
|
|
138
|
+
variants.push({ needle: q + from + q, replacement: wrap + to + wrap, pair });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Longest needle first: a selector that is a prefix of another must not win.
|
|
142
|
+
variants.sort((a, b) => b.needle.length - a.needle.length);
|
|
143
|
+
const counts = new Map();
|
|
144
|
+
let out = '';
|
|
145
|
+
let i = 0;
|
|
146
|
+
while (i < text.length) {
|
|
147
|
+
// Needles start with a quote (selector) or a dot (locator call) — nothing else
|
|
148
|
+
// is worth probing.
|
|
149
|
+
if (QUOTES.indexOf(text[i]) !== -1 || text[i] === '.') {
|
|
150
|
+
const hit = variants.find((v) => text.startsWith(v.needle, i));
|
|
151
|
+
if (hit) {
|
|
152
|
+
out += hit.replacement;
|
|
153
|
+
i += hit.needle.length;
|
|
154
|
+
const key = hit.pair;
|
|
155
|
+
counts.set(key, (counts.get(key) || 0) + 1);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
out += text[i];
|
|
160
|
+
i++;
|
|
161
|
+
}
|
|
162
|
+
const replacements = Array.from(counts, ([key, count]) => {
|
|
163
|
+
const { from, to } = pairs[key];
|
|
164
|
+
return { from, to, count };
|
|
165
|
+
});
|
|
166
|
+
return { text: out, replacements };
|
|
167
|
+
}
|
|
52
168
|
/**
|
|
53
169
|
* Apply `rewrites` to every file in `files`. Replaces a selector only where it
|
|
54
170
|
* appears as a quoted string literal (`'…'`/`"…"`/`` `…` ``), quote-safe for
|
|
55
171
|
* attribute selectors. When `dryRun` is true, computes counts without writing.
|
|
56
172
|
*/
|
|
57
|
-
function applyRewrites(files, rewrites, dryRun) {
|
|
173
|
+
function applyRewrites(files, rewrites, dryRun, locators) {
|
|
58
174
|
const edits = [];
|
|
59
175
|
let totalReplacements = 0;
|
|
60
176
|
if (rewrites.size > 0) {
|
|
61
177
|
for (const file of files) {
|
|
62
178
|
const original = fs.readFileSync(file, 'utf8');
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
updated = res.text;
|
|
69
|
-
replacements.push({ from, to, count: res.count });
|
|
70
|
-
totalReplacements += res.count;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
179
|
+
// `getByRole` is Playwright/JS syntax; a .py or .java suite gets the plain
|
|
180
|
+
// selector rewrite, which is why locators are an upgrade and not a rewrite
|
|
181
|
+
// of what `fix` means.
|
|
182
|
+
const useLocators = JS_EXT.has(path.extname(file)) ? locators : undefined;
|
|
183
|
+
const { text: updated, replacements } = applyRewritesToText(original, rewrites, useLocators);
|
|
73
184
|
if (updated !== original) {
|
|
74
185
|
if (!dryRun)
|
|
75
186
|
fs.writeFileSync(file, updated, 'utf8');
|
|
76
187
|
edits.push({ file, replacements });
|
|
188
|
+
totalReplacements += replacements.reduce((s, r) => s + r.count, 0);
|
|
77
189
|
}
|
|
78
190
|
}
|
|
79
191
|
}
|
package/dist/fixEngine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixEngine.js","sourceRoot":"","sources":["../src/fixEngine.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"fixEngine.js","sourceRoot":"","sources":["../src/fixEngine.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -97,6 +97,10 @@ const TOOLS = [
|
|
|
97
97
|
after_json: { type: 'object', description: 'Current mapping inline (alternative to after_path).' },
|
|
98
98
|
test_paths: { type: 'array', items: { type: 'string' }, description: 'Test files or directories to rewrite.' },
|
|
99
99
|
dry_run: { type: 'boolean', description: 'Preview the plan without writing. Default false.' },
|
|
100
|
+
use_locators: {
|
|
101
|
+
type: 'boolean',
|
|
102
|
+
description: "Upgrade rewrites to Playwright role locators — getByRole('button', { name: 'Save' }) — instead of selectors, wherever role + accessible name identifies exactly one element. Applies to .js/.ts files only; everything else keeps the selector rewrite. Immune to positional drift, so the fix does not need redoing at the next insertion. Default false.",
|
|
103
|
+
},
|
|
100
104
|
},
|
|
101
105
|
required: ['test_paths'],
|
|
102
106
|
},
|
|
@@ -145,12 +149,21 @@ async function callTool(name, args) {
|
|
|
145
149
|
}
|
|
146
150
|
const report = (0, match_1.diffMappings)(before, after);
|
|
147
151
|
const rewrites = (0, fixEngine_1.computeRewrites)(report.rows);
|
|
152
|
+
const locators = args?.use_locators
|
|
153
|
+
? (0, fixEngine_1.computeLocatorRewrites)(report.rows, after.elements)
|
|
154
|
+
: undefined;
|
|
148
155
|
const skipped = [];
|
|
149
156
|
const files = (0, fixEngine_1.collectFiles)(args.test_paths, (p) => skipped.push(p));
|
|
150
|
-
const result = (0, fixEngine_1.applyRewrites)(files, rewrites, !!args.dry_run);
|
|
157
|
+
const result = (0, fixEngine_1.applyRewrites)(files, rewrites, !!args.dry_run, locators);
|
|
151
158
|
const flagged = report.rows
|
|
152
159
|
.filter((r) => r.status === 'lost' || r.status === 'ambiguous' || r.status === 'renamed')
|
|
153
160
|
.map((r) => ({ status: r.status, role: r.role, name: r.name, selector: r.selector, newName: r.newName, candidateCount: r.candidateCount }));
|
|
161
|
+
// Rebound rows are rewritten like any other healable one, but they carry news
|
|
162
|
+
// a fix report must not bury: until now that selector resolved to a *different*
|
|
163
|
+
// element, so the suite was passing while clicking the wrong thing.
|
|
164
|
+
const rebound = report.rows
|
|
165
|
+
.filter((r) => r.rebound)
|
|
166
|
+
.map((r) => ({ role: r.role, name: r.name, selector: r.selector, resolved_to: r.reboundTo, healed_to: r.healedSelector }));
|
|
154
167
|
return JSON.stringify({
|
|
155
168
|
verdict: report.verdict,
|
|
156
169
|
counts: report.counts,
|
|
@@ -158,6 +171,7 @@ async function callTool(name, args) {
|
|
|
158
171
|
would_apply: result.totalReplacements,
|
|
159
172
|
edits: result.edits.map((e) => ({ file: (0, mapUrl_1.rel)(e.file), replacements: e.replacements })),
|
|
160
173
|
needs_human: flagged,
|
|
174
|
+
was_silently_wrong: rebound,
|
|
161
175
|
skipped_paths: skipped,
|
|
162
176
|
note: result.dryRun
|
|
163
177
|
? 'Dry run — nothing written.'
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,uCAAyB;AAEzB,sCAAyD;AACzD,4CAAgD;AAChD,0CAAiD;AACjD,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ia-qa/self-healing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Local-first self-healing for UI tests: a local MCP server + CLI that map your app's pages to a role/name/selector contract, diff selector drift (PASS/FIX/BLOCK), and apply deterministic fixes to Cypress/Playwright/Selenium tests. Runs on your machine — nothing leaves it.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"self-healing",
|
|
@@ -42,13 +42,22 @@
|
|
|
42
42
|
"node": ">=18.0.0"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@aws-sdk/client-ssm": "^3.600.0",
|
|
46
|
-
"playwright": "^1.45.0",
|
|
47
45
|
"prompts": "^2.4.2"
|
|
48
46
|
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"@aws-sdk/client-ssm": "^3.0.0",
|
|
49
|
+
"playwright": ">=1.40.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependenciesMeta": {
|
|
52
|
+
"@aws-sdk/client-ssm": {
|
|
53
|
+
"optional": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
49
56
|
"devDependencies": {
|
|
57
|
+
"@aws-sdk/client-ssm": "^3.600.0",
|
|
50
58
|
"@types/node": "^20.14.0",
|
|
51
59
|
"@types/prompts": "^2.4.9",
|
|
60
|
+
"playwright": "^1.45.0",
|
|
52
61
|
"typescript": "^5.5.0"
|
|
53
62
|
}
|
|
54
63
|
}
|