@testmuai/playwright-bindings 0.1.26 → 0.1.27
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/actionEngine.d.ts +37 -0
- package/dist/actionEngine.d.ts.map +1 -0
- package/dist/actionEngine.js +194 -0
- package/dist/actionEngine.js.map +1 -0
- package/dist/actionSpecs.d.ts +35 -0
- package/dist/actionSpecs.d.ts.map +1 -0
- package/dist/actionSpecs.js +354 -0
- package/dist/actionSpecs.js.map +1 -0
- package/dist/capability.d.ts +3 -5
- package/dist/capability.d.ts.map +1 -1
- package/dist/capability.js +66 -6
- package/dist/capability.js.map +1 -1
- package/dist/configure.d.ts +16 -0
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +14 -0
- package/dist/configure.js.map +1 -1
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +29 -0
- package/dist/errors.js.map +1 -1
- package/dist/healCache.d.ts +28 -0
- package/dist/healCache.d.ts.map +1 -0
- package/dist/healCache.js +17 -0
- package/dist/healCache.js.map +1 -0
- package/dist/healPatch.d.ts.map +1 -1
- package/dist/healPatch.js +45 -3
- package/dist/healPatch.js.map +1 -1
- package/dist/helpers/assertion.d.ts.map +1 -1
- package/dist/helpers/assertion.js +18 -0
- package/dist/helpers/assertion.js.map +1 -1
- package/dist/helpers/assertionV3.d.ts +67 -0
- package/dist/helpers/assertionV3.d.ts.map +1 -0
- package/dist/helpers/assertionV3.js +384 -0
- package/dist/helpers/assertionV3.js.map +1 -0
- package/dist/helpers/condition.d.ts +84 -0
- package/dist/helpers/condition.d.ts.map +1 -0
- package/dist/helpers/condition.js +292 -0
- package/dist/helpers/condition.js.map +1 -0
- package/dist/helpers/cookies.d.ts +12 -0
- package/dist/helpers/cookies.d.ts.map +1 -0
- package/dist/helpers/cookies.js +66 -0
- package/dist/helpers/cookies.js.map +1 -0
- package/dist/helpers/coordinateResolver.d.ts +29 -0
- package/dist/helpers/coordinateResolver.d.ts.map +1 -0
- package/dist/helpers/coordinateResolver.js +118 -0
- package/dist/helpers/coordinateResolver.js.map +1 -0
- package/dist/helpers/coordinateResolverRead.d.ts +36 -0
- package/dist/helpers/coordinateResolverRead.d.ts.map +1 -0
- package/dist/helpers/coordinateResolverRead.js +107 -0
- package/dist/helpers/coordinateResolverRead.js.map +1 -0
- package/dist/helpers/dialog.d.ts +29 -0
- package/dist/helpers/dialog.d.ts.map +1 -0
- package/dist/helpers/dialog.js +35 -0
- package/dist/helpers/dialog.js.map +1 -0
- package/dist/helpers/drag.d.ts +36 -1
- package/dist/helpers/drag.d.ts.map +1 -1
- package/dist/helpers/drag.js +267 -0
- package/dist/helpers/drag.js.map +1 -1
- package/dist/helpers/executeApi.d.ts +2 -0
- package/dist/helpers/executeApi.d.ts.map +1 -1
- package/dist/helpers/executeApi.js +30 -10
- package/dist/helpers/executeApi.js.map +1 -1
- package/dist/helpers/executeJs.d.ts.map +1 -1
- package/dist/helpers/executeJs.js +46 -3
- package/dist/helpers/executeJs.js.map +1 -1
- package/dist/helpers/gesture.d.ts +45 -0
- package/dist/helpers/gesture.d.ts.map +1 -0
- package/dist/helpers/gesture.js +131 -0
- package/dist/helpers/gesture.js.map +1 -0
- package/dist/helpers/healCascade.d.ts +57 -0
- package/dist/helpers/healCascade.d.ts.map +1 -0
- package/dist/helpers/healCascade.js +363 -0
- package/dist/helpers/healCascade.js.map +1 -0
- package/dist/helpers/png.d.ts +3 -0
- package/dist/helpers/png.d.ts.map +1 -0
- package/dist/helpers/png.js +18 -0
- package/dist/helpers/png.js.map +1 -0
- package/dist/helpers/screenshot.d.ts +27 -0
- package/dist/helpers/screenshot.d.ts.map +1 -1
- package/dist/helpers/screenshot.js +56 -0
- package/dist/helpers/screenshot.js.map +1 -1
- package/dist/helpers/scrollUntil.d.ts +13 -0
- package/dist/helpers/scrollUntil.d.ts.map +1 -0
- package/dist/helpers/scrollUntil.js +88 -0
- package/dist/helpers/scrollUntil.js.map +1 -0
- package/dist/helpers/tabs.d.ts +42 -1
- package/dist/helpers/tabs.d.ts.map +1 -1
- package/dist/helpers/tabs.js +259 -5
- package/dist/helpers/tabs.js.map +1 -1
- package/dist/helpers/text.d.ts +15 -0
- package/dist/helpers/text.d.ts.map +1 -0
- package/dist/helpers/text.js +24 -0
- package/dist/helpers/text.js.map +1 -0
- package/dist/helpers/textNormalize.d.ts +18 -0
- package/dist/helpers/textNormalize.d.ts.map +1 -0
- package/dist/helpers/textNormalize.js +39 -0
- package/dist/helpers/textNormalize.js.map +1 -0
- package/dist/helpers/textualRead.d.ts +37 -0
- package/dist/helpers/textualRead.d.ts.map +1 -0
- package/dist/helpers/textualRead.js +211 -0
- package/dist/helpers/textualRead.js.map +1 -0
- package/dist/helpers/vision.d.ts +2 -0
- package/dist/helpers/vision.d.ts.map +1 -1
- package/dist/helpers/vision.js +11 -0
- package/dist/helpers/vision.js.map +1 -1
- package/dist/helpers/visionV3.d.ts +38 -0
- package/dist/helpers/visionV3.d.ts.map +1 -0
- package/dist/helpers/visionV3.js +291 -0
- package/dist/helpers/visionV3.js.map +1 -0
- package/dist/helpers/wait.d.ts +14 -1
- package/dist/helpers/wait.d.ts.map +1 -1
- package/dist/helpers/wait.js +25 -0
- package/dist/helpers/wait.js.map +1 -1
- package/dist/index.d.ts +29 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -4
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts +4 -1
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +8 -3
- package/dist/log.js.map +1 -1
- package/dist/rankedLocator.d.ts +27 -0
- package/dist/rankedLocator.d.ts.map +1 -0
- package/dist/rankedLocator.js +85 -0
- package/dist/rankedLocator.js.map +1 -0
- package/dist/reporters/index.d.ts +2 -0
- package/dist/reporters/index.d.ts.map +1 -1
- package/dist/reporters/index.js.map +1 -1
- package/dist/reporters/lt.d.ts.map +1 -1
- package/dist/reporters/lt.js +7 -1
- package/dist/reporters/lt.js.map +1 -1
- package/dist/routeFailure.d.ts +9 -0
- package/dist/routeFailure.d.ts.map +1 -0
- package/dist/routeFailure.js +34 -0
- package/dist/routeFailure.js.map +1 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +21 -0
- package/dist/session.js.map +1 -1
- package/dist/step.d.ts +10 -0
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +14 -1
- package/dist/step.js.map +1 -1
- package/dist/testConfig.d.ts.map +1 -1
- package/dist/testConfig.js +8 -1
- package/dist/testConfig.js.map +1 -1
- package/dist/vars.d.ts +10 -0
- package/dist/vars.d.ts.map +1 -1
- package/dist/vars.js +30 -3
- package/dist/vars.js.map +1 -1
- package/dist/visionLocator.d.ts +53 -0
- package/dist/visionLocator.d.ts.map +1 -0
- package/dist/visionLocator.js +117 -0
- package/dist/visionLocator.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Condition classes for test evaluation — the V3 local-eval core.
|
|
3
|
+
*
|
|
4
|
+
* Port of PY testmu/_helpers/condition.py (itself ported from the Selenium
|
|
5
|
+
* binding). Consumed by exported test.js as LIVE OBJECTS — never a
|
|
6
|
+
* stringified repr the binding evals (the V3 PW-JS contract's deliberate
|
|
7
|
+
* divergence; eval under ESM is bundler- and CSP-hostile):
|
|
8
|
+
*
|
|
9
|
+
* const [ok] = await new Condition({
|
|
10
|
+
* conditions: [new ResolvedCondition('{{x}}', PossibleCondition('=='), '5')],
|
|
11
|
+
* connectors: [],
|
|
12
|
+
* }).evaluate();
|
|
13
|
+
*
|
|
14
|
+
* PossibleCondition is a CALLABLE const-object, not a TS enum: Python enums
|
|
15
|
+
* are callable by value, and the generator emits PossibleCondition('==') in
|
|
16
|
+
* both languages — a TS enum cannot keep that emission shape.
|
|
17
|
+
*
|
|
18
|
+
* Day-1 corner cases baked in (skill catalog Top-15):
|
|
19
|
+
* #3 connector fold combines the accumulator with results[i+1];
|
|
20
|
+
* #4 CONTAINS means right-in-left (left is the haystack);
|
|
21
|
+
* unknown operators/connectors THROW — never a silent wrong verdict.
|
|
22
|
+
*/
|
|
23
|
+
import { isV3 } from '../configure.js';
|
|
24
|
+
import { normalizeText } from './textNormalize.js';
|
|
25
|
+
import { resolveVar } from '../vars.js';
|
|
26
|
+
// ── Operators ─────────────────────────────────────────────────────────────────
|
|
27
|
+
const POSSIBLE_CONDITION_VALUES = [
|
|
28
|
+
'==', '!=', '>', '<', '>=', '<=',
|
|
29
|
+
'contains', 'not_contains', 'starts_with', 'ends_with',
|
|
30
|
+
];
|
|
31
|
+
function possibleConditionFn(raw) {
|
|
32
|
+
const v = raw;
|
|
33
|
+
// No fallback: an unrecognized operator must throw rather than silently
|
|
34
|
+
// defaulting to EQUALS and producing a wrong verdict (PY parity).
|
|
35
|
+
if (!POSSIBLE_CONDITION_VALUES.includes(v)) {
|
|
36
|
+
throw new Error(`'${raw}' is not a valid PossibleCondition`);
|
|
37
|
+
}
|
|
38
|
+
return v;
|
|
39
|
+
}
|
|
40
|
+
export const PossibleCondition = Object.assign(possibleConditionFn, {
|
|
41
|
+
EQUALS: '==', NOT_EQUALS: '!=',
|
|
42
|
+
GREATER_THAN: '>', LESS_THAN: '<',
|
|
43
|
+
GREATER_THAN_OR_EQUALS: '>=', LESS_THAN_OR_EQUALS: '<=',
|
|
44
|
+
CONTAINS: 'contains', NOT_CONTAINS: 'not_contains',
|
|
45
|
+
STARTS_WITH: 'starts_with', ENDS_WITH: 'ends_with',
|
|
46
|
+
});
|
|
47
|
+
function concatenationOperatorFn(raw) {
|
|
48
|
+
const v = raw.toUpperCase();
|
|
49
|
+
if (v !== 'AND' && v !== 'OR') {
|
|
50
|
+
throw new Error(`'${raw}' is not a valid ConcatenationOperator`);
|
|
51
|
+
}
|
|
52
|
+
return v;
|
|
53
|
+
}
|
|
54
|
+
export const ConcatenationOperator = Object.assign(concatenationOperatorFn, { AND: 'AND', OR: 'OR' });
|
|
55
|
+
// ── ResolvedCondition ─────────────────────────────────────────────────────────
|
|
56
|
+
/** A single comparison triple: left_operand op right_operand. */
|
|
57
|
+
export class ResolvedCondition {
|
|
58
|
+
leftOperand;
|
|
59
|
+
operator;
|
|
60
|
+
rightOperand;
|
|
61
|
+
constructor(leftOperand, operator, rightOperand) {
|
|
62
|
+
this.leftOperand = leftOperand;
|
|
63
|
+
this.operator = operator;
|
|
64
|
+
this.rightOperand = rightOperand;
|
|
65
|
+
}
|
|
66
|
+
toDict() {
|
|
67
|
+
return {
|
|
68
|
+
left_operand: this.leftOperand,
|
|
69
|
+
operator: this.operator,
|
|
70
|
+
right_operand: this.rightOperand,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Parse 'left op right' whitespace-delimited string. */
|
|
74
|
+
static fromString(condition) {
|
|
75
|
+
const parts = condition.split(/\s+/).filter(Boolean);
|
|
76
|
+
if (parts.length !== 3) {
|
|
77
|
+
throw new Error(`Cannot parse condition string: ${JSON.stringify(condition)}`);
|
|
78
|
+
}
|
|
79
|
+
const [left, op, right] = parts;
|
|
80
|
+
return new ResolvedCondition(left, PossibleCondition(op), right);
|
|
81
|
+
}
|
|
82
|
+
static fromJson(json) {
|
|
83
|
+
return new ResolvedCondition(json.left_operand ?? '', PossibleCondition(json.operator ?? ''), json.right_operand ?? '');
|
|
84
|
+
}
|
|
85
|
+
toString() {
|
|
86
|
+
return `${this.leftOperand} ${this.operator} ${this.rightOperand}`;
|
|
87
|
+
}
|
|
88
|
+
equals(other) {
|
|
89
|
+
return (other instanceof ResolvedCondition &&
|
|
90
|
+
this.leftOperand === other.leftOperand &&
|
|
91
|
+
this.operator === other.operator &&
|
|
92
|
+
this.rightOperand === other.rightOperand);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Default resolver: the binding's own variable store (async — ATMS/env). */
|
|
96
|
+
const defaultResolver = (template) => resolveVar(template);
|
|
97
|
+
/**
|
|
98
|
+
* Composite condition: ResolvedConditions joined by ConcatenationOperators.
|
|
99
|
+
* `await cond.evaluate()` returns `[boolean, usedVariables]`.
|
|
100
|
+
*/
|
|
101
|
+
export class Condition {
|
|
102
|
+
conditions;
|
|
103
|
+
connectors;
|
|
104
|
+
isV3;
|
|
105
|
+
constructor(opts) {
|
|
106
|
+
this.conditions = opts.conditions;
|
|
107
|
+
this.connectors = opts.connectors;
|
|
108
|
+
// V3 mode: text ops are case-insensitive + unicode-folded; AND binds
|
|
109
|
+
// tighter than OR (A OR B AND C == A OR (B AND C)). Resolved from the
|
|
110
|
+
// runtime config when not passed — codegen emits bare Condition({...})
|
|
111
|
+
// with no isV3 arg, so this is what makes those pick up V3 semantics.
|
|
112
|
+
this.isV3 = opts.isV3 ?? isV3();
|
|
113
|
+
}
|
|
114
|
+
// ── Internal helpers ────────────────────────────────────────────────────────
|
|
115
|
+
async resolvePlaceholder(s, variables, getVariableValue) {
|
|
116
|
+
if (getVariableValue) {
|
|
117
|
+
const result = await getVariableValue(s, variables);
|
|
118
|
+
return [result, { [s]: result }];
|
|
119
|
+
}
|
|
120
|
+
const t = s.trim();
|
|
121
|
+
if (t.startsWith('{{') && t.endsWith('}}')) {
|
|
122
|
+
const key = t.slice(2, -2).trim();
|
|
123
|
+
return [this.accessNestedValue(variables, key), { [key]: this.accessNestedValue(variables, key) }];
|
|
124
|
+
}
|
|
125
|
+
if (t.startsWith('${') && t.endsWith('}')) {
|
|
126
|
+
const key = t.slice(2, -1).trim();
|
|
127
|
+
return [this.accessNestedValue(variables, key), { [key]: this.accessNestedValue(variables, key) }];
|
|
128
|
+
}
|
|
129
|
+
return [s, {}]; // not a placeholder
|
|
130
|
+
}
|
|
131
|
+
/** Dotted + bracket-indexed traversal ('api_x.response_body.items[0].id'). */
|
|
132
|
+
accessNestedValue(dump, name) {
|
|
133
|
+
let value = dump;
|
|
134
|
+
for (let key of name.split('.')) {
|
|
135
|
+
while (key.includes('[') && key.includes(']')) {
|
|
136
|
+
const base = key.slice(0, key.indexOf('['));
|
|
137
|
+
const index = parseInt(key.slice(key.indexOf('[') + 1, key.indexOf(']')), 10);
|
|
138
|
+
if (base)
|
|
139
|
+
value = value[base];
|
|
140
|
+
value = value[index];
|
|
141
|
+
key = key.slice(key.indexOf(']') + 1);
|
|
142
|
+
}
|
|
143
|
+
if (key) {
|
|
144
|
+
if (value === null || typeof value !== 'object') {
|
|
145
|
+
throw new Error(`Variable '${name}' not found in variables`);
|
|
146
|
+
}
|
|
147
|
+
if (!(key in value)) {
|
|
148
|
+
throw new Error(`Variable '${name}' not found in variables`);
|
|
149
|
+
}
|
|
150
|
+
value = value[key];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return value;
|
|
154
|
+
}
|
|
155
|
+
isNumeric(val) {
|
|
156
|
+
if (typeof val === 'number')
|
|
157
|
+
return Number.isFinite(val);
|
|
158
|
+
if (typeof val === 'string') {
|
|
159
|
+
const t = val.trim();
|
|
160
|
+
if (t === '')
|
|
161
|
+
return false;
|
|
162
|
+
return Number.isFinite(Number(t));
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
toNumeric(val) {
|
|
167
|
+
if (typeof val === 'number')
|
|
168
|
+
return val;
|
|
169
|
+
if (typeof val === 'string') {
|
|
170
|
+
const n = Number(val.trim());
|
|
171
|
+
return Number.isFinite(n) ? n : null;
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
cleanString(s) {
|
|
176
|
+
if ((s.startsWith('"') && s.endsWith('"')) ||
|
|
177
|
+
(s.startsWith("'") && s.endsWith("'"))) {
|
|
178
|
+
return s.slice(1, -1);
|
|
179
|
+
}
|
|
180
|
+
return s;
|
|
181
|
+
}
|
|
182
|
+
/** Coerce mixed string/number operands before comparing (PY parity). */
|
|
183
|
+
typecast(left, right) {
|
|
184
|
+
const leftIsStr = typeof left === 'string';
|
|
185
|
+
const rightIsStr = typeof right === 'string';
|
|
186
|
+
const leftIsNum = this.isNumeric(left);
|
|
187
|
+
const rightIsNum = this.isNumeric(right);
|
|
188
|
+
if (leftIsNum && rightIsNum) {
|
|
189
|
+
return [this.toNumeric(left), this.toNumeric(right)];
|
|
190
|
+
}
|
|
191
|
+
let l = leftIsStr ? this.cleanString(left) : left;
|
|
192
|
+
let r = rightIsStr ? this.cleanString(right) : right;
|
|
193
|
+
if (leftIsStr && rightIsNum && this.isNumeric(l)) {
|
|
194
|
+
l = this.toNumeric(l);
|
|
195
|
+
}
|
|
196
|
+
else if (rightIsStr && leftIsNum && this.isNumeric(r)) {
|
|
197
|
+
r = this.toNumeric(r);
|
|
198
|
+
}
|
|
199
|
+
return [l, r];
|
|
200
|
+
}
|
|
201
|
+
/** Normalize a text operand for substring/prefix/suffix comparison.
|
|
202
|
+
* V3: accent-fold + case-fold; V4: plain String(). */
|
|
203
|
+
cmp(x) {
|
|
204
|
+
return this.isV3 ? normalizeText(x, { caseInsensitive: true }) : String(x);
|
|
205
|
+
}
|
|
206
|
+
evalCondition(operator, leftOperand, rightOperand) {
|
|
207
|
+
let [left, right] = this.typecast(leftOperand, rightOperand);
|
|
208
|
+
// bool <-> "true"/"false" normalization.
|
|
209
|
+
if (typeof left === 'boolean' && typeof right === 'string') {
|
|
210
|
+
const lowered = right.trim().toLowerCase();
|
|
211
|
+
if (lowered === 'true' || lowered === 'false')
|
|
212
|
+
right = lowered === 'true';
|
|
213
|
+
}
|
|
214
|
+
else if (typeof right === 'boolean' && typeof left === 'string') {
|
|
215
|
+
const lowered = left.trim().toLowerCase();
|
|
216
|
+
if (lowered === 'true' || lowered === 'false')
|
|
217
|
+
left = lowered === 'true';
|
|
218
|
+
}
|
|
219
|
+
switch (operator) {
|
|
220
|
+
case '==': return left === right;
|
|
221
|
+
case '!=': return left !== right;
|
|
222
|
+
case '>': return left > right;
|
|
223
|
+
case '<': return left < right;
|
|
224
|
+
case '>=': return left >= right;
|
|
225
|
+
case '<=': return left <= right;
|
|
226
|
+
// CONTAINS: left is the HAYSTACK (right in left) — corner-case #4.
|
|
227
|
+
case 'contains': return this.cmp(left).includes(this.cmp(right));
|
|
228
|
+
case 'not_contains': return !this.cmp(left).includes(this.cmp(right));
|
|
229
|
+
case 'starts_with': return this.cmp(left).startsWith(this.cmp(right));
|
|
230
|
+
case 'ends_with': return this.cmp(left).endsWith(this.cmp(right));
|
|
231
|
+
default:
|
|
232
|
+
throw new Error(`Unsupported condition: ${String(operator)}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// ── Public API ──────────────────────────────────────────────────────────────
|
|
236
|
+
/**
|
|
237
|
+
* Evaluate all conditions. Returns `[result, usedVariables]`.
|
|
238
|
+
*
|
|
239
|
+
* With no arguments (the emitted-code shape) variables resolve through the
|
|
240
|
+
* binding's own store. Pass an explicit resolver/variables for local eval.
|
|
241
|
+
*/
|
|
242
|
+
async evaluate(variables = {}, getVariableValue = defaultResolver) {
|
|
243
|
+
const used = {};
|
|
244
|
+
const results = [];
|
|
245
|
+
for (const condition of this.conditions) {
|
|
246
|
+
const [left, leftUsed] = await this.resolvePlaceholder(condition.leftOperand, variables, getVariableValue);
|
|
247
|
+
const [right, rightUsed] = await this.resolvePlaceholder(condition.rightOperand, variables, getVariableValue);
|
|
248
|
+
results.push(this.evalCondition(condition.operator, left, right));
|
|
249
|
+
Object.assign(used, leftUsed, rightUsed);
|
|
250
|
+
}
|
|
251
|
+
if (this.isV3) {
|
|
252
|
+
// V3 precedence fold: AND binds tighter than OR. Accumulate AND-groups
|
|
253
|
+
// left-to-right; each OR flushes the running group.
|
|
254
|
+
if (results.length === 0)
|
|
255
|
+
return [true, used];
|
|
256
|
+
let current = results[0];
|
|
257
|
+
const orGroups = [];
|
|
258
|
+
this.connectors.forEach((connector, idx) => {
|
|
259
|
+
// Corner-case #3: the operand is results[idx + 1], never results[idx].
|
|
260
|
+
const operand = idx + 1 < results.length ? results[idx + 1] : false;
|
|
261
|
+
if (connector === 'AND')
|
|
262
|
+
current = current && operand;
|
|
263
|
+
else if (connector === 'OR') {
|
|
264
|
+
orGroups.push(current);
|
|
265
|
+
current = operand;
|
|
266
|
+
}
|
|
267
|
+
else
|
|
268
|
+
throw new Error(`Unsupported connector: ${String(connector)}`);
|
|
269
|
+
});
|
|
270
|
+
orGroups.push(current);
|
|
271
|
+
return [orGroups.some(Boolean), used];
|
|
272
|
+
}
|
|
273
|
+
let finalResult = results.length ? results[0] : true;
|
|
274
|
+
this.connectors.forEach((connector, idx) => {
|
|
275
|
+
const operand = results[idx + 1];
|
|
276
|
+
if (connector === 'AND')
|
|
277
|
+
finalResult = finalResult && operand;
|
|
278
|
+
else if (connector === 'OR')
|
|
279
|
+
finalResult = finalResult || operand;
|
|
280
|
+
else
|
|
281
|
+
throw new Error(`Unsupported connector: ${String(connector)}`);
|
|
282
|
+
});
|
|
283
|
+
return [finalResult, used];
|
|
284
|
+
}
|
|
285
|
+
toDict() {
|
|
286
|
+
return {
|
|
287
|
+
connectors: [...this.connectors],
|
|
288
|
+
conditions: this.conditions.map((c) => c.toDict()),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=condition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"condition.js","sourceRoot":"","sources":["../../src/helpers/condition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Cookie read with V2 driver_query_script parity (playwright). */
|
|
2
|
+
import type { BrowserContext } from 'playwright';
|
|
3
|
+
/**
|
|
4
|
+
* Read cookies, then narrow by an attribute chain and an optional field.
|
|
5
|
+
*
|
|
6
|
+
* `attributes` entries are either `{index: n}` (array index) or
|
|
7
|
+
* `{<any>: [key]}` / `{<any>: [key, value]}` — a single-element array reads the
|
|
8
|
+
* key, a pair searches for the object whose key equals value.
|
|
9
|
+
* `field` is one of "len" | "keys" | "values", else the narrowed value is returned.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getCookies(context: BrowserContext, attributes?: Array<Record<string, unknown>> | null, field?: string): Promise<unknown>;
|
|
12
|
+
//# sourceMappingURL=cookies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/helpers/cookies.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAyBjD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,cAAc,EACvB,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,EAClD,KAAK,SAAK,GACT,OAAO,CAAC,OAAO,CAAC,CAiClB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { log } from '../log.js';
|
|
2
|
+
/** Depth-first search for the first object whose `key` equals `value`. */
|
|
3
|
+
function findObjectWithKv(data, key, value) {
|
|
4
|
+
if (Array.isArray(data)) {
|
|
5
|
+
for (const item of data) {
|
|
6
|
+
const found = findObjectWithKv(item, key, value);
|
|
7
|
+
if (found)
|
|
8
|
+
return found;
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
if (data !== null && typeof data === 'object') {
|
|
13
|
+
const obj = data;
|
|
14
|
+
if (obj[key] === value)
|
|
15
|
+
return obj;
|
|
16
|
+
for (const v of Object.values(obj)) {
|
|
17
|
+
const found = findObjectWithKv(v, key, value);
|
|
18
|
+
if (found)
|
|
19
|
+
return found;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Read cookies, then narrow by an attribute chain and an optional field.
|
|
26
|
+
*
|
|
27
|
+
* `attributes` entries are either `{index: n}` (array index) or
|
|
28
|
+
* `{<any>: [key]}` / `{<any>: [key, value]}` — a single-element array reads the
|
|
29
|
+
* key, a pair searches for the object whose key equals value.
|
|
30
|
+
* `field` is one of "len" | "keys" | "values", else the narrowed value is returned.
|
|
31
|
+
*/
|
|
32
|
+
export async function getCookies(context, attributes, field = '') {
|
|
33
|
+
const attrs = attributes ?? [];
|
|
34
|
+
log.helper(` [getCookies] attributes=${JSON.stringify(attrs)} field=${JSON.stringify(field)}`);
|
|
35
|
+
let queried = await context.cookies();
|
|
36
|
+
for (const attr of attrs) {
|
|
37
|
+
for (const [key, value] of Object.entries(attr)) {
|
|
38
|
+
if (key === 'index') {
|
|
39
|
+
queried = queried[Number(value)] ?? null;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const query = value;
|
|
43
|
+
if (query.length === 1) {
|
|
44
|
+
const obj = (queried ?? {});
|
|
45
|
+
queried = obj[String(query[0])] ?? '';
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
queried = findObjectWithKv(queried, String(query[0]), query[1]);
|
|
49
|
+
if (queried === null) {
|
|
50
|
+
throw new Error(`Key ${String(query[0])} with value ${String(query[1])} not found in queried content.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (field === 'len') {
|
|
56
|
+
if (Array.isArray(queried) || typeof queried === 'string')
|
|
57
|
+
return queried.length;
|
|
58
|
+
return Object.keys((queried ?? {})).length;
|
|
59
|
+
}
|
|
60
|
+
if (field === 'keys')
|
|
61
|
+
return Object.keys((queried ?? {}));
|
|
62
|
+
if (field === 'values')
|
|
63
|
+
return Object.values((queried ?? {}));
|
|
64
|
+
return queried;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=cookies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../../src/helpers/cookies.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAIhC,0EAA0E;AAC1E,SAAS,gBAAgB,CAAC,IAAU,EAAE,GAAW,EAAE,KAAc;IAC/D,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YACjD,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAC;QAC1B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,IAA+B,CAAC;QAC5C,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK;YAAE,OAAO,GAAG,CAAC;QACnC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,gBAAgB,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YAC9C,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAuB,EACvB,UAAkD,EAClD,KAAK,GAAG,EAAE;IAEV,MAAM,KAAK,GAAG,UAAU,IAAI,EAAE,CAAC;IAC/B,GAAG,CAAC,MAAM,CAAC,+BAA+B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClG,IAAI,OAAO,GAAS,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IAE5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;gBACpB,OAAO,GAAI,OAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC;gBACrD,SAAS;YACX,CAAC;YACD,MAAM,KAAK,GAAG,KAAkB,CAAC;YACjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,CAA4B,CAAC;gBACvD,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBACrB,MAAM,IAAI,KAAK,CACb,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,gCAAgC,CACvF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QACpB,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC;QACjF,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,EAAE,CAAW,CAAC,CAAC,MAAM,CAAC;IACvD,CAAC;IACD,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,EAAE,CAAW,CAAC,CAAC;IACpE,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,IAAI,EAAE,CAAW,CAAC,CAAC;IACxE,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coordinate → element → verified-XPath derivation (design spec §3.1, §4).
|
|
3
|
+
*
|
|
4
|
+
* playwright-ts twin of the PY/Selenium coordinate resolvers. RESOLVER_JS is
|
|
5
|
+
* the CANONICAL tree-shared script — it must stay byte-identical to the
|
|
6
|
+
* selenium-python / playwright-python copies (spec §4.3: edit ALL trees
|
|
7
|
+
* together).
|
|
8
|
+
*/
|
|
9
|
+
import type { Page } from 'playwright';
|
|
10
|
+
export declare const RESOLVER_JS = "try {\n var el = document.elementFromPoint(x, y);\n if (!el) { return null; }\n while (el.shadowRoot) {\n var deeper = el.shadowRoot.elementFromPoint(x, y);\n if (!deeper || deeper === el) { break; }\n el = deeper;\n }\n if (el.getRootNode && el.getRootNode() !== document) { return null; }\n var hitTag = el.tagName ? el.tagName.toLowerCase() : '';\n if (hitTag === 'iframe' || hitTag === 'frame' || hitTag === 'canvas' || hitTag === 'video') { return null; }\n\n var INTERACTABLE = 'a, button, input, select, textarea, summary, label, [onclick], [contenteditable], [tabindex]:not([tabindex=\"-1\"]), [role=\"button\"], [role=\"link\"], [role=\"checkbox\"], [role=\"radio\"], [role=\"menuitem\"], [role=\"tab\"], [role=\"option\"], [role=\"switch\"], [role=\"combobox\"], [role=\"textbox\"]';\n if (!(el.matches && el.matches(INTERACTABLE))) {\n var cur = el;\n var hops = 0;\n while (cur && cur !== document.documentElement && hops < 6) {\n cur = cur.parentElement;\n hops += 1;\n if (cur && cur.matches && cur.matches(INTERACTABLE)) { el = cur; break; }\n }\n }\n\n function xpathLiteral(v) {\n if (v.indexOf(\"'\") === -1) { return \"'\" + v + \"'\"; }\n if (v.indexOf('\"') === -1) { return '\"' + v + '\"'; }\n return \"concat('\" + v.split(\"'\").join(\"', \\\"'\\\", '\") + \"')\";\n }\n\n function verifies(xp) {\n try {\n var r = document.evaluate(xp, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n return r.snapshotLength === 1 && r.snapshotItem(0) === el;\n } catch (e) { return false; }\n }\n\n var tag = el.tagName.toLowerCase();\n var candidates = [];\n if (el.id) { candidates.push('//*[@id=' + xpathLiteral(el.id) + ']'); }\n var ATTRS = ['data-testid', 'data-test', 'data-qa', 'name', 'aria-label', 'placeholder', 'title'];\n for (var i = 0; i < ATTRS.length; i++) {\n var av = el.getAttribute(ATTRS[i]);\n if (av) { candidates.push('//' + tag + '[@' + ATTRS[i] + '=' + xpathLiteral(av) + ']'); break; }\n }\n var text = (el.textContent || '').replace(/\\s+/g, ' ').trim();\n if (text && text.length <= 64) {\n candidates.push('//' + tag + '[normalize-space(.)=' + xpathLiteral(text) + ']');\n }\n var parts = [];\n var node = el;\n while (node && node.nodeType === 1) {\n var name = node.tagName.toLowerCase();\n var idx = 1;\n var sib = node.previousElementSibling;\n while (sib) {\n if (sib.tagName === node.tagName) { idx += 1; }\n sib = sib.previousElementSibling;\n }\n parts.unshift(name + '[' + idx + ']');\n node = node.parentElement;\n }\n candidates.push('/' + parts.join('/'));\n\n for (var c = 0; c < candidates.length; c++) {\n if (verifies(candidates[c])) {\n return { xpath: candidates[c], tag: tag, id: el.id || '', text: text.slice(0, 80) };\n }\n }\n return null;\n} catch (e) {\n return null;\n}\n";
|
|
11
|
+
/** A self-verified, document-rooted XPath for the element under a point. */
|
|
12
|
+
export interface ResolvedTarget {
|
|
13
|
+
xpath: string;
|
|
14
|
+
meta: {
|
|
15
|
+
tag: string;
|
|
16
|
+
id: string;
|
|
17
|
+
text: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve viewport-CSS (x, y) to a verified XPath, or null.
|
|
22
|
+
*
|
|
23
|
+
* null ALWAYS means "use the coordinate fallback" (shadow-DOM hit, iframe
|
|
24
|
+
* hit, no node, verification failure, or any JS error). Never throws — a
|
|
25
|
+
* derivation failure must never break a heal that would have succeeded via
|
|
26
|
+
* the coord runner (spec §3.1).
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveCoordinate(page: Page, x: number, y: number): Promise<ResolvedTarget | null>;
|
|
29
|
+
//# sourceMappingURL=coordinateResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinateResolver.d.ts","sourceRoot":"","sources":["../../src/helpers/coordinateResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,eAAO,MAAM,WAAW,s1FAyEvB,CAAC;AAWF,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,EACV,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAyBhC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { log } from '../log.js';
|
|
2
|
+
// === CANONICAL_RESOLVER_JS_START === (edit ALL trees together; spec §4.3)
|
|
3
|
+
export const RESOLVER_JS = `\
|
|
4
|
+
try {
|
|
5
|
+
var el = document.elementFromPoint(x, y);
|
|
6
|
+
if (!el) { return null; }
|
|
7
|
+
while (el.shadowRoot) {
|
|
8
|
+
var deeper = el.shadowRoot.elementFromPoint(x, y);
|
|
9
|
+
if (!deeper || deeper === el) { break; }
|
|
10
|
+
el = deeper;
|
|
11
|
+
}
|
|
12
|
+
if (el.getRootNode && el.getRootNode() !== document) { return null; }
|
|
13
|
+
var hitTag = el.tagName ? el.tagName.toLowerCase() : '';
|
|
14
|
+
if (hitTag === 'iframe' || hitTag === 'frame' || hitTag === 'canvas' || hitTag === 'video') { return null; }
|
|
15
|
+
|
|
16
|
+
var INTERACTABLE = 'a, button, input, select, textarea, summary, label, [onclick], [contenteditable], [tabindex]:not([tabindex="-1"]), [role="button"], [role="link"], [role="checkbox"], [role="radio"], [role="menuitem"], [role="tab"], [role="option"], [role="switch"], [role="combobox"], [role="textbox"]';
|
|
17
|
+
if (!(el.matches && el.matches(INTERACTABLE))) {
|
|
18
|
+
var cur = el;
|
|
19
|
+
var hops = 0;
|
|
20
|
+
while (cur && cur !== document.documentElement && hops < 6) {
|
|
21
|
+
cur = cur.parentElement;
|
|
22
|
+
hops += 1;
|
|
23
|
+
if (cur && cur.matches && cur.matches(INTERACTABLE)) { el = cur; break; }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function xpathLiteral(v) {
|
|
28
|
+
if (v.indexOf("'") === -1) { return "'" + v + "'"; }
|
|
29
|
+
if (v.indexOf('"') === -1) { return '"' + v + '"'; }
|
|
30
|
+
return "concat('" + v.split("'").join("', \\"'\\", '") + "')";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function verifies(xp) {
|
|
34
|
+
try {
|
|
35
|
+
var r = document.evaluate(xp, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
36
|
+
return r.snapshotLength === 1 && r.snapshotItem(0) === el;
|
|
37
|
+
} catch (e) { return false; }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
var tag = el.tagName.toLowerCase();
|
|
41
|
+
var candidates = [];
|
|
42
|
+
if (el.id) { candidates.push('//*[@id=' + xpathLiteral(el.id) + ']'); }
|
|
43
|
+
var ATTRS = ['data-testid', 'data-test', 'data-qa', 'name', 'aria-label', 'placeholder', 'title'];
|
|
44
|
+
for (var i = 0; i < ATTRS.length; i++) {
|
|
45
|
+
var av = el.getAttribute(ATTRS[i]);
|
|
46
|
+
if (av) { candidates.push('//' + tag + '[@' + ATTRS[i] + '=' + xpathLiteral(av) + ']'); break; }
|
|
47
|
+
}
|
|
48
|
+
var text = (el.textContent || '').replace(/\\s+/g, ' ').trim();
|
|
49
|
+
if (text && text.length <= 64) {
|
|
50
|
+
candidates.push('//' + tag + '[normalize-space(.)=' + xpathLiteral(text) + ']');
|
|
51
|
+
}
|
|
52
|
+
var parts = [];
|
|
53
|
+
var node = el;
|
|
54
|
+
while (node && node.nodeType === 1) {
|
|
55
|
+
var name = node.tagName.toLowerCase();
|
|
56
|
+
var idx = 1;
|
|
57
|
+
var sib = node.previousElementSibling;
|
|
58
|
+
while (sib) {
|
|
59
|
+
if (sib.tagName === node.tagName) { idx += 1; }
|
|
60
|
+
sib = sib.previousElementSibling;
|
|
61
|
+
}
|
|
62
|
+
parts.unshift(name + '[' + idx + ']');
|
|
63
|
+
node = node.parentElement;
|
|
64
|
+
}
|
|
65
|
+
candidates.push('/' + parts.join('/'));
|
|
66
|
+
|
|
67
|
+
for (var c = 0; c < candidates.length; c++) {
|
|
68
|
+
if (verifies(candidates[c])) {
|
|
69
|
+
return { xpath: candidates[c], tag: tag, id: el.id || '', text: text.slice(0, 80) };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
} catch (e) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
77
|
+
// === CANONICAL_RESOLVER_JS_END ===
|
|
78
|
+
// Built via the Function constructor (browser-executed by Playwright, which
|
|
79
|
+
// serializes fn.toString() over the wire) — the grid CDP relay returns
|
|
80
|
+
// undefined for STRING page-functions, so a plain string wrap never runs.
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
82
|
+
const WRAPPED_FN = new Function('args', 'const [x, y] = args;\n' + RESOLVER_JS);
|
|
83
|
+
/**
|
|
84
|
+
* Resolve viewport-CSS (x, y) to a verified XPath, or null.
|
|
85
|
+
*
|
|
86
|
+
* null ALWAYS means "use the coordinate fallback" (shadow-DOM hit, iframe
|
|
87
|
+
* hit, no node, verification failure, or any JS error). Never throws — a
|
|
88
|
+
* derivation failure must never break a heal that would have succeeded via
|
|
89
|
+
* the coord runner (spec §3.1).
|
|
90
|
+
*/
|
|
91
|
+
export async function resolveCoordinate(page, x, y) {
|
|
92
|
+
let raw;
|
|
93
|
+
try {
|
|
94
|
+
raw = await page.evaluate(WRAPPED_FN, [Math.trunc(x), Math.trunc(y)]);
|
|
95
|
+
}
|
|
96
|
+
catch (exc) {
|
|
97
|
+
log.helper(` [resolver] derived_xpath=None reason=js-error: ${String(exc)}`);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (raw === null || typeof raw !== 'object') {
|
|
101
|
+
log.helper(' [resolver] derived_xpath=None reason=no-node-or-bail');
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const obj = raw;
|
|
105
|
+
const xpath = obj['xpath'];
|
|
106
|
+
if (typeof xpath !== 'string' || !xpath) {
|
|
107
|
+
log.helper(' [resolver] derived_xpath=None reason=verify-failed');
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const meta = {
|
|
111
|
+
tag: String(obj['tag'] ?? ''),
|
|
112
|
+
id: String(obj['id'] ?? ''),
|
|
113
|
+
text: String(obj['text'] ?? ''),
|
|
114
|
+
};
|
|
115
|
+
log.helper(` [resolver] derived_xpath=${xpath} meta=${JSON.stringify(meta)}`);
|
|
116
|
+
return { xpath, meta };
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=coordinateResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinateResolver.js","sourceRoot":"","sources":["../../src/helpers/coordinateResolver.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEhC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyE1B,CAAC;AACF,oCAAoC;AAEpC,4EAA4E;AAC5E,uEAAuE;AACvE,0EAA0E;AAC1E,8DAA8D;AAC9D,MAAM,UAAU,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,wBAAwB,GAAG,WAAW,CAElE,CAAC;AAQb;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAU,EACV,CAAS,EACT,CAAS;IAET,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAmB,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAU,CAAC,CAAC;IAC1F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,CAAC,sDAAsD,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5C,GAAG,CAAC,MAAM,CAAC,0DAA0D,CAAC,CAAC;QACvE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;QACxC,GAAG,CAAC,MAAM,CAAC,wDAAwD,CAAC,CAAC;QACrE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,IAAI,GAAG;QACX,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;KAChC,CAAC;IACF,GAAG,CAAC,MAAM,CAAC,gCAAgC,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-tuned coordinate → element → verified-XPath (textual_query read path).
|
|
3
|
+
*
|
|
4
|
+
* playwright-ts read twin of PY _coordinate_resolver_read.py / selenium's
|
|
5
|
+
* READ_RESOLVER_JS. READ_RESOLVER_JS is CANONICAL and byte-shared across all
|
|
6
|
+
* three trees (spec §4.3: edit ALL trees together).
|
|
7
|
+
*
|
|
8
|
+
* Key difference from coordinateResolver.ts / RESOLVER_JS:
|
|
9
|
+
* The interactable ancestor up-walk (INTERACTABLE selector + 6-hop
|
|
10
|
+
* parentElement loop) is OMITTED, and img is a bail tag. `el` stays the
|
|
11
|
+
* exact elementFromPoint hit, so non-inherited CSS (background-color) is
|
|
12
|
+
* read from the correct box, not a climbed a/button/[role] ancestor.
|
|
13
|
+
*/
|
|
14
|
+
import type { Page } from 'playwright';
|
|
15
|
+
export declare const READ_RESOLVER_JS = "try {\n var el = document.elementFromPoint(x, y);\n if (!el) { return null; }\n while (el.shadowRoot) {\n var deeper = el.shadowRoot.elementFromPoint(x, y);\n if (!deeper || deeper === el) { break; }\n el = deeper;\n }\n if (el.getRootNode && el.getRootNode() !== document) { return null; }\n var hitTag = el.tagName ? el.tagName.toLowerCase() : '';\n if (hitTag === 'iframe' || hitTag === 'frame' || hitTag === 'canvas' || hitTag === 'video' || hitTag === 'img') { return null; }\n\n // *** NO interactable up-walk here (the ONLY structural difference from\n // RESOLVER_JS): the read must stay on the exact direct hit so non-inherited\n // CSS (background-color) is read off the correct box. ***\n\n function xpathLiteral(v) {\n if (v.indexOf(\"'\") === -1) { return \"'\" + v + \"'\"; }\n if (v.indexOf('\"') === -1) { return '\"' + v + '\"'; }\n return \"concat('\" + v.split(\"'\").join(\"', \\\"'\\\", '\") + \"')\";\n }\n function verifies(xp) {\n try {\n var r = document.evaluate(xp, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n return r.snapshotLength === 1 && r.snapshotItem(0) === el;\n } catch (e) { return false; }\n }\n var tag = el.tagName.toLowerCase();\n var candidates = [];\n if (el.id) { candidates.push('//*[@id=' + xpathLiteral(el.id) + ']'); }\n var ATTRS = ['data-testid', 'data-test', 'data-qa', 'name', 'aria-label', 'placeholder', 'title'];\n for (var i = 0; i < ATTRS.length; i++) {\n var av = el.getAttribute(ATTRS[i]);\n if (av) { candidates.push('//' + tag + '[@' + ATTRS[i] + '=' + xpathLiteral(av) + ']'); break; }\n }\n var text = (el.textContent || '').replace(/\\s+/g, ' ').trim();\n if (text && text.length <= 64) {\n candidates.push('//' + tag + '[normalize-space(.)=' + xpathLiteral(text) + ']');\n }\n var parts = [];\n var node = el;\n while (node && node.nodeType === 1) {\n var name = node.tagName.toLowerCase();\n var idx = 1;\n var sib = node.previousElementSibling;\n while (sib) { if (sib.tagName === node.tagName) { idx += 1; } sib = sib.previousElementSibling; }\n parts.unshift(name + '[' + idx + ']');\n node = node.parentElement;\n }\n candidates.push('/' + parts.join('/'));\n for (var c = 0; c < candidates.length; c++) {\n if (verifies(candidates[c])) {\n return { xpath: candidates[c], tag: tag, id: el.id || '', text: text.slice(0, 80) };\n }\n }\n return null;\n} catch (e) {\n return null;\n}\n";
|
|
16
|
+
/** A self-verified, document-rooted XPath for the element under a point (read path). */
|
|
17
|
+
export interface ResolvedRead {
|
|
18
|
+
xpath: string;
|
|
19
|
+
meta: {
|
|
20
|
+
tag: string;
|
|
21
|
+
id: string;
|
|
22
|
+
text: string;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve viewport-CSS (x, y) to a verified XPath for READING, or null.
|
|
27
|
+
*
|
|
28
|
+
* Identical no-throw contract to resolveCoordinate but uses READ_RESOLVER_JS
|
|
29
|
+
* (no interactable up-walk), so the derived xpath is the EXACT direct hit —
|
|
30
|
+
* correct for non-interactable nodes and non-inherited CSS (background-color).
|
|
31
|
+
*
|
|
32
|
+
* null ALWAYS means "use the server fallback" (shadow-DOM hit, iframe hit,
|
|
33
|
+
* canvas/video/img hit, no node, verification failure, or any JS error).
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveCoordinateRead(page: Page, x: number, y: number): Promise<ResolvedRead | null>;
|
|
36
|
+
//# sourceMappingURL=coordinateResolverRead.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinateResolverRead.d.ts","sourceRoot":"","sources":["../../src/helpers/coordinateResolverRead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,eAAO,MAAM,gBAAgB,m7EA4D5B,CAAC;AAWF,wFAAwF;AACxF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,IAAI,EACV,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAyB9B"}
|