@ia-qa/self-healing 1.23.0 → 1.25.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 +23 -3
- package/TUTORIAL.md +19 -4
- package/dist/captureMerge.d.ts +11 -0
- package/dist/captureMerge.js +4 -1
- package/dist/captureMerge.js.map +1 -1
- package/dist/cli/audit.d.ts +22 -1
- package/dist/cli/audit.js +43 -6
- package/dist/cli/audit.js.map +1 -1
- package/dist/cli/fix.d.ts +15 -0
- package/dist/cli/fix.js +34 -1
- package/dist/cli/fix.js.map +1 -1
- package/dist/cli/index.js +3 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/login.d.ts +15 -2
- package/dist/cli/login.js +34 -4
- package/dist/cli/login.js.map +1 -1
- package/dist/cli/map.d.ts +21 -0
- package/dist/cli/map.js +46 -1
- package/dist/cli/map.js.map +1 -1
- package/dist/cli/run.js +6 -4
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/session.js +11 -2
- package/dist/cli/session.js.map +1 -1
- package/dist/cypress/capture.js +16 -6
- package/dist/cypress/capture.js.map +1 -1
- package/dist/exercised.d.ts +15 -0
- package/dist/exercised.js +7 -1
- package/dist/exercised.js.map +1 -1
- package/dist/explain.d.ts +14 -0
- package/dist/explain.js +23 -7
- package/dist/explain.js.map +1 -1
- package/dist/ingest.d.ts +15 -1
- package/dist/ingest.js +50 -12
- package/dist/ingest.js.map +1 -1
- package/dist/nameDrift.d.ts +25 -1
- package/dist/nameDrift.js +37 -7
- package/dist/nameDrift.js.map +1 -1
- package/dist/playwright/capture.js +7 -4
- package/dist/playwright/capture.js.map +1 -1
- package/dist/selenium/capture.js +14 -3
- package/dist/selenium/capture.js.map +1 -1
- package/dist/sessionCheck.d.ts +25 -0
- package/dist/sessionCheck.js +46 -0
- package/dist/sessionCheck.js.map +1 -1
- package/dist/unrepaired.d.ts +31 -0
- package/dist/unrepaired.js +0 -0
- package/dist/unrepaired.js.map +1 -1
- package/package.json +1 -1
- package/skills/ia-qa-heal/SKILL.md +2 -2
package/dist/nameDrift.js
CHANGED
|
@@ -22,11 +22,38 @@
|
|
|
22
22
|
*/
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
24
|
exports.REASON_LABEL = void 0;
|
|
25
|
+
exports.nameable = nameable;
|
|
25
26
|
exports.assessNameDrift = assessNameDrift;
|
|
26
27
|
exports.escalateVerdict = escalateVerdict;
|
|
27
28
|
exports.formatFinding = formatFinding;
|
|
28
29
|
exports.mergeFindings = mergeFindings;
|
|
29
30
|
const nameLocators_1 = require("./nameLocators");
|
|
31
|
+
/**
|
|
32
|
+
* Is this label something a test can be pointed at, or is it content?
|
|
33
|
+
*
|
|
34
|
+
* The rewrite this exists to refuse, from the field: a notification bell renamed from
|
|
35
|
+
* `Centre de notifications` to **`9+`**. The element is the same, the rename is real, one
|
|
36
|
+
* element carries the new label — every existing check says `fixable`, and `fix` writes
|
|
37
|
+
* `getByRole('button', { name: '9+' })` into the suite. That locator is broken the moment a
|
|
38
|
+
* tenth notification arrives, and this tool wrote it.
|
|
39
|
+
*
|
|
40
|
+
* The package already refuses to *emit* a locator it would call broken — that is why
|
|
41
|
+
* `computeLocatorRewrites` drops `nameMasked` rows rather than writing `name: 'Cart (*)'`.
|
|
42
|
+
* The same rule simply had no hold on the **target** of a rename.
|
|
43
|
+
*
|
|
44
|
+
* The test is "does it contain a letter", and the reason it is that blunt is the asymmetry:
|
|
45
|
+
* refusing a good rewrite costs a human one glance at a reported row, while accepting a bad
|
|
46
|
+
* one edits a passing test into a failing one. `9+`, `3`, `(5)`, `•` name nothing a person
|
|
47
|
+
* would recognise. `nameMask`'s `hasStablePart` is deliberately NOT reused — it asks whether
|
|
48
|
+
* a *pattern* keeps something recognisable after `*` is removed, and it answers yes to `9+`.
|
|
49
|
+
*
|
|
50
|
+
* A counter that *replaces* a label is also the one shape `nameMask` cannot express: a mask
|
|
51
|
+
* collapses the variable part of a stable label, and here nothing stable is left. So this
|
|
52
|
+
* row is reported for a human, and no pattern is suggested that would not work.
|
|
53
|
+
*/
|
|
54
|
+
function nameable(name) {
|
|
55
|
+
return /\p{L}/u.test(name ?? '');
|
|
56
|
+
}
|
|
30
57
|
const norm = nameLocators_1.normalizeName;
|
|
31
58
|
/**
|
|
32
59
|
* Which recorded test occurrences could be pointing at this element?
|
|
@@ -90,13 +117,15 @@ function assessNameDrift(rows, afterElements, usage) {
|
|
|
90
117
|
const targets = afterElements.filter((e) => reachable.has(e.role) && norm(e.name) === norm(row.newName));
|
|
91
118
|
const reason = shadowed
|
|
92
119
|
? 'shadowed'
|
|
93
|
-
:
|
|
94
|
-
? '
|
|
95
|
-
: targets.length
|
|
96
|
-
? '
|
|
97
|
-
:
|
|
98
|
-
? '
|
|
99
|
-
:
|
|
120
|
+
: !nameable(row.newName)
|
|
121
|
+
? 'unnameable-target'
|
|
122
|
+
: targets.length === 0
|
|
123
|
+
? 'no-target'
|
|
124
|
+
: targets.length > 1
|
|
125
|
+
? 'ambiguous-target'
|
|
126
|
+
: rewritable.length === 0
|
|
127
|
+
? 'text-anchored'
|
|
128
|
+
: 'fixable';
|
|
100
129
|
findings.push({
|
|
101
130
|
role: row.role,
|
|
102
131
|
oldName,
|
|
@@ -137,6 +166,7 @@ exports.REASON_LABEL = {
|
|
|
137
166
|
'ambiguous-target': 'several elements carry the new label — pick one by hand',
|
|
138
167
|
'no-target': 'the new label matches no element in this contract',
|
|
139
168
|
'text-anchored': 'only text-anchored references — the contract cannot say what they target',
|
|
169
|
+
'unnameable-target': 'the new label has no word in it — a counter, not a name. Rewriting to it would write a locator that breaks on the next change',
|
|
140
170
|
};
|
|
141
171
|
const sitesLine = (sites) => {
|
|
142
172
|
const where = sites.slice(0, 3).map((s) => `${s.file}:${s.line}`).join(', ');
|
package/dist/nameDrift.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nameDrift.js","sourceRoot":"","sources":["../src/nameDrift.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;
|
|
1
|
+
{"version":3,"file":"nameDrift.js","sourceRoot":"","sources":["../src/nameDrift.ts"],"names":[],"mappings":"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"}
|
|
@@ -64,7 +64,7 @@ function captureEnabled() {
|
|
|
64
64
|
return process.env[exports.CAPTURE_ENV] === '1';
|
|
65
65
|
}
|
|
66
66
|
const DEBOUNCE_MS = 300;
|
|
67
|
-
const state = { config: null, configLoaded: false, pages: new Map() };
|
|
67
|
+
const state = { config: null, configLoaded: false, pages: new Map(), unattributed: new Set() };
|
|
68
68
|
function config() {
|
|
69
69
|
if (!state.configLoaded) {
|
|
70
70
|
state.configLoaded = true;
|
|
@@ -86,8 +86,11 @@ async function capturePage(page) {
|
|
|
86
86
|
// Step-reached views share a URL, so a run-time capture cannot know which
|
|
87
87
|
// one it is looking at — naming a contract here would be a guess. `map`
|
|
88
88
|
// stays the path for those.
|
|
89
|
-
if (resolved.kind === 'steps')
|
|
89
|
+
if (resolved.kind === 'steps') {
|
|
90
|
+
for (const name of resolved.candidates)
|
|
91
|
+
state.unattributed.add(name);
|
|
90
92
|
return;
|
|
93
|
+
}
|
|
91
94
|
const elements = await (0, aom_1.extractInteractiveElements)(page);
|
|
92
95
|
if (elements.length === 0)
|
|
93
96
|
return;
|
|
@@ -105,7 +108,7 @@ async function capturePage(page) {
|
|
|
105
108
|
}
|
|
106
109
|
function writeShard() {
|
|
107
110
|
try {
|
|
108
|
-
if (state.pages.size === 0)
|
|
111
|
+
if (state.pages.size === 0 && state.unattributed.size === 0)
|
|
109
112
|
return;
|
|
110
113
|
const dir = (0, captureMerge_1.captureDir)();
|
|
111
114
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -115,7 +118,7 @@ function writeShard() {
|
|
|
115
118
|
url: c.url,
|
|
116
119
|
elements: c.elements,
|
|
117
120
|
}));
|
|
118
|
-
fs.writeFileSync(path.join(dir, `worker-${worker}.json`), JSON.stringify({ pages }, null, 2) + '\n', 'utf8');
|
|
121
|
+
fs.writeFileSync(path.join(dir, `worker-${worker}.json`), JSON.stringify({ pages, ...(state.unattributed.size > 0 ? { unattributed: [...state.unattributed].sort() } : {}) }, null, 2) + '\n', 'utf8');
|
|
119
122
|
}
|
|
120
123
|
catch {
|
|
121
124
|
/* a failed shard write loses one worker's capture, never the test run */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/playwright/capture.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,wCAEC;
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/playwright/capture.ts"],"names":[],"mappings":"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"}
|
package/dist/selenium/capture.js
CHANGED
|
@@ -69,6 +69,14 @@ function captureEnabled() {
|
|
|
69
69
|
}
|
|
70
70
|
/** Keyed by `captureKey()`, not by page name — see there. */
|
|
71
71
|
const pages = new Map();
|
|
72
|
+
/**
|
|
73
|
+
* Page names a visit might have been, when the URL could not say which.
|
|
74
|
+
*
|
|
75
|
+
* Same refusal, same fix, same file shape as the Playwright and Cypress hooks — guardrail #7.
|
|
76
|
+
* A bare `return` here turned an honest refusal into a silent drop, and `coverage` then
|
|
77
|
+
* reported those pages as never visited.
|
|
78
|
+
*/
|
|
79
|
+
const unattributed = new Set();
|
|
72
80
|
let cfg = null;
|
|
73
81
|
let cfgLoaded = false;
|
|
74
82
|
function config() {
|
|
@@ -85,7 +93,7 @@ function config() {
|
|
|
85
93
|
}
|
|
86
94
|
function writeShard() {
|
|
87
95
|
try {
|
|
88
|
-
if (pages.size === 0)
|
|
96
|
+
if (pages.size === 0 && unattributed.size === 0)
|
|
89
97
|
return;
|
|
90
98
|
const dir = (0, captureMerge_1.captureDir)();
|
|
91
99
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -95,7 +103,7 @@ function writeShard() {
|
|
|
95
103
|
url: c.url,
|
|
96
104
|
elements: c.elements,
|
|
97
105
|
}));
|
|
98
|
-
fs.writeFileSync(path.join(dir, `sel-${worker}.json`), JSON.stringify({ pages: shardPages }, null, 2) + '\n', 'utf8');
|
|
106
|
+
fs.writeFileSync(path.join(dir, `sel-${worker}.json`), JSON.stringify({ pages: shardPages, ...(unattributed.size > 0 ? { unattributed: [...unattributed].sort() } : {}) }, null, 2) + '\n', 'utf8');
|
|
99
107
|
}
|
|
100
108
|
catch {
|
|
101
109
|
/* a failed shard write loses one worker's capture, never the test run */
|
|
@@ -121,8 +129,11 @@ async function capture(driver) {
|
|
|
121
129
|
const resolved = (0, pageName_1.resolvePageName)(url, config());
|
|
122
130
|
// Step-reached views share a URL, so a run-time capture cannot know which one
|
|
123
131
|
// it is looking at — `map` stays the path for those.
|
|
124
|
-
if (resolved.kind === 'steps')
|
|
132
|
+
if (resolved.kind === 'steps') {
|
|
133
|
+
for (const name of resolved.candidates)
|
|
134
|
+
unattributed.add(name);
|
|
125
135
|
return;
|
|
136
|
+
}
|
|
126
137
|
const elements = (await driver.executeScript(extract_1.extractInPage)) || [];
|
|
127
138
|
if (elements.length === 0)
|
|
128
139
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/selenium/capture.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,wCAEC;
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/selenium/capture.ts"],"names":[],"mappings":"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"}
|
package/dist/sessionCheck.d.ts
CHANGED
|
@@ -47,6 +47,18 @@ export type SessionCause =
|
|
|
47
47
|
| 'wrong-host'
|
|
48
48
|
/** The file looks usable and the app still shows a login — the server dropped it. */
|
|
49
49
|
| 'rotated'
|
|
50
|
+
/**
|
|
51
|
+
* The app sent the browser to another site, and no password field was found there.
|
|
52
|
+
*
|
|
53
|
+
* Never `holds`, and never a failure either: it is the third exit code. Field report —
|
|
54
|
+
* an app redirected to its identity provider, whose form asks for an email first (the
|
|
55
|
+
* password screen comes later), so "redirected **and** a password field" found no
|
|
56
|
+
* password field and the verdict read `✅ This session opens the app`, printing the
|
|
57
|
+
* provider's own URL on the same line. An identity provider presenting a two-step form
|
|
58
|
+
* and a legitimate redirect off-site are indistinguishable from here, and the one thing
|
|
59
|
+
* that is certain is that the session was not used on the app.
|
|
60
|
+
*/
|
|
61
|
+
| 'off-site'
|
|
50
62
|
/** A storageState with nothing in it: this app keeps its token where the file cannot reach. */
|
|
51
63
|
| 'empty'
|
|
52
64
|
/** It opens the app. */
|
|
@@ -68,6 +80,18 @@ export interface SessionFacts {
|
|
|
68
80
|
}
|
|
69
81
|
/** `www.` and an apex are one site, the same fold `discover --sitemap` applies. */
|
|
70
82
|
export declare function foldHost(host: string): string;
|
|
83
|
+
/**
|
|
84
|
+
* Are these two URLs on the same site?
|
|
85
|
+
*
|
|
86
|
+
* Hostname only, folded — the same rule cookies follow, and the same one `foldHost` applies
|
|
87
|
+
* everywhere else here: a port is not a site (RFC 6265 ignores it), `www.` and the apex are
|
|
88
|
+
* one, and `http`/`https` are one. What this answers is "did the app send the browser
|
|
89
|
+
* somewhere else entirely", which is the signal an identity provider trips.
|
|
90
|
+
*
|
|
91
|
+
* A URL that cannot be parsed is **not** called the same site: the verdict that follows from
|
|
92
|
+
* `false` is "could not tell" (exit 2), which is the honest answer to an unparseable URL.
|
|
93
|
+
*/
|
|
94
|
+
export declare function sameSite(a: string, b: string): boolean;
|
|
71
95
|
/** A cookie domain (`.example.com`) covers a host when the host ends with it. */
|
|
72
96
|
export declare function domainCovers(domain: string, host: string): boolean;
|
|
73
97
|
export declare function readFacts(state: StoredSession, baseUrl: string, now?: number): SessionFacts;
|
|
@@ -90,6 +114,7 @@ export interface SessionVerdict {
|
|
|
90
114
|
export declare function judgeSession(facts: SessionFacts, replay?: {
|
|
91
115
|
landed: string;
|
|
92
116
|
wall: boolean;
|
|
117
|
+
offSite?: boolean;
|
|
93
118
|
error?: string;
|
|
94
119
|
}, loginCommand?: string): SessionVerdict;
|
|
95
120
|
/** "3 days", "4 hours", "12 minutes" — enough precision to act, never a timestamp to parse. */
|
package/dist/sessionCheck.js
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.foldHost = foldHost;
|
|
30
|
+
exports.sameSite = sameSite;
|
|
30
31
|
exports.domainCovers = domainCovers;
|
|
31
32
|
exports.readFacts = readFacts;
|
|
32
33
|
exports.judgeSession = judgeSession;
|
|
@@ -35,6 +36,25 @@ exports.describeAge = describeAge;
|
|
|
35
36
|
function foldHost(host) {
|
|
36
37
|
return host.replace(/^www\./i, '').toLowerCase();
|
|
37
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Are these two URLs on the same site?
|
|
41
|
+
*
|
|
42
|
+
* Hostname only, folded — the same rule cookies follow, and the same one `foldHost` applies
|
|
43
|
+
* everywhere else here: a port is not a site (RFC 6265 ignores it), `www.` and the apex are
|
|
44
|
+
* one, and `http`/`https` are one. What this answers is "did the app send the browser
|
|
45
|
+
* somewhere else entirely", which is the signal an identity provider trips.
|
|
46
|
+
*
|
|
47
|
+
* A URL that cannot be parsed is **not** called the same site: the verdict that follows from
|
|
48
|
+
* `false` is "could not tell" (exit 2), which is the honest answer to an unparseable URL.
|
|
49
|
+
*/
|
|
50
|
+
function sameSite(a, b) {
|
|
51
|
+
try {
|
|
52
|
+
return foldHost(new URL(a).hostname) === foldHost(new URL(b).hostname);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
38
58
|
/** A cookie domain (`.example.com`) covers a host when the host ends with it. */
|
|
39
59
|
function domainCovers(domain, host) {
|
|
40
60
|
const d = foldHost(domain.replace(/^\./, ''));
|
|
@@ -135,6 +155,32 @@ function judgeSession(facts, replay, loginCommand = 'ia-qa-heal login') {
|
|
|
135
155
|
],
|
|
136
156
|
};
|
|
137
157
|
}
|
|
158
|
+
// Before "it holds", because this is the case that used to be read as one. A wall on
|
|
159
|
+
// another site is still a wall (`rotated`, below) — this is the one where no password
|
|
160
|
+
// field was found there, and a missing password field off-site proves nothing at all.
|
|
161
|
+
if (replay?.offSite && !replay.wall) {
|
|
162
|
+
let landedHost = replay.landed;
|
|
163
|
+
try {
|
|
164
|
+
landedHost = new URL(replay.landed).hostname;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
/* keep the whole URL when it will not parse — it is still what the reader needs */
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
cause: 'off-site',
|
|
171
|
+
holds: false,
|
|
172
|
+
headline: `Asked for ${facts.host}, landed on ${replay.landed} — another site, and no login form on it.`,
|
|
173
|
+
remedy: [
|
|
174
|
+
`Nothing was proven either way: the session was never used on ${facts.host}.`,
|
|
175
|
+
`An identity provider asking for an email first (the password screen comes later) looks`,
|
|
176
|
+
`exactly like this, and so does an app that legitimately sends you to ${landedHost}.`,
|
|
177
|
+
`Open that URL yourself to tell them apart. If it is a login, a person logs in again:`,
|
|
178
|
+
` ${loginCommand}`,
|
|
179
|
+
`If it is where your app really lives, point baseUrl there — or re-run this check with`,
|
|
180
|
+
`--url on a page that is behind the login, which is what the session is for.`,
|
|
181
|
+
],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
138
184
|
if (replay && !replay.wall) {
|
|
139
185
|
return {
|
|
140
186
|
cause: 'holds',
|
package/dist/sessionCheck.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionCheck.js","sourceRoot":"","sources":["../src/sessionCheck.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;;
|
|
1
|
+
{"version":3,"file":"sessionCheck.js","sourceRoot":"","sources":["../src/sessionCheck.ts"],"names":[],"mappings":"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"}
|
package/dist/unrepaired.d.ts
CHANGED
|
@@ -62,6 +62,37 @@ export declare function reasonFor(row: UnrepairedRow): string;
|
|
|
62
62
|
* anything resembling "no". That distinction is the whole point of this module.
|
|
63
63
|
*/
|
|
64
64
|
export declare function referencedButUnrepaired(rows: UnrepairedRow[], repaired: Set<string>, usage: Usage | null): UnrepairedFinding[];
|
|
65
|
+
/**
|
|
66
|
+
* The arithmetic behind "nothing to apply" — the sentence that dissolves the contradiction.
|
|
67
|
+
*
|
|
68
|
+
* Field report: `diff` announced **40 healable elements** and `fix --dry-run` proposed no
|
|
69
|
+
* change at all. Both were correct and the pair reads as a bug, so the reader either
|
|
70
|
+
* concludes the tool is broken or starts editing by hand — the two worst outcomes available.
|
|
71
|
+
*
|
|
72
|
+
* What was missing is that "repairable" is a fact about the **contract** (this element moved
|
|
73
|
+
* and the tool knows where to) while a rewrite is a fact about the **sources** (that exact
|
|
74
|
+
* string is written in a file it can edit). A Page Object that builds its selectors, a suite
|
|
75
|
+
* that locates by role, a project that never ran `ingest` — all three produce 40 and 0
|
|
76
|
+
* legitimately. Stating the two numbers side by side is the whole fix; inventing a third
|
|
77
|
+
* explanation would not be.
|
|
78
|
+
*
|
|
79
|
+
* `referenced` is deliberately **not measured** without an inventory rather than reported as
|
|
80
|
+
* zero: "no test writes these selectors" and "nobody has told me what your tests write" are
|
|
81
|
+
* opposite findings, and the second one has a remedy.
|
|
82
|
+
*/
|
|
83
|
+
export interface RepairArithmetic {
|
|
84
|
+
/** Rows that are not `ok` and not `added` — what actually drifted. */
|
|
85
|
+
drifted: number;
|
|
86
|
+
/** Of those, the ones the contract can repair towards a known new selector. */
|
|
87
|
+
repairable: number;
|
|
88
|
+
/** Of *those*, the ones whose old selector the inventory has seen in a source file. */
|
|
89
|
+
referenced: number;
|
|
90
|
+
/** False when there is no `usage.json`, which makes `referenced` meaningless. */
|
|
91
|
+
measured: boolean;
|
|
92
|
+
}
|
|
93
|
+
export declare function repairArithmetic(rows: UnrepairedRow[], usage: Usage | null): RepairArithmetic;
|
|
94
|
+
/** One line, or nothing at all when nothing drifted — silence on the good case. */
|
|
95
|
+
export declare function arithmeticLine(a: RepairArithmetic): string | null;
|
|
65
96
|
/**
|
|
66
97
|
* The block that replaces "no test file referenced any of the drifted selectors".
|
|
67
98
|
*
|
package/dist/unrepaired.js
CHANGED
|
Binary file
|
package/dist/unrepaired.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unrepaired.js","sourceRoot":"","sources":["../src/unrepaired.ts"],"names":[],"mappings":";;AAuDA,8BAsBC;AAWD,0DAwCC;AAUD,0CA6BC;
|
|
1
|
+
{"version":3,"file":"unrepaired.js","sourceRoot":"","sources":["../src/unrepaired.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.25.0",
|
|
4
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",
|
|
@@ -54,7 +54,7 @@ exists only in a state nothing captured (behind a tab, a modal, a mode toggle).
|
|
|
54
54
|
| "their suite takes 20 min and `run` runs it twice" | `run --no-verify` — the second run is the post-fix verification, and it is optional. Say what they lose: the exit code then reflects the diff, not a re-proved green suite |
|
|
55
55
|
| "here is my failing test / red build — why?" | `explain --junit <file>` (or `--message "<error text>"`, or pipe the log). Start here when the user hands you a failure rather than a question: it names the locator, judges it against the two captures, and a **PASS rules drift out** so you stop hunting selectors. It re-runs nothing and edits nothing |
|
|
56
56
|
| "day one, no baseline — is my suite still valid?" | `audit` |
|
|
57
|
-
| "the contract misses everything behind my menus / tabs / modals" | `map --deep`. A plain `map` records one state of a page — what is visible when it loads. `--deep` also opens menus, tabs, dialogs and accordions and puts what they reveal in the same contract, each element carrying the click path (`via`) that reaches it. Every non-GET request is blocked while it walks,
|
|
57
|
+
| "the contract misses everything behind my menus / tabs / modals" | `map --deep`. A plain `map` records one state of a page — what is visible when it loads. `--deep` also opens menus, tabs, dialogs and accordions and puts what they reveal in the same contract, each element carrying the click path (`via`) that reaches it. Every non-GET request is blocked while it walks, plus a denylist on action-sounding labels. **Neither stops a GET that writes** (admin action links, one-click confirmations): tell the user to run `--deep` against staging first and read the `via` paths before pointing it at production. **A deep baseline may only be diffed against a deep capture** (§4.13) |
|
|
58
58
|
| "is the app I mapped even sound?" | `check` (dead links · unnamed elements · name collisions · orphan pages) |
|
|
59
59
|
| "which pages am I *not* covering?" | `discover` (`--sitemap` / `--crawl`; suggests only). Behind a login `--sitemap` sees nothing — `--crawl` is the one that works, and it reuses the session |
|
|
60
60
|
| "give me the app's structure" | `graph --format mermaid\|svg\|json\|markdown` |
|
|
@@ -64,7 +64,7 @@ exists only in a state nothing captured (behind a tab, a modal, a mode toggle).
|
|
|
64
64
|
| "is this getting better or worse?" | `history` (`--json`) — the trend no single run can reconstruct |
|
|
65
65
|
| "gate my pipeline on it" | `diff --junit <file>` — every major CI charts the trend natively |
|
|
66
66
|
| `map` says "login wall" / the app is behind SSO | if a storageState already exists (most authenticated Playwright suites write one in `globalSetup`): `--session <file>`, `IAQA_SESSION`, or `"session"` in config.json — no second login. Otherwise tell the human to run `ia-qa-heal login` — **you cannot do it** (§4.12) |
|
|
67
|
-
| "is the session still good?" / before blaming the app for a wall | `session --check`. It tells the
|
|
67
|
+
| "is the session still good?" / before blaming the app for a wall | `session --check`. It tells the causes **apart**: `expired` (every cookie's date is past) and `wrong-host` (nothing is scoped to `baseUrl`) are decided **from the file, no browser**; `rotated` (the file is fine, the server still answers a login) needs one request. `off-site` is **not a verdict about the session** — the app sent the replay to another host (an identity provider) and no login form was found there, which proves nothing either way; report it as inconclusive and ask the human to open that URL. Exit 0 holds · 1 does not · 2 could not tell (`unknown` **and** `off-site`). `--offline` skips the browser entirely. Run it **before** a long `map`, and when a tour or a map reports a wall — a `wrong-host` is the one no amount of logging in will fix |
|
|
68
68
|
| "let me look at it / decide myself" | tell the human to run `ia-qa-heal ui` — **do not run it yourself** (§4.8) |
|
|
69
69
|
| first-time setup | `ia-qa-heal init --yes --base-url <url> --discover [--tests <paths>] [--bootstrap]` — asks nothing, so it cannot hang. `--discover` fills `pages` from their sitemap (plain fetch, no browser); `--bootstrap` also chains ingest → map → baseline. Writing `.ia-qa/config.json` by hand still works |
|
|
70
70
|
| "288 lost, red everywhere, on an app that looks fine" | read the **systemic delta** block `diff` prints — the same element gone from ~every page is one fact about the *capture*, not N drifts. Usually a consent banner, a tour or a flag: the fix is `prepare` in config.json (§4.16), not a rewrite |
|