@ia-qa/self-healing 1.5.7 → 1.6.1
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 +80 -6
- package/dist/checks.d.ts +152 -0
- package/dist/checks.js +0 -0
- package/dist/checks.js.map +1 -0
- package/dist/cli/args.js +2 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/audit.d.ts +63 -0
- package/dist/cli/audit.js +328 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/check.d.ts +1 -0
- package/dist/cli/check.js +329 -0
- package/dist/cli/check.js.map +1 -0
- package/dist/cli/diff.d.ts +20 -1
- package/dist/cli/diff.js +106 -9
- package/dist/cli/diff.js.map +1 -1
- package/dist/cli/fix.js +53 -7
- package/dist/cli/fix.js.map +1 -1
- package/dist/cli/index.js +30 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/ingest.js +26 -9
- package/dist/cli/ingest.js.map +1 -1
- package/dist/cli/run.js +11 -3
- package/dist/cli/run.js.map +1 -1
- package/dist/fixEngine.d.ts +41 -2
- package/dist/fixEngine.js +65 -5
- package/dist/fixEngine.js.map +1 -1
- package/dist/htmlReport.js +55 -6
- package/dist/htmlReport.js.map +1 -1
- package/dist/ingest.d.ts +15 -1
- package/dist/ingest.js +0 -0
- package/dist/ingest.js.map +1 -1
- package/dist/mcp/server.js +22 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/nameDrift.d.ts +85 -0
- package/dist/nameDrift.js +177 -0
- package/dist/nameDrift.js.map +1 -0
- package/dist/nameHint.d.ts +51 -0
- package/dist/nameHint.js +0 -0
- package/dist/nameHint.js.map +1 -0
- package/dist/nameLocators.d.ts +103 -0
- package/dist/nameLocators.js +235 -0
- package/dist/nameLocators.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Static inventory of **name-anchored** locators — the other half of `ingest`.
|
|
4
|
+
*
|
|
5
|
+
* `usage.selectors` answers "which CSS selectors does the suite use?". That was
|
|
6
|
+
* only ever half the question: a suite written the modern way does not hold CSS
|
|
7
|
+
* at all. `page.getByRole('button', { name: 'Save' })`, `cy.contains('Save')` and
|
|
8
|
+
* `By.linkText('Save')` are anchored on the **accessible name**, so they survive
|
|
9
|
+
* every selector rewrite this tool can perform and break on the one kind of drift
|
|
10
|
+
* it used to classify as harmless: a rename.
|
|
11
|
+
*
|
|
12
|
+
* Same discipline as `ingest`: quoted literals in known call shapes, no
|
|
13
|
+
* execution, no AST, no network. A name built by concatenation or holding `${…}`
|
|
14
|
+
* is invisible here — and invisible to the rewrite below too, which is why it is
|
|
15
|
+
* skipped rather than guessed at.
|
|
16
|
+
*
|
|
17
|
+
* Framework parity is the point (guardrail: Playwright / Cypress / Selenium must
|
|
18
|
+
* all be first-class). Every shape below carries what the contract needs to check
|
|
19
|
+
* it: a name, and a role when the call states one.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.AUTHORITATIVE_SHAPES = exports.CONTRACT_ROLES = exports.SHAPE_ROLES = exports.normalizeName = void 0;
|
|
23
|
+
exports.judgeable = judgeable;
|
|
24
|
+
exports.quoteLiteral = quoteLiteral;
|
|
25
|
+
exports.scanNameLocators = scanNameLocators;
|
|
26
|
+
exports.candidateRoles = candidateRoles;
|
|
27
|
+
const normalizeName = (s) => (s == null ? '' : String(s)).toLowerCase().trim().replace(/\s+/g, ' ');
|
|
28
|
+
exports.normalizeName = normalizeName;
|
|
29
|
+
/**
|
|
30
|
+
* The roles a name-anchored call can be checked against.
|
|
31
|
+
*
|
|
32
|
+
* `getByLabel` / `getByPlaceholder` do not name a role, but `extractInPage`
|
|
33
|
+
* derives an accessible name from `<label>`, then `placeholder`, then `name` —
|
|
34
|
+
* so both resolve against form-control roles and nothing else.
|
|
35
|
+
*/
|
|
36
|
+
exports.SHAPE_ROLES = {
|
|
37
|
+
'playwright-label': ['textbox', 'combobox', 'checkbox', 'radio', 'slider'],
|
|
38
|
+
'playwright-placeholder': ['textbox', 'combobox'],
|
|
39
|
+
'selenium-linktext': ['link'],
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Every role `extractInPage` can emit — the complete vocabulary of a contract.
|
|
43
|
+
*
|
|
44
|
+
* A locator asking for anything else is asking about a part of the page the
|
|
45
|
+
* mapping never claimed to hold. `getByRole('heading', …)` is the common case:
|
|
46
|
+
* headings are not interactive, so no contract has ever contained one, and
|
|
47
|
+
* "absent from the contract" would mean "absent from the app" only if the two
|
|
48
|
+
* were the same thing. They are not, and a checker that forgets it reports every
|
|
49
|
+
* heading in the suite as broken.
|
|
50
|
+
*/
|
|
51
|
+
exports.CONTRACT_ROLES = new Set([
|
|
52
|
+
'button', 'link', 'textbox', 'combobox', 'checkbox', 'radio', 'menuitem', 'tab', 'slider', 'generic',
|
|
53
|
+
]);
|
|
54
|
+
/**
|
|
55
|
+
* Shapes whose miss is *evidence* that a test targets nothing.
|
|
56
|
+
*
|
|
57
|
+
* The contract maps interactive elements only. `getByText('Terms of service')`
|
|
58
|
+
* may well point at a paragraph the mapping never saw, so its absence proves
|
|
59
|
+
* nothing — reporting it would be a false positive, and one false positive costs
|
|
60
|
+
* more than ten honest "inconclusive". A stated role, a label or a placeholder,
|
|
61
|
+
* on the other hand, can designate something the contract holds — provided the
|
|
62
|
+
* role is one the contract speaks (see `judgeable` below).
|
|
63
|
+
*/
|
|
64
|
+
exports.AUTHORITATIVE_SHAPES = new Set([
|
|
65
|
+
'playwright-role',
|
|
66
|
+
'playwright-label',
|
|
67
|
+
'playwright-placeholder',
|
|
68
|
+
'selenium-linktext',
|
|
69
|
+
]);
|
|
70
|
+
/**
|
|
71
|
+
* Can this occurrence's absence from a contract be read as a finding?
|
|
72
|
+
*
|
|
73
|
+
* Both halves must hold: a shape that names an element the contract enumerates,
|
|
74
|
+
* AND a role the contract can actually contain.
|
|
75
|
+
*/
|
|
76
|
+
function judgeable(site) {
|
|
77
|
+
if (!exports.AUTHORITATIVE_SHAPES.has(site.shape))
|
|
78
|
+
return false;
|
|
79
|
+
const roles = candidateRoles(site);
|
|
80
|
+
return roles !== null && roles.some((r) => exports.CONTRACT_ROLES.has(r));
|
|
81
|
+
}
|
|
82
|
+
const Q = "(['\"`])";
|
|
83
|
+
/** Body of a quoted literal: no unescaped closing quote, no interpolation. */
|
|
84
|
+
const BODY = '((?:(?!\\1)[^\\\\]|\\\\.)*?)';
|
|
85
|
+
/**
|
|
86
|
+
* A literal we can read *and* rewrite. A template hole (`${…}`) makes the runtime
|
|
87
|
+
* value unknowable, and a regex argument (`{ name: /save/i }`) is not a literal at
|
|
88
|
+
* all — both are left to the human rather than guessed at.
|
|
89
|
+
*/
|
|
90
|
+
function literalName(raw) {
|
|
91
|
+
if (raw == null)
|
|
92
|
+
return null;
|
|
93
|
+
if (raw.includes('${'))
|
|
94
|
+
return null;
|
|
95
|
+
return raw.replace(/\\(['"`\\])/g, '$1');
|
|
96
|
+
}
|
|
97
|
+
/** Wrap `name` in a quote it does not contain; escape as a last resort. */
|
|
98
|
+
function quoteLiteral(name) {
|
|
99
|
+
for (const q of ["'", '"', '`']) {
|
|
100
|
+
if (name.indexOf(q) === -1 && !(q === '`' && name.includes('${')))
|
|
101
|
+
return q + name + q;
|
|
102
|
+
}
|
|
103
|
+
return "'" + name.replace(/(['\\])/g, '\\$1') + "'";
|
|
104
|
+
}
|
|
105
|
+
/** Replace the `name: '…'` value inside an already-matched `getByRole(…)` call. */
|
|
106
|
+
function renameRoleCall(call, newName) {
|
|
107
|
+
return call.replace(/(\bname\s*:\s*)(['"`])((?:(?!\2)[^\\]|\\.)*?)\2/, (_m, key) => key + quoteLiteral(newName));
|
|
108
|
+
}
|
|
109
|
+
/** Replace the Nth quoted literal of an already-matched call. */
|
|
110
|
+
function renameNthLiteral(call, newName, nth) {
|
|
111
|
+
let seen = 0;
|
|
112
|
+
return call.replace(/(['"`])((?:(?!\1)[^\\]|\\.)*?)\1/g, (m, _q, _body) => {
|
|
113
|
+
seen++;
|
|
114
|
+
return seen === nth ? quoteLiteral(newName) : m;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Playwright and Testing Library are the same call under two spellings, and a
|
|
119
|
+
* Cypress suite reaches role-anchored locating only through the second
|
|
120
|
+
* (`@testing-library/cypress` → `cy.findByRole`). Matching the whole family
|
|
121
|
+
* rather than Playwright's spelling alone is what keeps the three frameworks at
|
|
122
|
+
* parity here — otherwise a Cypress suite would have no rewritable locator at
|
|
123
|
+
* all, and "parity" would mean "we read your file and did nothing".
|
|
124
|
+
*
|
|
125
|
+
* `getBy` / `findBy` / `queryBy`, with or without `All`.
|
|
126
|
+
*/
|
|
127
|
+
const V = '(?:get|find|query)(?:All)?By';
|
|
128
|
+
/**
|
|
129
|
+
* Every needle starts at the `.` so the single-pass rewriter in `fixEngine` — which
|
|
130
|
+
* only probes at `.` and quote characters — can match it. That covers
|
|
131
|
+
* `page.getByRole`, `screen.findByRole`, `cy.findByRole`, `cy.contains`,
|
|
132
|
+
* `By.linkText` and any chained form. A bare destructured `getByText('…')` (React
|
|
133
|
+
* Testing Library) is inventoried but not rewritten: an accepted, reported miss.
|
|
134
|
+
*/
|
|
135
|
+
const SHAPES = [
|
|
136
|
+
{
|
|
137
|
+
shape: 'playwright-role',
|
|
138
|
+
re: new RegExp(`\\.${V}Role\\(\\s*${Q}([a-z]+)\\1\\s*,\\s*\\{[^{}]*?\\bname\\s*:\\s*(['"\`])((?:(?!\\3)[^\\\\]|\\\\.)*?)\\3[^{}]*\\}\\s*\\)`, 'g'),
|
|
139
|
+
nameGroup: 4,
|
|
140
|
+
roleGroup: 2,
|
|
141
|
+
literalIndex: 2,
|
|
142
|
+
role: true,
|
|
143
|
+
},
|
|
144
|
+
{ shape: 'playwright-label', re: new RegExp(`\\.${V}Label(?:Text)?\\(\\s*${Q}${BODY}\\1`, 'g'), nameGroup: 2, literalIndex: 1 },
|
|
145
|
+
{ shape: 'playwright-placeholder', re: new RegExp(`\\.${V}Placeholder(?:Text)?\\(\\s*${Q}${BODY}\\1`, 'g'), nameGroup: 2, literalIndex: 1 },
|
|
146
|
+
{ shape: 'playwright-alt', re: new RegExp(`\\.${V}AltText\\(\\s*${Q}${BODY}\\1`, 'g'), nameGroup: 2, literalIndex: 1 },
|
|
147
|
+
{ shape: 'playwright-title', re: new RegExp(`\\.${V}Title\\(\\s*${Q}${BODY}\\1`, 'g'), nameGroup: 2, literalIndex: 1 },
|
|
148
|
+
// `By` + `Text(` exactly, so `.getByLabelText(` and `.getByAltText(` are not
|
|
149
|
+
// candidates for it and the shapes above stay mutually exclusive.
|
|
150
|
+
{ shape: 'playwright-text', re: new RegExp(`\\.${V}Text\\(\\s*${Q}${BODY}\\1`, 'g'), nameGroup: 2, literalIndex: 1 },
|
|
151
|
+
// `cy.contains(selector, text)` — the text is the SECOND literal. Checked before
|
|
152
|
+
// the one-argument form so the two-argument call is never read as `contains(text)`.
|
|
153
|
+
{
|
|
154
|
+
shape: 'cypress-contains',
|
|
155
|
+
re: new RegExp(`\\.contains\\(\\s*${Q}${BODY}\\1\\s*,\\s*(['"\`])((?:(?!\\3)[^\\\\]|\\\\.)*?)\\3`, 'g'),
|
|
156
|
+
nameGroup: 4,
|
|
157
|
+
literalIndex: 2,
|
|
158
|
+
},
|
|
159
|
+
{ shape: 'cypress-contains', re: new RegExp(`\\.contains\\(\\s*${Q}${BODY}\\1\\s*\\)`, 'g'), nameGroup: 2, literalIndex: 1 },
|
|
160
|
+
{ shape: 'selenium-linktext', re: new RegExp(`\\.(?:linkText|partialLinkText)\\(\\s*${Q}${BODY}\\1`, 'g'), nameGroup: 2, literalIndex: 1 },
|
|
161
|
+
// Selenium's constant form, shared by the Java / Python / C# bindings:
|
|
162
|
+
// `find_element(By.LINK_TEXT, "Save")`.
|
|
163
|
+
{
|
|
164
|
+
shape: 'selenium-linktext',
|
|
165
|
+
re: new RegExp(`\\.(?:LINK_TEXT|PARTIAL_LINK_TEXT)\\s*,\\s*${Q}${BODY}\\1`, 'g'),
|
|
166
|
+
nameGroup: 2,
|
|
167
|
+
literalIndex: 1,
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
/**
|
|
171
|
+
* Find every name-anchored locator in `text`.
|
|
172
|
+
*
|
|
173
|
+
* Overlapping shapes are resolved by source position: the first definition that
|
|
174
|
+
* claims a character range wins, which is why the two-argument `cy.contains` is
|
|
175
|
+
* declared before the one-argument form.
|
|
176
|
+
*/
|
|
177
|
+
function scanNameLocators(text, file) {
|
|
178
|
+
const lines = text.split('\n');
|
|
179
|
+
const lineStart = [];
|
|
180
|
+
let acc = 0;
|
|
181
|
+
for (const l of lines) {
|
|
182
|
+
lineStart.push(acc);
|
|
183
|
+
acc += l.length + 1;
|
|
184
|
+
}
|
|
185
|
+
const lineOf = (index) => {
|
|
186
|
+
let lo = 0;
|
|
187
|
+
let hi = lineStart.length - 1;
|
|
188
|
+
while (lo < hi) {
|
|
189
|
+
const mid = (lo + hi + 1) >> 1;
|
|
190
|
+
if (lineStart[mid] <= index)
|
|
191
|
+
lo = mid;
|
|
192
|
+
else
|
|
193
|
+
hi = mid - 1;
|
|
194
|
+
}
|
|
195
|
+
return lo + 1;
|
|
196
|
+
};
|
|
197
|
+
const claimed = [];
|
|
198
|
+
const out = [];
|
|
199
|
+
for (const def of SHAPES) {
|
|
200
|
+
def.re.lastIndex = 0;
|
|
201
|
+
let m;
|
|
202
|
+
while ((m = def.re.exec(text)) !== null) {
|
|
203
|
+
const start = m.index;
|
|
204
|
+
const end = start + m[0].length;
|
|
205
|
+
if (claimed.some(([s, e]) => start < e && end > s))
|
|
206
|
+
continue;
|
|
207
|
+
const name = literalName(m[def.nameGroup]);
|
|
208
|
+
if (name == null || name.trim() === '')
|
|
209
|
+
continue;
|
|
210
|
+
claimed.push([start, end]);
|
|
211
|
+
const call = m[0];
|
|
212
|
+
const shape = def.shape;
|
|
213
|
+
const role = def.roleGroup ? m[def.roleGroup] : undefined;
|
|
214
|
+
const literalIndex = def.literalIndex;
|
|
215
|
+
out.push({
|
|
216
|
+
name,
|
|
217
|
+
role,
|
|
218
|
+
shape,
|
|
219
|
+
site: { file, line: lineOf(start), shape, ...(role ? { role } : {}), text: name },
|
|
220
|
+
call,
|
|
221
|
+
rename: (newName) => shape === 'playwright-role'
|
|
222
|
+
? renameRoleCall(call, newName)
|
|
223
|
+
: renameNthLiteral(call, newName, literalIndex),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return out.sort((a, b) => a.site.line - b.site.line);
|
|
228
|
+
}
|
|
229
|
+
/** Roles a hit can legitimately resolve to, or `null` when it constrains nothing. */
|
|
230
|
+
function candidateRoles(hit) {
|
|
231
|
+
if (hit.role)
|
|
232
|
+
return [hit.role];
|
|
233
|
+
return exports.SHAPE_ROLES[hit.shape] ?? null;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=nameLocators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nameLocators.js","sourceRoot":"","sources":["../src/nameLocators.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": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
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",
|