@testmuai/playwright-bindings 0.1.24 → 0.1.25-beta.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/dist/configure.d.ts +5 -0
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +1 -0
- package/dist/configure.js.map +1 -1
- package/dist/healPatch.d.ts +2 -0
- package/dist/healPatch.d.ts.map +1 -1
- package/dist/healPatch.js +127 -1
- package/dist/healPatch.js.map +1 -1
- package/dist/helpers/autohealAx.d.ts +25 -0
- package/dist/helpers/autohealAx.d.ts.map +1 -0
- package/dist/helpers/autohealAx.js +96 -0
- package/dist/helpers/autohealAx.js.map +1 -0
- package/dist/helpers/axTree/captureAxTree.d.ts +32 -0
- package/dist/helpers/axTree/captureAxTree.d.ts.map +1 -0
- package/dist/helpers/axTree/captureAxTree.js +109 -0
- package/dist/helpers/axTree/captureAxTree.js.map +1 -0
- package/dist/helpers/axTree/index.d.ts +8 -0
- package/dist/helpers/axTree/index.d.ts.map +1 -0
- package/dist/helpers/axTree/index.js +7 -0
- package/dist/helpers/axTree/index.js.map +1 -0
- package/dist/helpers/axTree/serializeAxTree.d.ts +82 -0
- package/dist/helpers/axTree/serializeAxTree.d.ts.map +1 -0
- package/dist/helpers/axTree/serializeAxTree.js +199 -0
- package/dist/helpers/axTree/serializeAxTree.js.map +1 -0
- package/dist/helpers/textualAnalyzer/heal.d.ts +1 -1
- package/dist/helpers/textualAnalyzer/heal.d.ts.map +1 -1
- package/dist/helpers/textualAnalyzer/heal.js +6 -3
- package/dist/helpers/textualAnalyzer/heal.js.map +1 -1
- package/dist/helpers/textualAnalyzer/index.d.ts +1 -0
- package/dist/helpers/textualAnalyzer/index.d.ts.map +1 -1
- package/dist/helpers/textualAnalyzer/index.js +2 -2
- package/dist/helpers/textualAnalyzer/index.js.map +1 -1
- package/package.json +1 -1
package/dist/configure.d.ts
CHANGED
|
@@ -27,6 +27,11 @@ export interface ConfigureOptions {
|
|
|
27
27
|
defaultNavigationTimeoutMs?: number;
|
|
28
28
|
/** Opt-in marker — code-gen sets this for V4 KaneAI runs. Gates LT:Options.kaneRunV4 + preCmdVisual emission. */
|
|
29
29
|
kaneRunV4?: boolean;
|
|
30
|
+
/** Global locator auto-heal version gate. Default '' keeps the vision heal
|
|
31
|
+
* path; code-gen sets configure({ autoHealVersion: 'AH2' }) to route failed
|
|
32
|
+
* actions through the AX-tree locator heal. Read by healPatch (mirrors PY's
|
|
33
|
+
* global `auto_heal_version` config — set once, read via configure.get). */
|
|
34
|
+
autoHealVersion?: string;
|
|
30
35
|
}
|
|
31
36
|
declare const DEFAULTS: Required<ConfigureOptions>;
|
|
32
37
|
type ConfigKey = keyof typeof DEFAULTS;
|
package/dist/configure.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,iHAAiH;IACjH,SAAS,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,iHAAiH;IACjH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;iFAG6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,QAAA,MAAM,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAoBxC,CAAC;AAEF,KAAK,SAAS,GAAG,MAAM,OAAO,QAAQ,CAAC;AAKvC,KAAK,aAAa,GAAG,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAGtD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAEhE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAUtD;AAED,wBAAgB,GAAG,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAErE;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAE9C;AAED,wBAAgB,MAAM,IAAI,IAAI,CAU7B"}
|
package/dist/configure.js
CHANGED
package/dist/configure.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAoC/B,MAAM,QAAQ,GAA+B;IAC3C,SAAS,EAAE,KAAK;IAChB,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,EAAE;IACR,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,aAAa,EAAE,EAAE;IACjB,aAAa,EAAE,EAAE;IACjB,gBAAgB,EAAE,KAAK;IACvB,SAAS,EAAE,EAAE;IACb,UAAU,EAAE,EAAE;IACd,eAAe,EAAE,EAAE;IACnB,aAAa,EAAE,EAAE;IACjB,aAAa,EAAE,CAAC;IAChB,sBAAsB,EAAE,KAAK;IAC7B,0BAA0B,EAAE,KAAK;IACjC,SAAS,EAAE,KAAK;IAChB,eAAe,EAAE,EAAE;CACpB,CAAC;AAIF,MAAM,IAAI,GAA+B,EAAE,GAAG,QAAQ,EAAE,CAAC;AACzD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAa,CAAC;AAGrC,MAAM,KAAK,GAAoB,EAAE,CAAC;AAElC,MAAM,UAAU,sBAAsB,CAAC,IAAmB;IACxD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAsB;IAC9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAgB,EAAE,CAAC;QACnD,IAAI,CAAC,CAAC,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC;YACvB,GAAG,CAAC,IAAI,CAAC,kCAAkC,GAAG,aAAa,CAAC,CAAC;YAC7D,SAAS;QACX,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,GAAG,CAAsB,GAAM;IAC7C,OAAO,IAAI,CAAC,GAAG,CAAyB,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,GAAc;IACnC,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,MAAM;IACpB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAgB,EAAE,CAAC;QACvD,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YAAG,IAAmC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;aAClE,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;YAAG,IAAmC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;;YAC3F,IAAmC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACvD,CAAC;IACD,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,uFAAuF;IACvF,4FAA4F;AAC9F,CAAC"}
|
package/dist/healPatch.d.ts
CHANGED
|
@@ -15,4 +15,6 @@ export declare function installHealPatch(samplePage: Page): void;
|
|
|
15
15
|
* cleanup of the originals map.
|
|
16
16
|
*/
|
|
17
17
|
export declare function _uninstallHealPatch(samplePage?: Page): void;
|
|
18
|
+
/** Test-only: reset the warn-once latch for an unrecognized autoHealVersion. */
|
|
19
|
+
export declare function _resetAhVersionWarned(): void;
|
|
18
20
|
//# sourceMappingURL=healPatch.d.ts.map
|
package/dist/healPatch.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"healPatch.d.ts","sourceRoot":"","sources":["../src/healPatch.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAgB,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"healPatch.d.ts","sourceRoot":"","sources":["../src/healPatch.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAgB,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAmPrD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI,CAUvD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAU3D;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
|
package/dist/healPatch.js
CHANGED
|
@@ -1,15 +1,102 @@
|
|
|
1
1
|
import { currentStep, _getReporter } from './step.js';
|
|
2
2
|
import { config } from './config.js';
|
|
3
|
+
import { get as getConfig } from './configure.js';
|
|
3
4
|
import { getVisionCoordinates } from './helpers/vision.js';
|
|
4
|
-
import {
|
|
5
|
+
import { runLocatorHeal } from './helpers/autohealAx.js';
|
|
6
|
+
import { log, repr } from './log.js';
|
|
5
7
|
const HEAL_METHODS = [
|
|
6
8
|
'click', 'dblclick', 'fill', 'type', 'press',
|
|
7
9
|
'hover', 'check', 'uncheck', 'selectOption',
|
|
8
10
|
'setInputFiles', 'scrollIntoViewIfNeeded', 'focus', 'tap',
|
|
9
11
|
];
|
|
10
12
|
const COORD_METHODS = new Set(['click', 'dblclick', 'hover']);
|
|
13
|
+
// Maps a Locator method → the AH2 autoheal action_type enum
|
|
14
|
+
// (click | select | type | scroll). Mirrors PY's `_METHOD_TO_ACTION_TYPE`.
|
|
15
|
+
// Methods omitted (focus, and the JS-absent drag_to) skip AH2 entirely — the
|
|
16
|
+
// API has no action_type slot for them.
|
|
17
|
+
const METHOD_TO_ACTION_TYPE = {
|
|
18
|
+
click: 'click', dblclick: 'click', tap: 'click',
|
|
19
|
+
hover: 'click', check: 'click', uncheck: 'click',
|
|
20
|
+
fill: 'type', type: 'type', press: 'type', setInputFiles: 'type',
|
|
21
|
+
selectOption: 'select',
|
|
22
|
+
scrollIntoViewIfNeeded: 'scroll',
|
|
23
|
+
};
|
|
24
|
+
// Playwright methods whose options object is the SECOND positional arg (the
|
|
25
|
+
// first is a value: text / key / values / files). All other HEAL_METHODS take
|
|
26
|
+
// options as the FIRST arg. Used to inject a capped retry timeout at the right
|
|
27
|
+
// position (mirrors PY's `_capped_retry_kwargs`, which caps the `timeout` kwarg).
|
|
28
|
+
const OPTIONS_AT_INDEX_1 = new Set(['fill', 'type', 'press', 'selectOption', 'setInputFiles']);
|
|
29
|
+
const RETRY_TIMEOUT_CAP_MS = 5_000;
|
|
30
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
31
|
+
/**
|
|
32
|
+
* Read the drifted selector off a Locator, defensively — the value the AH2
|
|
33
|
+
* heal endpoint receives as `previous_selectors`. Playwright JS stores it as
|
|
34
|
+
* a plain own-property `_selector` (empirically verified: `page.locator('#x')
|
|
35
|
+
* ._selector === '#x'`, xpath keeps its `xpath=` prefix; there is NO
|
|
36
|
+
* `_impl_obj` in JS — that was the Python path). Never throws.
|
|
37
|
+
*
|
|
38
|
+
* NOTE: `_selector` is a private Playwright internal — no public API exposes
|
|
39
|
+
* it. On a Playwright rename/removal this degrades to `""` (the heal still
|
|
40
|
+
* runs, it just loses the re-anchor hint); the real-`page.locator(...)`
|
|
41
|
+
* regression test in healPatchAh2.test.ts asserts non-empty extraction, so a
|
|
42
|
+
* rename fails CI loudly instead of silently dropping the hint.
|
|
43
|
+
*/
|
|
44
|
+
function readDriftedSelector(loc) {
|
|
45
|
+
try {
|
|
46
|
+
const s = loc?._selector;
|
|
47
|
+
return typeof s === 'string' ? s : '';
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Clone `args`, injecting a capped `timeout` into the method's options arg. */
|
|
54
|
+
function withCappedTimeout(name, args) {
|
|
55
|
+
const idx = OPTIONS_AT_INDEX_1.has(name) ? 1 : 0;
|
|
56
|
+
const next = args.slice();
|
|
57
|
+
const existing = next[idx] && typeof next[idx] === 'object' ? next[idx] : undefined;
|
|
58
|
+
const orig = existing?.['timeout'];
|
|
59
|
+
const capped = Math.min(typeof orig === 'number' ? orig : DEFAULT_TIMEOUT_MS, RETRY_TIMEOUT_CAP_MS);
|
|
60
|
+
next[idx] = { ...(existing ?? {}), timeout: capped };
|
|
61
|
+
return next;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* AH2 branch: capture → heal → resolve a fresh locator → retry the SAME method
|
|
65
|
+
* on it. Applies to ALL HEAL_METHODS that map to an action type (not just the
|
|
66
|
+
* coord ones), since it yields a real fresh locator. The retry runs the
|
|
67
|
+
* UNWRAPPED `original` on the fresh locator (exactly like PY's heal-cache
|
|
68
|
+
* fast-path calls `original(fresh, ...)`) so it cannot recurse back into this
|
|
69
|
+
* wrapper. Never throws; returns `{ healed:false }` on any miss/failure so the
|
|
70
|
+
* caller falls through to the vision path / rethrows.
|
|
71
|
+
*/
|
|
72
|
+
async function tryAh2LocatorHeal(loc, original, name, args, description) {
|
|
73
|
+
const page = loc.page();
|
|
74
|
+
const previous = readDriftedSelector(loc);
|
|
75
|
+
const actionType = METHOD_TO_ACTION_TYPE[name];
|
|
76
|
+
if (!actionType)
|
|
77
|
+
return { healed: false };
|
|
78
|
+
const healed = await runLocatorHeal(page, description, actionType, previous);
|
|
79
|
+
if (!healed)
|
|
80
|
+
return { healed: false };
|
|
81
|
+
const selector = healed.locatorType === 'xpath' ? `xpath=${healed.locator}` : healed.locator;
|
|
82
|
+
try {
|
|
83
|
+
const fresh = page.locator(selector);
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
|
+
const value = await original.apply(fresh, withCappedTimeout(name, args));
|
|
86
|
+
log.helper(`[heal] ${name} '${description}' → fresh locator ${selector.slice(0, 80)}`);
|
|
87
|
+
return { healed: true, value };
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
log.warn(`[heal] retry on fresh locator ${selector} failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
91
|
+
return { healed: false };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
11
94
|
const originals = new Map();
|
|
12
95
|
let installed = false;
|
|
96
|
+
// Warn once (not per-action) when autoHealVersion is configured to a
|
|
97
|
+
// non-empty value that isn't the recognized 'AH2' — most likely a typo that
|
|
98
|
+
// would otherwise silently fall back to the legacy heal with no signal.
|
|
99
|
+
let ahVersionWarned = false;
|
|
13
100
|
/**
|
|
14
101
|
* Capture element rect via locator.boundingBox() and ship it via the
|
|
15
102
|
* `lambda-element-bounds` action verb. Best-effort. Never raises — failure
|
|
@@ -54,6 +141,41 @@ function wrap(name, original) {
|
|
|
54
141
|
catch (e) {
|
|
55
142
|
const err = e;
|
|
56
143
|
const strict = isStrictModeViolation(err);
|
|
144
|
+
// Warn once (not per-action) on a non-empty, unrecognized
|
|
145
|
+
// autoHealVersion — most likely a typo (e.g. 'AH3') that would
|
|
146
|
+
// otherwise silently fall back to the legacy heal below with no signal.
|
|
147
|
+
const ahVersion = getConfig('autoHealVersion');
|
|
148
|
+
if (ahVersion && ahVersion !== 'AH2' && !ahVersionWarned) {
|
|
149
|
+
log.warn(`[heal] unrecognized autoHealVersion=${repr(ahVersion)} — using legacy heal`);
|
|
150
|
+
ahVersionWarned = true;
|
|
151
|
+
}
|
|
152
|
+
// AH2 locator heal, gated by the GLOBAL config (mirror PY's global
|
|
153
|
+
// `auto_heal_version`): set once via configure({ autoHealVersion: 'AH2' })
|
|
154
|
+
// and read via configure.get — NOT a per-step opt. This branch is
|
|
155
|
+
// TERMINAL — it mirrors PY's `_default_heal` use_ax path: on a miss,
|
|
156
|
+
// `heal_fn` returns False and the wrapper does a bare `raise` of the
|
|
157
|
+
// ORIGINAL exception, with no other heal attempted. So here too: on ANY
|
|
158
|
+
// miss (runLocatorHeal returns null, or the fresh-locator retry itself
|
|
159
|
+
// fails), rethrow the original error immediately — we do NOT fall
|
|
160
|
+
// through to the (coord-only) vision heal below. A vision click landing
|
|
161
|
+
// somewhere would mask a genuine AH2 failure, which is exactly the
|
|
162
|
+
// fail-loud behavior PY's design avoids. When the global gate is off,
|
|
163
|
+
// this block is skipped entirely and the vision path stays byte-unchanged.
|
|
164
|
+
if (ahVersion === 'AH2' &&
|
|
165
|
+
METHOD_TO_ACTION_TYPE[name] &&
|
|
166
|
+
(strict || (err?.name === 'TimeoutError' && (await this.count()) === 0))) {
|
|
167
|
+
let outcome;
|
|
168
|
+
try {
|
|
169
|
+
outcome = await tryAh2LocatorHeal(this, original, name, args, stepInfo.description);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// tryAh2LocatorHeal never throws by contract; defensive only.
|
|
173
|
+
outcome = { healed: false };
|
|
174
|
+
}
|
|
175
|
+
if (outcome.healed)
|
|
176
|
+
return outcome.value;
|
|
177
|
+
throw e;
|
|
178
|
+
}
|
|
57
179
|
// Heal on a timeout where the element is absent (count === 0), or a
|
|
58
180
|
// strict-mode violation where the selector matched >1 element (count > 0
|
|
59
181
|
// is expected, so skip the absence check). Both gated to coord-healable
|
|
@@ -134,4 +256,8 @@ export function _uninstallHealPatch(samplePage) {
|
|
|
134
256
|
originals.clear();
|
|
135
257
|
installed = false;
|
|
136
258
|
}
|
|
259
|
+
/** Test-only: reset the warn-once latch for an unrecognized autoHealVersion. */
|
|
260
|
+
export function _resetAhVersionWarned() {
|
|
261
|
+
ahVersionWarned = false;
|
|
262
|
+
}
|
|
137
263
|
//# sourceMappingURL=healPatch.js.map
|
package/dist/healPatch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"healPatch.js","sourceRoot":"","sources":["../src/healPatch.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"healPatch.js","sourceRoot":"","sources":["../src/healPatch.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAErC,MAAM,YAAY,GAAG;IACnB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;IAC5C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc;IAC3C,eAAe,EAAE,wBAAwB,EAAE,OAAO,EAAE,KAAK;CACjD,CAAC;AAEX,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;AAE9D,4DAA4D;AAC5D,2EAA2E;AAC3E,6EAA6E;AAC7E,wCAAwC;AACxC,MAAM,qBAAqB,GAA2B;IACpD,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO;IAC/C,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IAChD,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM;IAChE,YAAY,EAAE,QAAQ;IACtB,sBAAsB,EAAE,QAAQ;CACjC,CAAC;AAEF,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,kFAAkF;AAClF,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;AAE/F,MAAM,oBAAoB,GAAG,KAAK,CAAC;AACnC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC;;;;;;;;;;;;GAYG;AACH,SAAS,mBAAmB,CAAC,GAAY;IACvC,IAAI,CAAC;QACH,MAAM,CAAC,GAAI,GAAkD,EAAE,SAAS,CAAC;QACzE,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,SAAS,iBAAiB,CAAC,IAAY,EAAE,IAAe;IACtD,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1B,MAAM,QAAQ,GACZ,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAI,CAAC,GAAG,CAA6B,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,CAAC;IACpG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACrD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,iBAAiB,CAC9B,GAAY,EACZ,QAAkD,EAClD,IAAY,EACZ,IAAe,EACf,WAAmB;IAEnB,MAAM,IAAI,GAAS,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC7E,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAEtC,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;IAC7F,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACrC,8DAA8D;QAC9D,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAY,EAAE,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAChF,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,KAAK,WAAW,qBAAqB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QACvF,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,IAAI,CAAC,iCAAiC,QAAQ,YAAY,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5G,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAAmB,CAAC;AAC7C,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB,qEAAqE;AACrE,4EAA4E;AAC5E,wEAAwE;AACxE,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B;;;;GAIG;AACH,KAAK,UAAU,oBAAoB,CAAC,OAAgB,EAAE,aAAsB;IAC1E,IAAI,CAAC;QACH,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,KAAK,OAAO;YAAE,OAAO;QACjD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,CAAC,GAAG,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,MAAM,CAAC,CAAC,iBAAiB,CACvB,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAChE,aAAa,CACd,CAAC;IACJ,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,MAAM,CAAC,6BAA6B,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,GAAyB;IACtD,OAAO,CACL,OAAO,GAAG,EAAE,OAAO,KAAK,QAAQ;QAChC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAC5D,CAAC;AACJ,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,QAAkD;IAC5E,OAAO,KAAK,UAAU,OAAO,CAAgB,GAAG,IAAe;QAC7D,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,IAAI,CAAC,QAAQ;YAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAEjD,MAAM,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;QAEzD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK;YAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAE7D,IAAI,CAAC;YACH,OAAO,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,GAAG,GAAG,CAAwC,CAAC;YACrD,MAAM,MAAM,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;YAE1C,0DAA0D;YAC1D,+DAA+D;YAC/D,wEAAwE;YACxE,MAAM,SAAS,GAAG,SAAS,CAAC,iBAAiB,CAAC,CAAC;YAC/C,IAAI,SAAS,IAAI,SAAS,KAAK,KAAK,IAAI,CAAC,eAAe,EAAE,CAAC;gBACzD,GAAG,CAAC,IAAI,CAAC,uCAAuC,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;gBACvF,eAAe,GAAG,IAAI,CAAC;YACzB,CAAC;YAED,mEAAmE;YACnE,2EAA2E;YAC3E,kEAAkE;YAClE,qEAAqE;YACrE,qEAAqE;YACrE,wEAAwE;YACxE,uEAAuE;YACvE,kEAAkE;YAClE,wEAAwE;YACxE,mEAAmE;YACnE,sEAAsE;YACtE,2EAA2E;YAC3E,IACE,SAAS,KAAK,KAAK;gBACnB,qBAAqB,CAAC,IAAI,CAAC;gBAC3B,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,cAAc,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EACxE,CAAC;gBACD,IAAI,OAA6C,CAAC;gBAClD,IAAI,CAAC;oBACH,OAAO,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;gBACtF,CAAC;gBAAC,MAAM,CAAC;oBACP,8DAA8D;oBAC9D,OAAO,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBAC9B,CAAC;gBACD,IAAI,OAAO,CAAC,MAAM;oBAAE,OAAO,OAAO,CAAC,KAAK,CAAC;gBACzC,MAAM,CAAC,CAAC;YACV,CAAC;YAED,oEAAoE;YACpE,yEAAyE;YACzE,wEAAwE;YACxE,sEAAsE;YACtE,yDAAyD;YACzD,IACE,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;gBACvB,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,cAAc,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EACxE,CAAC;gBACD,4DAA4D;gBAC5D,qEAAqE;gBACrE,kEAAkE;gBAClE,sDAAsD;gBACtD,IAAI,CAAC;oBACH,MAAM,IAAI,GAAS,IAAI,CAAC,IAAI,EAAE,CAAC;oBAC/B,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;oBAC5E,IAAI,MAAM,EAAE,CAAC;wBACX,IAAI,IAAI,KAAK,OAAO;4BAAE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;wBACjE,8DAA8D;wBAC9D,8DAA8D;wBAC9D,OAAQ,IAAI,CAAC,KAAa,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;oBACvD,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,4DAA4D;gBAC9D,CAAC;YACH,CAAC;YACD,+DAA+D;YAC/D,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,8DAA8D;AAC9D,SAAS,mBAAmB,CAAC,UAAgB;IAC3C,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,8DAA8D;IAC9D,OAAQ,SAAS,CAAC,WAAmB,CAAC,SAAS,CAAC;AAClD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAgB;IAC/C,IAAI,SAAS;QAAE,OAAO;IACtB,MAAM,KAAK,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,OAAO,IAAI,KAAK,UAAU;YAAE,SAAS;QACzC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,IAAgD,CAAC,CAAC;IAC7E,CAAC;IACD,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAiB;IACnD,IAAI,CAAC,UAAU,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACxC,SAAS,CAAC,KAAK,EAAE,CAAC;QAClB,SAAS,GAAG,KAAK,CAAC;QAClB,OAAO;IACT,CAAC;IACD,MAAM,KAAK,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,SAAS,GAAG,KAAK,CAAC;AACpB,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,qBAAqB;IACnC,eAAe,GAAG,KAAK,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AH2 standalone-binding heal client (TS mirror of the Python
|
|
3
|
+
* `testmu/_helpers/autoheal_ax.py`): capture the live AX tree → POST
|
|
4
|
+
* `/api/v1/AH2/autoheal` → resolve the returned `ref` → a fresh locator.
|
|
5
|
+
*
|
|
6
|
+
* This is the REPLAY-time counterpart to the runner's AH2 grounding: exported
|
|
7
|
+
* JS tests run inside customer CI with no runner process, so the whole
|
|
8
|
+
* capture → heal → resolve pipeline runs in-process here using the shared AX
|
|
9
|
+
* pipeline (`axTree/`) and the binding's own selector synthesis
|
|
10
|
+
* (`textualAnalyzer/locatorEnrichment.enrichElementLocator`).
|
|
11
|
+
*
|
|
12
|
+
* Returns `{ locator, locatorType, confidence, reasoning }` on a hit, or
|
|
13
|
+
* `null` on ANY miss (smart off, invalid action type, capture failed, non-200,
|
|
14
|
+
* no ref, confidence below floor, ref not in the table, enrichment failed,
|
|
15
|
+
* transport/other error). NEVER throws.
|
|
16
|
+
*/
|
|
17
|
+
import type { Page } from 'playwright';
|
|
18
|
+
export interface LocatorHeal {
|
|
19
|
+
locator: string;
|
|
20
|
+
locatorType: string;
|
|
21
|
+
confidence: number;
|
|
22
|
+
reasoning: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function runLocatorHeal(page: Page, actionInstruction: string, actionType: string, previousSelectors?: string, confidenceFloor?: number): Promise<LocatorHeal | null>;
|
|
25
|
+
//# sourceMappingURL=autohealAx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autohealAx.d.ts","sourceRoot":"","sources":["../../src/helpers/autohealAx.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,YAAY,CAAC;AAUnD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AA0CD,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,MAAM,EAClB,iBAAiB,SAAK,EACtB,eAAe,SAAM,GACpB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAiD7B"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { config } from '../config.js';
|
|
2
|
+
import { fetchWithAuth } from '../http.js';
|
|
3
|
+
import { log } from '../log.js';
|
|
4
|
+
import { captureAxTree } from './axTree/index.js';
|
|
5
|
+
import { enrichElementLocator } from './textualAnalyzer/locatorEnrichment.js';
|
|
6
|
+
const HEAL_TIMEOUT_MS = 60_000;
|
|
7
|
+
const VALID_ACTION_TYPES = new Set(['click', 'select', 'type', 'scroll']);
|
|
8
|
+
function healUrl() {
|
|
9
|
+
return config.current.aiApiHost.replace(/\/+$/, '') + '/api/v1/AH2/autoheal';
|
|
10
|
+
}
|
|
11
|
+
async function postAxHeal(url, body) {
|
|
12
|
+
try {
|
|
13
|
+
const resp = await fetchWithAuth(url, {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: { 'content-type': 'application/json' },
|
|
16
|
+
body: JSON.stringify(body),
|
|
17
|
+
signal: AbortSignal.timeout(HEAL_TIMEOUT_MS),
|
|
18
|
+
});
|
|
19
|
+
if (!resp.ok) {
|
|
20
|
+
log.helper(`[autoheal_ax] ${url} -> ${resp.status}`);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return (await resp.json());
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
log.warn(`[autoheal_ax] transport error: ${e instanceof Error ? e.message : String(e)}`);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve a live CDP session that can act on `frameId`'s nodes.
|
|
32
|
+
*
|
|
33
|
+
* v1 is main-frame-only (`captureAxTree` never inlines OOPIF content, so every
|
|
34
|
+
* ref carries `frame_id == ""`), so this always opens a fresh main-page
|
|
35
|
+
* session — identical to what the Python `resolve_session_for_frame` does for
|
|
36
|
+
* the `""` main-frame convention. Frame-scoped routing (the Python
|
|
37
|
+
* `_frame_capture.resolve_session_for_frame` OOPIF path) lands together with
|
|
38
|
+
* frame-aware capture as a documented follow-up. Caller owns detaching it.
|
|
39
|
+
*/
|
|
40
|
+
async function resolveSessionForFrame(page, _frameId) {
|
|
41
|
+
return page.context().newCDPSession(page);
|
|
42
|
+
}
|
|
43
|
+
export async function runLocatorHeal(page, actionInstruction, actionType, previousSelectors = '', confidenceFloor = 0.7) {
|
|
44
|
+
if (!config.current.smart || !VALID_ACTION_TYPES.has(actionType))
|
|
45
|
+
return null;
|
|
46
|
+
try {
|
|
47
|
+
const captured = await captureAxTree(page);
|
|
48
|
+
if (captured === null)
|
|
49
|
+
return null;
|
|
50
|
+
const { doc, refTable } = captured;
|
|
51
|
+
const body = {
|
|
52
|
+
action_instruction: actionInstruction,
|
|
53
|
+
action_type: actionType,
|
|
54
|
+
dom_snapshot: doc,
|
|
55
|
+
previous_selectors: previousSelectors || '',
|
|
56
|
+
};
|
|
57
|
+
const resp = await postAxHeal(healUrl(), body);
|
|
58
|
+
if (!resp || !resp['ref'])
|
|
59
|
+
return null;
|
|
60
|
+
const confidence = Number(resp['confidence'] ?? 0);
|
|
61
|
+
if (confidence < confidenceFloor) {
|
|
62
|
+
log.helper(`[autoheal_ax] confidence ${confidence} < floor ${confidenceFloor}`);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const entry = refTable[String(resp['ref'])];
|
|
66
|
+
if (!entry || entry.backend_dom_node_id == null)
|
|
67
|
+
return null;
|
|
68
|
+
// Frame-scope: resolve on the ref's own frame CDP session (main frame for v1).
|
|
69
|
+
const cdp = await resolveSessionForFrame(page, entry.frame_id);
|
|
70
|
+
let enriched;
|
|
71
|
+
try {
|
|
72
|
+
enriched = await enrichElementLocator(cdp, { backendDomNodeId: entry.backend_dom_node_id });
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
try {
|
|
76
|
+
await cdp.detach();
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
/* ignore */
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!enriched || !enriched.locator)
|
|
83
|
+
return null;
|
|
84
|
+
return {
|
|
85
|
+
locator: enriched.locator,
|
|
86
|
+
locatorType: enriched.locatorType ?? 'css',
|
|
87
|
+
confidence,
|
|
88
|
+
reasoning: typeof resp['reasoning'] === 'string' ? resp['reasoning'] : '',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
log.warn(`[autoheal_ax] unexpected: ${e instanceof Error ? e.message : String(e)}`);
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=autohealAx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autohealAx.js","sourceRoot":"","sources":["../../src/helpers/autohealAx.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main-frame AX capture → greppable doc + per-step ref table (TS).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the Python `testmu/_helpers/ax_tree/_capture.py` (`capture_ax_tree`)
|
|
5
|
+
* + `_accessibility.py` CDP path, but MAIN-FRAME ONLY for v1. The Python
|
|
6
|
+
* design's frame-aware capture (`_frame_capture.py` — same-process + OOPIF
|
|
7
|
+
* iframes inlined into one continuous ref space) is a documented follow-up
|
|
8
|
+
* here; this matches the v16-server's stated main-frame acceptance. The
|
|
9
|
+
* serializer (`serializeAxTree`) supports the frame-merge whole, so the
|
|
10
|
+
* `e<N>` doc + refTable format is already byte-identical to Python's
|
|
11
|
+
* frame-aware output — only the OOPIF *capture* is deferred.
|
|
12
|
+
*
|
|
13
|
+
* Plumbing mirrors `textualAnalyzer/domStructured.ts`: page.context()
|
|
14
|
+
* .newCDPSession → Accessibility.getFullAXTree → build the AxNode tree →
|
|
15
|
+
* serializeAxTree. Unlike domStructured it fetches NO bounding boxes (the
|
|
16
|
+
* serializer is a pure structural walk with no viewport filter — Python's
|
|
17
|
+
* capture passes skip_bounding_boxes=True on this path), and it normalizes
|
|
18
|
+
* CDP tri-state strings ("true"/"false"/"mixed") before rendering.
|
|
19
|
+
*/
|
|
20
|
+
import type { Page } from 'playwright';
|
|
21
|
+
import { type RefTable } from './serializeAxTree.js';
|
|
22
|
+
/**
|
|
23
|
+
* Capture the page's main-frame AX document + per-step ref table.
|
|
24
|
+
*
|
|
25
|
+
* @returns `{ doc, refTable }`, or `null` when the tree is empty or capture
|
|
26
|
+
* fails (never throws).
|
|
27
|
+
*/
|
|
28
|
+
export declare function captureAxTree(page: Page): Promise<{
|
|
29
|
+
doc: string;
|
|
30
|
+
refTable: RefTable;
|
|
31
|
+
} | null>;
|
|
32
|
+
//# sourceMappingURL=captureAxTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captureAxTree.d.ts","sourceRoot":"","sources":["../../../src/helpers/axTree/captureAxTree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,YAAY,CAAC;AAEnD,OAAO,EAAgC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAqEnF;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAAG,IAAI,CAAC,CA+BnG"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { log } from '../../log.js';
|
|
2
|
+
import { serializeAxTree } from './serializeAxTree.js';
|
|
3
|
+
/** Extract a CDP property's `.value.value`, or null. */
|
|
4
|
+
function cdpProp(properties, name) {
|
|
5
|
+
if (!properties)
|
|
6
|
+
return null;
|
|
7
|
+
for (const p of properties) {
|
|
8
|
+
if (p['name'] === name) {
|
|
9
|
+
const v = p['value'];
|
|
10
|
+
return typeof v === 'object' && v !== null ? v.value ?? null : null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
/** A CDP AXValue's `.value` as a string. */
|
|
16
|
+
function axValue(node, key) {
|
|
17
|
+
const info = node[key];
|
|
18
|
+
return typeof info === 'object' && info !== null
|
|
19
|
+
? String(info.value ?? '')
|
|
20
|
+
: '';
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Normalize a tri-state AX value to true / false / "mixed" / null.
|
|
24
|
+
* CDP reports `checked`/`pressed` as the STRINGS "true"/"false"/"mixed"; the
|
|
25
|
+
* serializer's state rendering keys on real booleans / "mixed", so an
|
|
26
|
+
* unchecked box would otherwise render as [checked] (JS "false" is truthy).
|
|
27
|
+
* Mirrors Python `_normalize_tristate`.
|
|
28
|
+
*/
|
|
29
|
+
function normalizeTristate(value) {
|
|
30
|
+
if (typeof value === 'boolean' || value == null)
|
|
31
|
+
return value ?? null;
|
|
32
|
+
if (typeof value === 'string') {
|
|
33
|
+
const lowered = value.trim().toLowerCase();
|
|
34
|
+
if (lowered === 'true')
|
|
35
|
+
return true;
|
|
36
|
+
if (lowered === 'false')
|
|
37
|
+
return false;
|
|
38
|
+
if (lowered === 'mixed')
|
|
39
|
+
return 'mixed';
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
function parseNode(node, byId) {
|
|
44
|
+
const props = node['properties'];
|
|
45
|
+
const children = [];
|
|
46
|
+
for (const cid of node['childIds'] ?? []) {
|
|
47
|
+
const child = byId.get(cid);
|
|
48
|
+
if (child)
|
|
49
|
+
children.push(parseNode(child, byId));
|
|
50
|
+
}
|
|
51
|
+
const levelRaw = cdpProp(props, 'level');
|
|
52
|
+
return {
|
|
53
|
+
role: axValue(node, 'role'),
|
|
54
|
+
name: axValue(node, 'name'),
|
|
55
|
+
value: axValue(node, 'value') || null,
|
|
56
|
+
url: cdpProp(props, 'url') ?? null,
|
|
57
|
+
level: typeof levelRaw === 'number' ? levelRaw : levelRaw != null ? Number(levelRaw) : null,
|
|
58
|
+
checked: normalizeTristate(cdpProp(props, 'checked')),
|
|
59
|
+
pressed: normalizeTristate(cdpProp(props, 'pressed')),
|
|
60
|
+
disabled: Boolean(cdpProp(props, 'disabled')),
|
|
61
|
+
selected: cdpProp(props, 'selected') ?? null,
|
|
62
|
+
expanded: cdpProp(props, 'expanded') ?? null,
|
|
63
|
+
required: Boolean(cdpProp(props, 'required')),
|
|
64
|
+
readonly: Boolean(cdpProp(props, 'readonly')),
|
|
65
|
+
focused: Boolean(cdpProp(props, 'focused')),
|
|
66
|
+
backendDomNodeId: node['backendDOMNodeId'] ?? null,
|
|
67
|
+
children,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Capture the page's main-frame AX document + per-step ref table.
|
|
72
|
+
*
|
|
73
|
+
* @returns `{ doc, refTable }`, or `null` when the tree is empty or capture
|
|
74
|
+
* fails (never throws).
|
|
75
|
+
*/
|
|
76
|
+
export async function captureAxTree(page) {
|
|
77
|
+
let cdp = null;
|
|
78
|
+
try {
|
|
79
|
+
cdp = await page.context().newCDPSession(page);
|
|
80
|
+
const result = (await cdp.send('Accessibility.getFullAXTree', {}));
|
|
81
|
+
const nodes = result.nodes ?? [];
|
|
82
|
+
if (nodes.length === 0)
|
|
83
|
+
return null;
|
|
84
|
+
const byId = new Map();
|
|
85
|
+
for (const node of nodes) {
|
|
86
|
+
const nid = node['nodeId'];
|
|
87
|
+
if (nid)
|
|
88
|
+
byId.set(nid, node);
|
|
89
|
+
}
|
|
90
|
+
const root = nodes.find((n) => !n['parentId']) ?? nodes[0];
|
|
91
|
+
const tree = parseNode(root, byId);
|
|
92
|
+
return serializeAxTree(tree);
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
log.warn(`[autoheal_ax] capture failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
if (cdp) {
|
|
100
|
+
try {
|
|
101
|
+
await cdp.detach();
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
/* ignore */
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=captureAxTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captureAxTree.js","sourceRoot":"","sources":["../../../src/helpers/axTree/captureAxTree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AX-tree capture + serialization for AH2 locator auto-heal (TS mirror of the
|
|
3
|
+
* Python `testmu/_helpers/ax_tree` package).
|
|
4
|
+
*/
|
|
5
|
+
export { serializeAxTree, AX_DOC_MAX_CHARS, TEXT_TRUNCATE_CHARS } from './serializeAxTree.js';
|
|
6
|
+
export type { AxNode, FrameCapture, RefEntry, RefTable } from './serializeAxTree.js';
|
|
7
|
+
export { captureAxTree } from './captureAxTree.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/helpers/axTree/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC9F,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AX-tree capture + serialization for AH2 locator auto-heal (TS mirror of the
|
|
3
|
+
* Python `testmu/_helpers/ax_tree` package).
|
|
4
|
+
*/
|
|
5
|
+
export { serializeAxTree, AX_DOC_MAX_CHARS, TEXT_TRUNCATE_CHARS } from './serializeAxTree.js';
|
|
6
|
+
export { captureAxTree } from './captureAxTree.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/helpers/axTree/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE9F,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AX-tree text serializer producing a greppable doc + per-step ref table.
|
|
3
|
+
*
|
|
4
|
+
* Byte-faithful TS port of the Python binding's
|
|
5
|
+
* `testmu/_helpers/ax_tree/_serializer.py` (`serialize_ax_tree`). The SAME
|
|
6
|
+
* `(doc, refTable)` format is consumed by the v16-server + controller
|
|
7
|
+
* (`/api/v1/AH2/autoheal` reads `doc`; the binding resolves refs off
|
|
8
|
+
* `refTable`), so the `e<N>` line format and refTable shape MUST stay
|
|
9
|
+
* byte-identical across both bindings.
|
|
10
|
+
*
|
|
11
|
+
* Pure — no I/O. The caller (`captureAxTree`) captures the `AxNode` tree via
|
|
12
|
+
* CDP before calling this.
|
|
13
|
+
*
|
|
14
|
+
* Frame-aware merge is ported whole (`frameChildren`): when the walk hits an
|
|
15
|
+
* `iframe`-role node it looks it up by the owning node's OWN backendDomNodeId
|
|
16
|
+
* (stable identity, never positional) and inlines the matched frame's content
|
|
17
|
+
* one indent deeper, marking `[frame f<N>]` on the owner line. Passing no
|
|
18
|
+
* `frameChildren` (or `[]`) reproduces the single-tree output byte-for-byte —
|
|
19
|
+
* the v1 `captureAxTree` is main-frame-only and always calls it that way; the
|
|
20
|
+
* merge machinery is here so the doc/refTable format is identical to Python's
|
|
21
|
+
* frame-aware output when OOPIF capture lands (documented follow-up).
|
|
22
|
+
*/
|
|
23
|
+
export declare const AX_DOC_MAX_CHARS = 500000;
|
|
24
|
+
export declare const TEXT_TRUNCATE_CHARS = 200;
|
|
25
|
+
/**
|
|
26
|
+
* Duck-typed accessibility node — only the fields the serializer READS. Built
|
|
27
|
+
* from CDP by `captureAxTree`; mirrors the Python `AxNode` attributes the
|
|
28
|
+
* serializer duck-types on.
|
|
29
|
+
*/
|
|
30
|
+
export interface AxNode {
|
|
31
|
+
role: string;
|
|
32
|
+
name: string;
|
|
33
|
+
children: AxNode[];
|
|
34
|
+
backendDomNodeId: number | null;
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
checked?: boolean | string | null;
|
|
37
|
+
expanded?: boolean | null;
|
|
38
|
+
selected?: boolean | null;
|
|
39
|
+
pressed?: boolean | string | null;
|
|
40
|
+
focused?: boolean;
|
|
41
|
+
required?: boolean;
|
|
42
|
+
readonly?: boolean;
|
|
43
|
+
level?: number | null;
|
|
44
|
+
url?: string | null;
|
|
45
|
+
value?: string | null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Capture result for one iframe (mirrors Python `FrameCapture`). `status` is
|
|
49
|
+
* one of "captured" | "hidden" | "capture_failed" | "depth_exceeded" |
|
|
50
|
+
* "unresolved". `tree` is populated only when captured. `ownerBackendNodeId`
|
|
51
|
+
* is the owning iframe AX node's backendDomNodeId — the stable key the walk
|
|
52
|
+
* matches on (never positional).
|
|
53
|
+
*/
|
|
54
|
+
export interface FrameCapture {
|
|
55
|
+
frameId: string;
|
|
56
|
+
status: string;
|
|
57
|
+
tree?: AxNode | null;
|
|
58
|
+
children?: FrameCapture[];
|
|
59
|
+
ownerBackendNodeId?: number | null;
|
|
60
|
+
}
|
|
61
|
+
export interface RefEntry {
|
|
62
|
+
backend_dom_node_id: number | null;
|
|
63
|
+
role: string;
|
|
64
|
+
name: string;
|
|
65
|
+
frame_id: string;
|
|
66
|
+
}
|
|
67
|
+
export type RefTable = Record<string, RefEntry>;
|
|
68
|
+
/**
|
|
69
|
+
* Serialize an accessibility tree into a greppable text doc + ref table.
|
|
70
|
+
*
|
|
71
|
+
* @param root The tree to walk (main frame).
|
|
72
|
+
* @param frameChildren Ordered FrameCaptures for iframes directly owned by
|
|
73
|
+
* `root`'s tree. `undefined`/`[]` reproduces single-tree output exactly.
|
|
74
|
+
* @returns `{ doc, refTable }` — `doc` one line per node; `refTable` maps each
|
|
75
|
+
* `e<N>` to `{ backend_dom_node_id, role, name, frame_id }` (`frame_id` is
|
|
76
|
+
* "" for the main frame).
|
|
77
|
+
*/
|
|
78
|
+
export declare function serializeAxTree(root: AxNode, frameChildren?: FrameCapture[] | null): {
|
|
79
|
+
doc: string;
|
|
80
|
+
refTable: RefTable;
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=serializeAxTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serializeAxTree.d.ts","sourceRoot":"","sources":["../../../src/helpers/axTree/serializeAxTree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAUH,eAAO,MAAM,gBAAgB,SAAU,CAAC;AACxC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAQvC;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,QAAQ;IACvB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAoDhD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,aAAa,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI,GACpC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAyGrC"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AX-tree text serializer producing a greppable doc + per-step ref table.
|
|
3
|
+
*
|
|
4
|
+
* Byte-faithful TS port of the Python binding's
|
|
5
|
+
* `testmu/_helpers/ax_tree/_serializer.py` (`serialize_ax_tree`). The SAME
|
|
6
|
+
* `(doc, refTable)` format is consumed by the v16-server + controller
|
|
7
|
+
* (`/api/v1/AH2/autoheal` reads `doc`; the binding resolves refs off
|
|
8
|
+
* `refTable`), so the `e<N>` line format and refTable shape MUST stay
|
|
9
|
+
* byte-identical across both bindings.
|
|
10
|
+
*
|
|
11
|
+
* Pure — no I/O. The caller (`captureAxTree`) captures the `AxNode` tree via
|
|
12
|
+
* CDP before calling this.
|
|
13
|
+
*
|
|
14
|
+
* Frame-aware merge is ported whole (`frameChildren`): when the walk hits an
|
|
15
|
+
* `iframe`-role node it looks it up by the owning node's OWN backendDomNodeId
|
|
16
|
+
* (stable identity, never positional) and inlines the matched frame's content
|
|
17
|
+
* one indent deeper, marking `[frame f<N>]` on the owner line. Passing no
|
|
18
|
+
* `frameChildren` (or `[]`) reproduces the single-tree output byte-for-byte —
|
|
19
|
+
* the v1 `captureAxTree` is main-frame-only and always calls it that way; the
|
|
20
|
+
* merge machinery is here so the doc/refTable format is identical to Python's
|
|
21
|
+
* frame-aware output when OOPIF capture lands (documented follow-up).
|
|
22
|
+
*/
|
|
23
|
+
/** The AX role Chrome assigns an <iframe>/<frame> element (compared lowercased). */
|
|
24
|
+
const FRAME_ROLE = 'iframe';
|
|
25
|
+
/** Pathology backstop, interpolated into the depth_exceeded note (mirrors Python). */
|
|
26
|
+
const FRAME_DEPTH_BACKSTOP = 10;
|
|
27
|
+
/** Structural/container roles carrying no info: skipped, children promoted to the same depth. */
|
|
28
|
+
const SKIP_ROLES = new Set(['none', 'generic', 'rootwebarea', 'webarea', 'inlinetextbox']);
|
|
29
|
+
export const AX_DOC_MAX_CHARS = 500_000;
|
|
30
|
+
export const TEXT_TRUNCATE_CHARS = 200;
|
|
31
|
+
const TRUNCATION_MARKER = '…[document truncated]';
|
|
32
|
+
// Column layout: "e<N>" + BASE_GAP spaces + (INDENT_PER_DEPTH * depth) spaces + role.
|
|
33
|
+
const BASE_GAP = 3;
|
|
34
|
+
const INDENT_PER_DEPTH = 2;
|
|
35
|
+
/** Index a level's FrameCaptures by their OWNER backendDomNodeId (drops null owners). */
|
|
36
|
+
function indexByOwner(frameChildren) {
|
|
37
|
+
const m = new Map();
|
|
38
|
+
for (const fc of frameChildren) {
|
|
39
|
+
if (fc.ownerBackendNodeId != null)
|
|
40
|
+
m.set(fc.ownerBackendNodeId, fc);
|
|
41
|
+
}
|
|
42
|
+
return m;
|
|
43
|
+
}
|
|
44
|
+
/** Truncate a name/value string at TEXT_TRUNCATE_CHARS, marking cuts with '…'. */
|
|
45
|
+
function truncate(text) {
|
|
46
|
+
if (text.length > TEXT_TRUNCATE_CHARS)
|
|
47
|
+
return text.slice(0, TEXT_TRUNCATE_CHARS) + '…';
|
|
48
|
+
return text;
|
|
49
|
+
}
|
|
50
|
+
/** Render sparse state tags in the fixed order required by the spec. */
|
|
51
|
+
function renderStates(node) {
|
|
52
|
+
const states = [];
|
|
53
|
+
if (node.disabled)
|
|
54
|
+
states.push('[disabled]');
|
|
55
|
+
if (node.checked === 'mixed')
|
|
56
|
+
states.push('[checked=mixed]');
|
|
57
|
+
else if (node.checked === true)
|
|
58
|
+
states.push('[checked]');
|
|
59
|
+
else if (node.checked === false)
|
|
60
|
+
states.push('[unchecked]');
|
|
61
|
+
if (node.expanded === true)
|
|
62
|
+
states.push('[expanded]');
|
|
63
|
+
else if (node.expanded === false)
|
|
64
|
+
states.push('[collapsed]');
|
|
65
|
+
if (node.selected)
|
|
66
|
+
states.push('[selected]');
|
|
67
|
+
if (node.pressed === 'mixed')
|
|
68
|
+
states.push('[pressed=mixed]');
|
|
69
|
+
else if (node.pressed === true)
|
|
70
|
+
states.push('[pressed]');
|
|
71
|
+
else if (node.pressed === false)
|
|
72
|
+
states.push('[unpressed]');
|
|
73
|
+
if (node.focused)
|
|
74
|
+
states.push('[focused]');
|
|
75
|
+
if (node.required)
|
|
76
|
+
states.push('[required]');
|
|
77
|
+
if (node.readonly)
|
|
78
|
+
states.push('[readonly]');
|
|
79
|
+
return states;
|
|
80
|
+
}
|
|
81
|
+
/** Render one doc line for an already-normalized (non-skipped) role. */
|
|
82
|
+
function renderLine(ref, depth, role, node) {
|
|
83
|
+
const gap = ' '.repeat(BASE_GAP + INDENT_PER_DEPTH * depth);
|
|
84
|
+
const name = truncate(node.name || '');
|
|
85
|
+
const extras = renderStates(node);
|
|
86
|
+
if (role === 'heading' && node.level != null)
|
|
87
|
+
extras.push(`level=${node.level}`);
|
|
88
|
+
else if (node.url)
|
|
89
|
+
extras.push(`url=${node.url}`);
|
|
90
|
+
if (node.value)
|
|
91
|
+
extras.push(`{value=${truncate(node.value)}}`);
|
|
92
|
+
let line = `${ref}${gap}${role} "${name}"`;
|
|
93
|
+
if (extras.length)
|
|
94
|
+
line += ' ' + extras.join(' ');
|
|
95
|
+
return line;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Serialize an accessibility tree into a greppable text doc + ref table.
|
|
99
|
+
*
|
|
100
|
+
* @param root The tree to walk (main frame).
|
|
101
|
+
* @param frameChildren Ordered FrameCaptures for iframes directly owned by
|
|
102
|
+
* `root`'s tree. `undefined`/`[]` reproduces single-tree output exactly.
|
|
103
|
+
* @returns `{ doc, refTable }` — `doc` one line per node; `refTable` maps each
|
|
104
|
+
* `e<N>` to `{ backend_dom_node_id, role, name, frame_id }` (`frame_id` is
|
|
105
|
+
* "" for the main frame).
|
|
106
|
+
*/
|
|
107
|
+
export function serializeAxTree(root, frameChildren) {
|
|
108
|
+
const lines = [];
|
|
109
|
+
const refTable = {};
|
|
110
|
+
const state = { ref: 0, length: 0, truncated: false, frameNum: 0 };
|
|
111
|
+
function appendLine(line) {
|
|
112
|
+
const addedLen = line.length + (lines.length ? 1 : 0); // +1 for the joining newline
|
|
113
|
+
const charBudget = AX_DOC_MAX_CHARS - TRUNCATION_MARKER.length - 1;
|
|
114
|
+
if (state.length + addedLen > charBudget) {
|
|
115
|
+
state.truncated = true;
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
lines.push(line);
|
|
119
|
+
state.length += addedLen;
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
function renderFrame(fc, depth, frameNum) {
|
|
123
|
+
const gap = ' '.repeat(BASE_GAP + INDENT_PER_DEPTH * depth);
|
|
124
|
+
if (fc.status === 'unresolved') {
|
|
125
|
+
appendLine(`${gap}[frame ? unresolved — not captured]`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (fc.status === 'hidden') {
|
|
129
|
+
appendLine(`${gap}[frame f${frameNum} hidden — not captured]`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (fc.status === 'depth_exceeded') {
|
|
133
|
+
appendLine(`${gap}[frame f${frameNum} not captured — depth exceeds ${FRAME_DEPTH_BACKSTOP}]`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (fc.status !== 'captured' || fc.tree == null) {
|
|
137
|
+
appendLine(`${gap}[frame f${frameNum} capture failed]`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const childrenByOwner = indexByOwner(fc.children ?? []);
|
|
141
|
+
walk(fc.tree, depth, fc.frameId, childrenByOwner);
|
|
142
|
+
}
|
|
143
|
+
function walk(node, depth, frameId, frameChildrenByOwner) {
|
|
144
|
+
if (state.truncated)
|
|
145
|
+
return;
|
|
146
|
+
const role = (node.role || '').trim().toLowerCase();
|
|
147
|
+
if (!role || SKIP_ROLES.has(role)) {
|
|
148
|
+
for (const child of node.children) {
|
|
149
|
+
walk(child, depth, frameId, frameChildrenByOwner);
|
|
150
|
+
if (state.truncated)
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
state.ref += 1;
|
|
156
|
+
const ref = `e${state.ref}`;
|
|
157
|
+
// Matched by the iframe node's OWN backendDomNodeId (stable identity),
|
|
158
|
+
// never by consuming an iterator positionally.
|
|
159
|
+
const fc = role === FRAME_ROLE && node.backendDomNodeId != null
|
|
160
|
+
? frameChildrenByOwner.get(node.backendDomNodeId)
|
|
161
|
+
: undefined;
|
|
162
|
+
// Display number minted HERE, in document order — never carried in.
|
|
163
|
+
let frameNum = 0;
|
|
164
|
+
if (fc !== undefined) {
|
|
165
|
+
state.frameNum += 1;
|
|
166
|
+
frameNum = state.frameNum;
|
|
167
|
+
}
|
|
168
|
+
let line = renderLine(ref, depth, role, node);
|
|
169
|
+
if (fc !== undefined) {
|
|
170
|
+
line += fc.status === 'unresolved' ? ' [frame ?]' : ` [frame f${frameNum}]`;
|
|
171
|
+
}
|
|
172
|
+
if (!appendLine(line))
|
|
173
|
+
return;
|
|
174
|
+
refTable[ref] = {
|
|
175
|
+
backend_dom_node_id: node.backendDomNodeId,
|
|
176
|
+
role,
|
|
177
|
+
// Stripped at the source: downstream locator-enrichment strips the name
|
|
178
|
+
// before comparing against the DOM's accessible name.
|
|
179
|
+
name: (node.name || '').trim(),
|
|
180
|
+
frame_id: frameId,
|
|
181
|
+
};
|
|
182
|
+
if (fc !== undefined) {
|
|
183
|
+
renderFrame(fc, depth + 1, frameNum);
|
|
184
|
+
if (state.truncated)
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
for (const child of node.children) {
|
|
188
|
+
walk(child, depth + 1, frameId, frameChildrenByOwner);
|
|
189
|
+
if (state.truncated)
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
walk(root, 0, '', indexByOwner(frameChildren ?? []));
|
|
194
|
+
let doc = lines.join('\n');
|
|
195
|
+
if (state.truncated)
|
|
196
|
+
doc = doc ? `${doc}\n${TRUNCATION_MARKER}` : TRUNCATION_MARKER;
|
|
197
|
+
return { doc, refTable };
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=serializeAxTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serializeAxTree.js","sourceRoot":"","sources":["../../../src/helpers/axTree/serializeAxTree.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,5 +13,5 @@ import type { Page } from 'playwright';
|
|
|
13
13
|
export interface HealOutcome {
|
|
14
14
|
value: string;
|
|
15
15
|
}
|
|
16
|
-
export declare function runHeal(page: Page, query: string, expectedValue: string | null, needsUnitConversion: boolean, condition?: string | null): Promise<HealOutcome | null>;
|
|
16
|
+
export declare function runHeal(page: Page, query: string, expectedValue: string | null, needsUnitConversion: boolean, condition?: string | null, previousCode?: string | null): Promise<HealOutcome | null>;
|
|
17
17
|
//# sourceMappingURL=heal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heal.d.ts","sourceRoot":"","sources":["../../../src/helpers/textualAnalyzer/heal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,YAAY,CAAC;AAWtD,MAAM,WAAW,WAAW;IAK1B,KAAK,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"heal.d.ts","sourceRoot":"","sources":["../../../src/helpers/textualAnalyzer/heal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,YAAY,CAAC;AAWtD,MAAM,WAAW,WAAW;IAK1B,KAAK,EAAE,MAAM,CAAC;CACf;AAyCD,wBAAsB,OAAO,CAC3B,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,EAAE,mBAAmB,EAAE,OAAO,EACrF,SAAS,GAAE,MAAM,GAAG,IAAW,EAAE,YAAY,GAAE,MAAM,GAAG,IAAW,GAClE,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAwC7B"}
|
|
@@ -9,7 +9,7 @@ const HEAL_TIMEOUT_MS = 60_000;
|
|
|
9
9
|
function healUrl() {
|
|
10
10
|
return config.current.aiApiHost.replace(/\/+$/, '') + '/api/v1/textual_analyzer/heal';
|
|
11
11
|
}
|
|
12
|
-
async function postHeal(query, domSnapshot, expectedValue, needsUnit, condition = null) {
|
|
12
|
+
async function postHeal(query, domSnapshot, expectedValue, needsUnit, condition = null, previousCode = null) {
|
|
13
13
|
const body = {
|
|
14
14
|
query,
|
|
15
15
|
dom_snapshot: domSnapshot,
|
|
@@ -18,6 +18,9 @@ async function postHeal(query, domSnapshot, expectedValue, needsUnit, condition
|
|
|
18
18
|
// Checkpoint condition drives in-code derivation on regen; without it the
|
|
19
19
|
// heal would return a raw read for a derived (arithmetic/boolean) step.
|
|
20
20
|
condition: condition ?? '',
|
|
21
|
+
// v3 re-anchoring: the recorded working code. Old servers ignore unknown
|
|
22
|
+
// keys; old recordings pass null -> '' (blind regen, unchanged).
|
|
23
|
+
previous_code: previousCode ?? '',
|
|
21
24
|
};
|
|
22
25
|
try {
|
|
23
26
|
const resp = await fetchWithAuth(healUrl(), {
|
|
@@ -38,11 +41,11 @@ async function postHeal(query, domSnapshot, expectedValue, needsUnit, condition
|
|
|
38
41
|
return null;
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
|
-
export async function runHeal(page, query, expectedValue, needsUnitConversion, condition = null) {
|
|
44
|
+
export async function runHeal(page, query, expectedValue, needsUnitConversion, condition = null, previousCode = null) {
|
|
42
45
|
const structured = await captureStructuredDom(page);
|
|
43
46
|
if (structured == null || !structured.text)
|
|
44
47
|
return null;
|
|
45
|
-
const resp = await postHeal(query, structured.text, expectedValue, needsUnitConversion, condition);
|
|
48
|
+
const resp = await postHeal(query, structured.text, expectedValue, needsUnitConversion, condition, previousCode);
|
|
46
49
|
if (!resp || !resp['code'])
|
|
47
50
|
return null;
|
|
48
51
|
const code = String(resp['code']);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heal.js","sourceRoot":"","sources":["../../../src/helpers/textualAnalyzer/heal.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,MAAM,eAAe,GAAG,MAAM,CAAC;AAU/B,SAAS,OAAO;IACd,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,+BAA+B,CAAC;AACxF,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,KAAa,EAAE,WAAmB,EAAE,aAA4B,EAAE,SAAkB,EACpF,YAA2B,IAAI;
|
|
1
|
+
{"version":3,"file":"heal.js","sourceRoot":"","sources":["../../../src/helpers/textualAnalyzer/heal.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,MAAM,eAAe,GAAG,MAAM,CAAC;AAU/B,SAAS,OAAO;IACd,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,+BAA+B,CAAC;AACxF,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,KAAa,EAAE,WAAmB,EAAE,aAA4B,EAAE,SAAkB,EACpF,YAA2B,IAAI,EAAE,eAA8B,IAAI;IAEnE,MAAM,IAAI,GAAG;QACX,KAAK;QACL,YAAY,EAAE,WAAW;QACzB,cAAc,EAAE,aAAa;QAC7B,qBAAqB,EAAE,SAAS;QAChC,0EAA0E;QAC1E,wEAAwE;QACxE,SAAS,EAAE,SAAS,IAAI,EAAE;QAC1B,yEAAyE;QACzE,iEAAiE;QACjE,aAAa,EAAE,YAAY,IAAI,EAAE;KAClC,CAAC;IACF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,eAAe,CAAC;SAC7C,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,iEAAiE;YACjE,GAAG,CAAC,MAAM,CAAC,oCAAoC,OAAO,EAAE,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9E,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAA4B,CAAC;IACxD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,IAAI,CAAC,wCAAwC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/F,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,IAAU,EAAE,KAAa,EAAE,aAA4B,EAAE,mBAA4B,EACrF,YAA2B,IAAI,EAAE,eAA8B,IAAI;IAEnE,MAAM,UAAU,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,UAAU,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAExD,MAAM,IAAI,GAAG,MAAM,QAAQ,CACzB,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,mBAAmB,EAAE,SAAS,EAAE,YAAY,CACpF,CAAC;IACF,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAExC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAExC,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,CAAC;QACH,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,GAAG,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAC;YAC7B,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;YAC5E,MAAM,GAAG,GAAG,QAAQ,EAAE,OAAO,CAAC;YAC9B,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,aAAa,EAAE,CAAC;YAC/D,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YAAC,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjD,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,IAAI,CAAC,4CAA4C,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACnG,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC,CAAC,gCAAgC;IAEhF,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/helpers/textualAnalyzer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,YAAY,CAAC;AAStD,qBAAa,yBAA0B,SAAQ,KAAK;CAAG;AAEvD,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/helpers/textualAnalyzer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,YAAY,CAAC;AAStD,qBAAa,yBAA0B,SAAQ,KAAK;CAAG;AAEvD,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAsBD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA2BtG"}
|
|
@@ -31,7 +31,7 @@ async function staleAndHandles(page, locators) {
|
|
|
31
31
|
* Returns the extracted value (string; transforms applied downstream as today).
|
|
32
32
|
*/
|
|
33
33
|
export async function textualAnalyzer(page, opts) {
|
|
34
|
-
const { wrappedJs, locators, query, expectedValue = null, needsUnitConversion = false, condition = null } = opts;
|
|
34
|
+
const { wrappedJs, locators, query, expectedValue = null, needsUnitConversion = false, condition = null, codeJs = null, } = opts;
|
|
35
35
|
const { stale, handles } = await staleAndHandles(page, locators);
|
|
36
36
|
// Happy path — every recorded locator visible.
|
|
37
37
|
if (stale.length === 0 && handles.length === locators.length) {
|
|
@@ -40,7 +40,7 @@ export async function textualAnalyzer(page, opts) {
|
|
|
40
40
|
// Drift — regenerate the whole extraction.
|
|
41
41
|
log.helper(`[textual_analyzer] ${stale.length}/${locators.length} locators not visible -> heal ` +
|
|
42
42
|
`(query=${repr(preview(query, 60).replace(/\.\.\.$/, ''))})`);
|
|
43
|
-
const outcome = await runHeal(page, query, expectedValue, needsUnitConversion, condition);
|
|
43
|
+
const outcome = await runHeal(page, query, expectedValue, needsUnitConversion, condition, codeJs);
|
|
44
44
|
if (outcome == null) {
|
|
45
45
|
throw new TextualAnalyzerHealFailed(`textualAnalyzer could not heal extraction for query=${repr(query)}; stale locators: ${JSON.stringify(stale)}`);
|
|
46
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/helpers/textualAnalyzer/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,gFAAgF;AAChF,iFAAiF;AACjF,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,MAAM,OAAO,yBAA0B,SAAQ,KAAK;CAAG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/helpers/textualAnalyzer/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,gFAAgF;AAChF,iFAAiF;AACjF,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,MAAM,OAAO,yBAA0B,SAAQ,KAAK;CAAG;AAcvD,KAAK,UAAU,eAAe,CAC5B,IAAU,EAAE,QAAkB;IAE9B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;QACzC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;YACxE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;YAC5C,IAAI,MAAM,IAAI,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;gBAC/B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;YACnC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAU,EAAE,IAA4B;IAC5E,MAAM,EACJ,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,EAAE,mBAAmB,GAAG,KAAK,EAC7E,SAAS,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,GAChC,GAAG,IAAI,CAAC;IAET,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAEjE,+CAA+C;IAC/C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC7D,OAAO,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAkB,CAAC;IAC5E,CAAC;IAED,2CAA2C;IAC3C,GAAG,CAAC,MAAM,CACR,sBAAsB,KAAK,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,gCAAgC;QACrF,UAAU,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAC7D,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAClG,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,yBAAyB,CACjC,uDAAuD,IAAI,CAAC,KAAK,CAAC,qBAAqB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAC/G,CAAC;IACJ,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,8CAA8C,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChF,OAAO,OAAO,CAAC,KAAK,CAAC;AACvB,CAAC"}
|