@muuktest/amikoo-playwright 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/dist/capture.cjs +57 -0
- package/dist/capture.cjs.map +1 -0
- package/dist/capture.d.cts +6 -0
- package/dist/capture.d.ts +6 -0
- package/dist/capture.js +23 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli/agent-setup.cjs +68 -0
- package/dist/cli/agent-setup.cjs.map +1 -0
- package/dist/cli/agent-setup.d.cts +11 -0
- package/dist/cli/agent-setup.d.ts +11 -0
- package/dist/cli/agent-setup.js +31 -0
- package/dist/cli/agent-setup.js.map +1 -0
- package/dist/cli/amikoo-playwright-agent.md +82 -0
- package/dist/cli/fixture-creator.cjs +163 -0
- package/dist/cli/fixture-creator.cjs.map +1 -0
- package/dist/cli/fixture-creator.d.cts +12 -0
- package/dist/cli/fixture-creator.d.ts +12 -0
- package/dist/cli/fixture-creator.js +128 -0
- package/dist/cli/fixture-creator.js.map +1 -0
- package/dist/cli/index.cjs +134 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +111 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/mcp-setup.cjs +116 -0
- package/dist/cli/mcp-setup.cjs.map +1 -0
- package/dist/cli/mcp-setup.d.cts +12 -0
- package/dist/cli/mcp-setup.d.ts +12 -0
- package/dist/cli/mcp-setup.js +81 -0
- package/dist/cli/mcp-setup.js.map +1 -0
- package/dist/cli/scanner.cjs +137 -0
- package/dist/cli/scanner.cjs.map +1 -0
- package/dist/cli/scanner.d.cts +16 -0
- package/dist/cli/scanner.d.ts +16 -0
- package/dist/cli/scanner.js +100 -0
- package/dist/cli/scanner.js.map +1 -0
- package/dist/cli/test-updater.cjs +131 -0
- package/dist/cli/test-updater.cjs.map +1 -0
- package/dist/cli/test-updater.d.cts +12 -0
- package/dist/cli/test-updater.d.ts +12 -0
- package/dist/cli/test-updater.js +96 -0
- package/dist/cli/test-updater.js.map +1 -0
- package/dist/dom/buildDomTree.js +1760 -0
- package/dist/helpers/dom-extractor.cjs +344 -0
- package/dist/helpers/dom-extractor.cjs.map +1 -0
- package/dist/helpers/dom-extractor.d.cts +9 -0
- package/dist/helpers/dom-extractor.d.ts +9 -0
- package/dist/helpers/dom-extractor.js +318 -0
- package/dist/helpers/dom-extractor.js.map +1 -0
- package/dist/helpers/dom-service.cjs +365 -0
- package/dist/helpers/dom-service.cjs.map +1 -0
- package/dist/helpers/dom-service.d.cts +82 -0
- package/dist/helpers/dom-service.d.ts +82 -0
- package/dist/helpers/dom-service.js +338 -0
- package/dist/helpers/dom-service.js.map +1 -0
- package/dist/helpers/failure-analyzer.cjs +276 -0
- package/dist/helpers/failure-analyzer.cjs.map +1 -0
- package/dist/helpers/failure-analyzer.d.cts +100 -0
- package/dist/helpers/failure-analyzer.d.ts +100 -0
- package/dist/helpers/failure-analyzer.js +241 -0
- package/dist/helpers/failure-analyzer.js.map +1 -0
- package/dist/index.cjs +32 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var dom_service_exports = {};
|
|
20
|
+
__export(dom_service_exports, {
|
|
21
|
+
DOMBaseNode: () => DOMBaseNode,
|
|
22
|
+
DOMElementNode: () => DOMElementNode,
|
|
23
|
+
DOMTextNode: () => DOMTextNode,
|
|
24
|
+
DomService: () => DomService
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(dom_service_exports);
|
|
27
|
+
class DOMBaseNode {
|
|
28
|
+
is_visible;
|
|
29
|
+
parent;
|
|
30
|
+
constructor(isVisible, parent = null) {
|
|
31
|
+
this.is_visible = isVisible;
|
|
32
|
+
this.parent = parent;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
class DOMTextNode extends DOMBaseNode {
|
|
36
|
+
text;
|
|
37
|
+
type;
|
|
38
|
+
constructor(text, isVisible, parent = null) {
|
|
39
|
+
super(isVisible, parent);
|
|
40
|
+
this.text = text;
|
|
41
|
+
this.type = "TEXT_NODE";
|
|
42
|
+
}
|
|
43
|
+
has_parent_with_highlight_index() {
|
|
44
|
+
let current = this.parent;
|
|
45
|
+
while (current !== null) {
|
|
46
|
+
if (current.highlight_index !== null && current.highlight_index !== void 0) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
current = current.parent;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function convertSimpleXpathToCssSelector(xpath) {
|
|
55
|
+
if (!xpath) return "";
|
|
56
|
+
xpath = xpath.replace(/^\/+/, "");
|
|
57
|
+
const parts = xpath.split("/");
|
|
58
|
+
const cssParts = [];
|
|
59
|
+
for (let part of parts) {
|
|
60
|
+
if (!part) continue;
|
|
61
|
+
if (part.includes(":") && !part.includes("[")) {
|
|
62
|
+
const basePart = part.replace(/:/g, "\\:");
|
|
63
|
+
cssParts.push(basePart);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (part.includes("[")) {
|
|
67
|
+
let basePart = part.substring(0, part.indexOf("["));
|
|
68
|
+
if (basePart.includes(":")) {
|
|
69
|
+
basePart = basePart.replace(/:/g, "\\:");
|
|
70
|
+
}
|
|
71
|
+
const indexPart = part.substring(part.indexOf("["));
|
|
72
|
+
const indices = indexPart.split("]").filter((i) => i).map((i) => i.replace("[", ""));
|
|
73
|
+
for (const idx of indices) {
|
|
74
|
+
try {
|
|
75
|
+
if (/^\d+$/.test(idx)) {
|
|
76
|
+
const index = parseInt(idx) - 1;
|
|
77
|
+
basePart += `:nth-of-type(${index + 1})`;
|
|
78
|
+
} else if (idx === "last()") {
|
|
79
|
+
basePart += ":last-of-type";
|
|
80
|
+
} else if (idx.includes("position()") && idx.includes(">1")) {
|
|
81
|
+
basePart += ":nth-of-type(n+2)";
|
|
82
|
+
}
|
|
83
|
+
} catch (e) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
cssParts.push(basePart);
|
|
88
|
+
} else {
|
|
89
|
+
cssParts.push(part);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return cssParts.join(" > ");
|
|
93
|
+
}
|
|
94
|
+
function enhancedCssSelectorForElement(element, includeDynamicAttributes = true) {
|
|
95
|
+
try {
|
|
96
|
+
let cssSelector = convertSimpleXpathToCssSelector(element.xpath);
|
|
97
|
+
if (element.attributes.class && includeDynamicAttributes) {
|
|
98
|
+
const validClassNamePattern = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;
|
|
99
|
+
const classes = element.attributes.class.split(/\s+/);
|
|
100
|
+
for (const className of classes) {
|
|
101
|
+
if (!className.trim()) continue;
|
|
102
|
+
if (validClassNamePattern.test(className)) {
|
|
103
|
+
cssSelector += `.${className}`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const SAFE_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
108
|
+
"id",
|
|
109
|
+
"name",
|
|
110
|
+
"type",
|
|
111
|
+
"placeholder",
|
|
112
|
+
"aria-label",
|
|
113
|
+
"aria-labelledby",
|
|
114
|
+
"aria-describedby",
|
|
115
|
+
"role",
|
|
116
|
+
"for",
|
|
117
|
+
"autocomplete",
|
|
118
|
+
"required",
|
|
119
|
+
"readonly",
|
|
120
|
+
"alt",
|
|
121
|
+
"title",
|
|
122
|
+
"src",
|
|
123
|
+
"href",
|
|
124
|
+
"target"
|
|
125
|
+
]);
|
|
126
|
+
if (includeDynamicAttributes) {
|
|
127
|
+
SAFE_ATTRIBUTES.add("data-id");
|
|
128
|
+
SAFE_ATTRIBUTES.add("data-qa");
|
|
129
|
+
SAFE_ATTRIBUTES.add("data-cy");
|
|
130
|
+
SAFE_ATTRIBUTES.add("data-testid");
|
|
131
|
+
}
|
|
132
|
+
for (const [attribute, value] of Object.entries(element.attributes)) {
|
|
133
|
+
if (attribute === "class") continue;
|
|
134
|
+
if (!attribute.trim()) continue;
|
|
135
|
+
if (!SAFE_ATTRIBUTES.has(attribute)) continue;
|
|
136
|
+
const safeAttribute = attribute.replace(/:/g, "\\:");
|
|
137
|
+
if (value === "") {
|
|
138
|
+
cssSelector += `[${safeAttribute}]`;
|
|
139
|
+
} else if (/["'<>`\n\r\t]/.test(value)) {
|
|
140
|
+
let processedValue = value;
|
|
141
|
+
if (processedValue.includes("\n")) {
|
|
142
|
+
processedValue = processedValue.split("\n")[0];
|
|
143
|
+
}
|
|
144
|
+
const collapsedValue = processedValue.replace(/\s+/g, " ").trim();
|
|
145
|
+
const safeValue = collapsedValue.replace(/"/g, '\\"');
|
|
146
|
+
cssSelector += `[${safeAttribute}*="${safeValue}"]`;
|
|
147
|
+
} else {
|
|
148
|
+
cssSelector += `[${safeAttribute}="${value}"]`;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return cssSelector;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
const tagName = element.tag_name || "*";
|
|
154
|
+
return `${tagName}[highlight_index='${element.highlight_index}']`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
class DOMElementNode extends DOMBaseNode {
|
|
158
|
+
tag_name;
|
|
159
|
+
xpath;
|
|
160
|
+
attributes;
|
|
161
|
+
children;
|
|
162
|
+
childrenTags;
|
|
163
|
+
is_interactive;
|
|
164
|
+
is_reference;
|
|
165
|
+
is_top_element;
|
|
166
|
+
is_in_viewport;
|
|
167
|
+
shadow_root;
|
|
168
|
+
highlight_index;
|
|
169
|
+
page_coordinates;
|
|
170
|
+
viewport_coordinates;
|
|
171
|
+
_css_selector;
|
|
172
|
+
constructor(data) {
|
|
173
|
+
super(data.isVisible || false, null);
|
|
174
|
+
this.tag_name = data.tagName || "";
|
|
175
|
+
this.xpath = data.xpath || "";
|
|
176
|
+
this.attributes = data.attributes || {};
|
|
177
|
+
this.children = [];
|
|
178
|
+
this.childrenTags = data.childrenTags || [];
|
|
179
|
+
this.is_interactive = data.isInteractive || false;
|
|
180
|
+
this.is_reference = data.isReference || false;
|
|
181
|
+
this.is_top_element = data.isTopElement || false;
|
|
182
|
+
this.is_in_viewport = data.isInViewport || false;
|
|
183
|
+
this.shadow_root = data.shadowRoot || false;
|
|
184
|
+
this.highlight_index = data.highlightIndex;
|
|
185
|
+
this.page_coordinates = data.pageCoordinates || null;
|
|
186
|
+
this.viewport_coordinates = data.viewportCoordinates || null;
|
|
187
|
+
this._css_selector = null;
|
|
188
|
+
}
|
|
189
|
+
get css_selector() {
|
|
190
|
+
if (this._css_selector === null) {
|
|
191
|
+
this._css_selector = enhancedCssSelectorForElement(this, true);
|
|
192
|
+
}
|
|
193
|
+
return this._css_selector;
|
|
194
|
+
}
|
|
195
|
+
get_meaningful_text() {
|
|
196
|
+
const semanticAttrs = ["value", "aria-label", "title", "placeholder", "alt", "name"];
|
|
197
|
+
for (const attr of semanticAttrs) {
|
|
198
|
+
if (this.attributes[attr]) {
|
|
199
|
+
return this.clean_text(this.attributes[attr]);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const tag = this.tag_name.toLowerCase();
|
|
203
|
+
if (tag === "a") {
|
|
204
|
+
for (const child of this.children) {
|
|
205
|
+
if (!(child instanceof DOMElementNode)) continue;
|
|
206
|
+
const ctag = child.tag_name.toLowerCase();
|
|
207
|
+
if (ctag === "img") {
|
|
208
|
+
const alt = child.attributes.alt || "";
|
|
209
|
+
const title = child.attributes.title || "";
|
|
210
|
+
if (alt) return this.clean_text(alt);
|
|
211
|
+
if (title) return this.clean_text(title);
|
|
212
|
+
} else if (ctag === "svg") {
|
|
213
|
+
const ariaLabel = child.attributes["aria-label"] || "";
|
|
214
|
+
const title = child.attributes.title || "";
|
|
215
|
+
if (ariaLabel) return this.clean_text(ariaLabel);
|
|
216
|
+
if (title) return this.clean_text(title);
|
|
217
|
+
for (const g of child.children) {
|
|
218
|
+
if (g instanceof DOMElementNode && g.tag_name.toLowerCase() === "title") {
|
|
219
|
+
const titleText = this.get_all_text_from_node(g);
|
|
220
|
+
if (titleText) return this.clean_text(titleText);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (tag === "img") {
|
|
227
|
+
const alt = this.attributes.alt || "";
|
|
228
|
+
const title = this.attributes.title || "";
|
|
229
|
+
if (alt) return this.clean_text(alt);
|
|
230
|
+
if (title) return this.clean_text(title);
|
|
231
|
+
}
|
|
232
|
+
if (tag === "svg") {
|
|
233
|
+
const ariaLabel = this.attributes["aria-label"] || "";
|
|
234
|
+
const title = this.attributes.title || "";
|
|
235
|
+
if (ariaLabel) return this.clean_text(ariaLabel);
|
|
236
|
+
if (title) return this.clean_text(title);
|
|
237
|
+
for (const child of this.children) {
|
|
238
|
+
if (child instanceof DOMElementNode && child.tag_name.toLowerCase() === "title") {
|
|
239
|
+
const titleText = this.get_all_text_from_node(child);
|
|
240
|
+
if (titleText) return this.clean_text(titleText);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const textVal = this.get_all_children_text(-1).trim();
|
|
245
|
+
return textVal ? this.clean_text(textVal) : "";
|
|
246
|
+
}
|
|
247
|
+
get_all_children_text(maxDepth = 1) {
|
|
248
|
+
const textParts = [];
|
|
249
|
+
const collectText = (node, currentDepth) => {
|
|
250
|
+
if (maxDepth !== -1 && currentDepth > maxDepth) return;
|
|
251
|
+
if (node instanceof DOMTextNode) {
|
|
252
|
+
if (node.text && node.is_visible) {
|
|
253
|
+
textParts.push(node.text.trim());
|
|
254
|
+
}
|
|
255
|
+
} else if (node instanceof DOMElementNode) {
|
|
256
|
+
for (const child of node.children) {
|
|
257
|
+
collectText(child, currentDepth + 1);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
const children = this.children || [];
|
|
262
|
+
if (children.length === 1 && children[0] instanceof DOMElementNode) {
|
|
263
|
+
const child = children[0];
|
|
264
|
+
const tag = child.tag_name.toLowerCase();
|
|
265
|
+
if (tag === "div" || tag === "span") {
|
|
266
|
+
for (const gc of child.children) {
|
|
267
|
+
collectText(gc, 1);
|
|
268
|
+
}
|
|
269
|
+
return textParts.filter((t) => t).join(" ");
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
for (const child of children) {
|
|
273
|
+
collectText(child, 1);
|
|
274
|
+
}
|
|
275
|
+
return textParts.filter((t) => t).join(" ");
|
|
276
|
+
}
|
|
277
|
+
get_all_text_from_node(node) {
|
|
278
|
+
if (node instanceof DOMTextNode) {
|
|
279
|
+
return node.text;
|
|
280
|
+
} else if (node instanceof DOMElementNode) {
|
|
281
|
+
return node.get_all_children_text(-1);
|
|
282
|
+
}
|
|
283
|
+
return "";
|
|
284
|
+
}
|
|
285
|
+
clean_text(text) {
|
|
286
|
+
if (!text) return "";
|
|
287
|
+
const parts = text.split(/\s+/);
|
|
288
|
+
const mid = Math.floor(parts.length / 2);
|
|
289
|
+
if (parts.length > 1) {
|
|
290
|
+
const firstHalf = parts.slice(0, mid).join(" ");
|
|
291
|
+
const secondHalf = parts.slice(mid).join(" ");
|
|
292
|
+
if (firstHalf === secondHalf) {
|
|
293
|
+
return firstHalf;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return parts.join(" ");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
class DomService {
|
|
300
|
+
async buildDomTree(page, jsCode, options = {}) {
|
|
301
|
+
const args = {
|
|
302
|
+
doHighlightElements: options.highlightElements ?? true,
|
|
303
|
+
focusHighlightIndex: options.focusElement ?? -1,
|
|
304
|
+
viewportExpansion: options.viewportExpansion ?? -1,
|
|
305
|
+
debugMode: options.debugMode ?? false
|
|
306
|
+
};
|
|
307
|
+
const evalPage = await page.evaluate(({ code, params }) => {
|
|
308
|
+
eval(code);
|
|
309
|
+
return window.buildDomTreeMain(params);
|
|
310
|
+
}, { code: jsCode, params: args });
|
|
311
|
+
return this.constructDomTree(evalPage);
|
|
312
|
+
}
|
|
313
|
+
constructDomTree(evalPage2) {
|
|
314
|
+
const jsNodeMap = evalPage2.map;
|
|
315
|
+
const jsRootId = evalPage2.rootId;
|
|
316
|
+
const selectorMap = {};
|
|
317
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
318
|
+
const childrenMap = /* @__PURE__ */ new Map();
|
|
319
|
+
for (const [id, nodeData] of Object.entries(jsNodeMap)) {
|
|
320
|
+
const { node, childrenIds } = this.parseNode(nodeData);
|
|
321
|
+
if (!node) continue;
|
|
322
|
+
nodeMap.set(id, node);
|
|
323
|
+
childrenMap.set(id, childrenIds);
|
|
324
|
+
if (node instanceof DOMElementNode && node.highlight_index !== null && node.highlight_index !== void 0) {
|
|
325
|
+
selectorMap[node.highlight_index] = node;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
for (const [idStr, node] of nodeMap.entries()) {
|
|
329
|
+
if (node instanceof DOMElementNode) {
|
|
330
|
+
const childIds = childrenMap.get(idStr) || [];
|
|
331
|
+
for (const childId of childIds) {
|
|
332
|
+
const childNode = nodeMap.get(String(childId));
|
|
333
|
+
if (childNode) {
|
|
334
|
+
childNode.parent = node;
|
|
335
|
+
node.children.push(childNode);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const rootNode = nodeMap.get(String(jsRootId));
|
|
341
|
+
return { elementTree: rootNode, selectorMap };
|
|
342
|
+
}
|
|
343
|
+
parseNode(nodeData) {
|
|
344
|
+
if (!nodeData) return { node: null, childrenIds: [] };
|
|
345
|
+
if (nodeData.type === "TEXT_NODE") {
|
|
346
|
+
const textNode = new DOMTextNode(
|
|
347
|
+
nodeData.text || "",
|
|
348
|
+
nodeData.isVisible || false,
|
|
349
|
+
null
|
|
350
|
+
);
|
|
351
|
+
return { node: textNode, childrenIds: [] };
|
|
352
|
+
}
|
|
353
|
+
const elementNode = new DOMElementNode(nodeData);
|
|
354
|
+
const childrenIds = nodeData.children || [];
|
|
355
|
+
return { node: elementNode, childrenIds };
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
359
|
+
0 && (module.exports = {
|
|
360
|
+
DOMBaseNode,
|
|
361
|
+
DOMElementNode,
|
|
362
|
+
DOMTextNode,
|
|
363
|
+
DomService
|
|
364
|
+
});
|
|
365
|
+
//# sourceMappingURL=dom-service.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/dom-service.ts"],"sourcesContent":["/**\n * DOM Node Classes - Port from Python views.py\n */\nimport type { Page } from '@playwright/test';\n\nexport interface Coordinates {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface DOMElementData {\n tagName?: string;\n xpath?: string;\n attributes?: Record<string, string>;\n childrenTags?: string[];\n isInteractive?: boolean;\n isReference?: boolean;\n isTopElement?: boolean;\n isInViewport?: boolean;\n isVisible?: boolean;\n shadowRoot?: boolean;\n highlightIndex?: number | null;\n pageCoordinates?: Coordinates | null;\n viewportCoordinates?: Coordinates | null;\n children?: number[];\n type?: string;\n text?: string;\n}\n\ninterface BuildDomTreeEvalResult {\n rootId: number;\n map: Record<string, DOMElementData>;\n}\n\nexport interface DomTreeResult {\n elementTree: DOMElementNode | undefined;\n selectorMap: Record<number, DOMElementNode>;\n}\n\nexport class DOMBaseNode {\n is_visible: boolean;\n parent: DOMElementNode | null;\n\n constructor(isVisible: boolean, parent: DOMElementNode | null = null) {\n this.is_visible = isVisible;\n this.parent = parent;\n }\n}\n\nexport class DOMTextNode extends DOMBaseNode {\n text: string;\n type: string;\n\n constructor(text: string, isVisible: boolean, parent: DOMElementNode | null = null) {\n super(isVisible, parent);\n this.text = text;\n this.type = 'TEXT_NODE';\n }\n\n has_parent_with_highlight_index(): boolean {\n let current: DOMElementNode | null = this.parent;\n while (current !== null) {\n if (current.highlight_index !== null && current.highlight_index !== undefined) {\n return true;\n }\n current = current.parent;\n }\n return false;\n }\n}\n\n/**\n * Port of enhanced_css_selector_for_element from Python\n */\nfunction convertSimpleXpathToCssSelector(xpath: string): string {\n if (!xpath) return '';\n\n xpath = xpath.replace(/^\\/+/, '');\n const parts = xpath.split('/');\n const cssParts: string[] = [];\n\n for (let part of parts) {\n if (!part) continue;\n\n if (part.includes(':') && !part.includes('[')) {\n const basePart = part.replace(/:/g, '\\\\:');\n cssParts.push(basePart);\n continue;\n }\n\n if (part.includes('[')) {\n let basePart = part.substring(0, part.indexOf('['));\n\n if (basePart.includes(':')) {\n basePart = basePart.replace(/:/g, '\\\\:');\n }\n\n const indexPart = part.substring(part.indexOf('['));\n const indices = indexPart.split(']').filter(i => i).map(i => i.replace('[', ''));\n\n for (const idx of indices) {\n try {\n if (/^\\d+$/.test(idx)) {\n const index = parseInt(idx) - 1;\n basePart += `:nth-of-type(${index + 1})`;\n } else if (idx === 'last()') {\n basePart += ':last-of-type';\n } else if (idx.includes('position()') && idx.includes('>1')) {\n basePart += ':nth-of-type(n+2)';\n }\n } catch (e) {\n continue;\n }\n }\n\n cssParts.push(basePart);\n } else {\n cssParts.push(part);\n }\n }\n\n return cssParts.join(' > ');\n}\n\nfunction enhancedCssSelectorForElement(element: DOMElementNode, includeDynamicAttributes = true): string {\n try {\n let cssSelector = convertSimpleXpathToCssSelector(element.xpath);\n\n if (element.attributes.class && includeDynamicAttributes) {\n const validClassNamePattern = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;\n const classes = element.attributes.class.split(/\\s+/);\n\n for (const className of classes) {\n if (!className.trim()) continue;\n if (validClassNamePattern.test(className)) {\n cssSelector += `.${className}`;\n }\n }\n }\n\n const SAFE_ATTRIBUTES = new Set([\n 'id', 'name', 'type', 'placeholder',\n 'aria-label', 'aria-labelledby', 'aria-describedby', 'role',\n 'for', 'autocomplete', 'required', 'readonly',\n 'alt', 'title', 'src', 'href', 'target'\n ]);\n\n if (includeDynamicAttributes) {\n SAFE_ATTRIBUTES.add('data-id');\n SAFE_ATTRIBUTES.add('data-qa');\n SAFE_ATTRIBUTES.add('data-cy');\n SAFE_ATTRIBUTES.add('data-testid');\n }\n\n for (const [attribute, value] of Object.entries(element.attributes)) {\n if (attribute === 'class') continue;\n if (!attribute.trim()) continue;\n if (!SAFE_ATTRIBUTES.has(attribute)) continue;\n\n const safeAttribute = attribute.replace(/:/g, '\\\\:');\n\n if (value === '') {\n cssSelector += `[${safeAttribute}]`;\n } else if (/[\"'<>`\\n\\r\\t]/.test(value)) {\n let processedValue = value;\n if (processedValue.includes('\\n')) {\n processedValue = processedValue.split('\\n')[0];\n }\n const collapsedValue = processedValue.replace(/\\s+/g, ' ').trim();\n const safeValue = collapsedValue.replace(/\"/g, '\\\\\"');\n cssSelector += `[${safeAttribute}*=\"${safeValue}\"]`;\n } else {\n cssSelector += `[${safeAttribute}=\"${value}\"]`;\n }\n }\n\n return cssSelector;\n\n } catch (error) {\n const tagName = element.tag_name || '*';\n return `${tagName}[highlight_index='${element.highlight_index}']`;\n }\n}\n\nexport class DOMElementNode extends DOMBaseNode {\n tag_name: string;\n xpath: string;\n attributes: Record<string, string>;\n children: (DOMElementNode | DOMTextNode)[];\n childrenTags: string[];\n is_interactive: boolean;\n is_reference: boolean;\n is_top_element: boolean;\n is_in_viewport: boolean;\n shadow_root: boolean;\n highlight_index: number | null | undefined;\n page_coordinates: Coordinates | null;\n viewport_coordinates: Coordinates | null;\n private _css_selector: string | null;\n\n constructor(data: DOMElementData) {\n super(data.isVisible || false, null);\n\n this.tag_name = data.tagName || '';\n this.xpath = data.xpath || '';\n this.attributes = data.attributes || {};\n this.children = [];\n this.childrenTags = data.childrenTags || [];\n this.is_interactive = data.isInteractive || false;\n this.is_reference = data.isReference || false;\n this.is_top_element = data.isTopElement || false;\n this.is_in_viewport = data.isInViewport || false;\n this.shadow_root = data.shadowRoot || false;\n this.highlight_index = data.highlightIndex;\n this.page_coordinates = data.pageCoordinates || null;\n this.viewport_coordinates = data.viewportCoordinates || null;\n this._css_selector = null;\n }\n\n get css_selector(): string {\n if (this._css_selector === null) {\n this._css_selector = enhancedCssSelectorForElement(this, true);\n }\n return this._css_selector;\n }\n\n get_meaningful_text(): string {\n const semanticAttrs = ['value', 'aria-label', 'title', 'placeholder', 'alt', 'name'];\n for (const attr of semanticAttrs) {\n if (this.attributes[attr]) {\n return this.clean_text(this.attributes[attr]);\n }\n }\n\n const tag = this.tag_name.toLowerCase();\n\n if (tag === 'a') {\n for (const child of this.children) {\n if (!(child instanceof DOMElementNode)) continue;\n const ctag = child.tag_name.toLowerCase();\n\n if (ctag === 'img') {\n const alt = child.attributes.alt || '';\n const title = child.attributes.title || '';\n if (alt) return this.clean_text(alt);\n if (title) return this.clean_text(title);\n } else if (ctag === 'svg') {\n const ariaLabel = child.attributes['aria-label'] || '';\n const title = child.attributes.title || '';\n if (ariaLabel) return this.clean_text(ariaLabel);\n if (title) return this.clean_text(title);\n\n for (const g of child.children) {\n if (g instanceof DOMElementNode && g.tag_name.toLowerCase() === 'title') {\n const titleText = this.get_all_text_from_node(g);\n if (titleText) return this.clean_text(titleText);\n }\n }\n }\n }\n }\n\n if (tag === 'img') {\n const alt = this.attributes.alt || '';\n const title = this.attributes.title || '';\n if (alt) return this.clean_text(alt);\n if (title) return this.clean_text(title);\n }\n\n if (tag === 'svg') {\n const ariaLabel = this.attributes['aria-label'] || '';\n const title = this.attributes.title || '';\n if (ariaLabel) return this.clean_text(ariaLabel);\n if (title) return this.clean_text(title);\n\n for (const child of this.children) {\n if (child instanceof DOMElementNode && child.tag_name.toLowerCase() === 'title') {\n const titleText = this.get_all_text_from_node(child);\n if (titleText) return this.clean_text(titleText);\n }\n }\n }\n\n const textVal = this.get_all_children_text(-1).trim();\n return textVal ? this.clean_text(textVal) : '';\n }\n\n get_all_children_text(maxDepth = 1): string {\n const textParts: string[] = [];\n\n const collectText = (node: DOMElementNode | DOMTextNode, currentDepth: number): void => {\n if (maxDepth !== -1 && currentDepth > maxDepth) return;\n\n if (node instanceof DOMTextNode) {\n if (node.text && node.is_visible) {\n textParts.push(node.text.trim());\n }\n } else if (node instanceof DOMElementNode) {\n for (const child of node.children) {\n collectText(child, currentDepth + 1);\n }\n }\n };\n\n const children = this.children || [];\n\n if (children.length === 1 && children[0] instanceof DOMElementNode) {\n const child = children[0];\n const tag = child.tag_name.toLowerCase();\n if (tag === 'div' || tag === 'span') {\n for (const gc of child.children) {\n collectText(gc, 1);\n }\n return textParts.filter(t => t).join(' ');\n }\n }\n\n for (const child of children) {\n collectText(child, 1);\n }\n\n return textParts.filter(t => t).join(' ');\n }\n\n get_all_text_from_node(node: DOMElementNode | DOMTextNode): string {\n if (node instanceof DOMTextNode) {\n return node.text;\n } else if (node instanceof DOMElementNode) {\n return node.get_all_children_text(-1);\n }\n return '';\n }\n\n clean_text(text: string): string {\n if (!text) return '';\n\n const parts = text.split(/\\s+/);\n const mid = Math.floor(parts.length / 2);\n\n if (parts.length > 1) {\n const firstHalf = parts.slice(0, mid).join(' ');\n const secondHalf = parts.slice(mid).join(' ');\n if (firstHalf === secondHalf) {\n return firstHalf;\n }\n }\n\n return parts.join(' ');\n }\n}\n\n/**\n * Port of DomService from Python service.py\n */\nexport class DomService {\n async buildDomTree(\n page: Page,\n jsCode: string,\n options: {\n highlightElements?: boolean;\n focusElement?: number;\n viewportExpansion?: number;\n debugMode?: boolean;\n } = {}\n ): Promise<DomTreeResult> {\n const args = {\n doHighlightElements: options.highlightElements ?? true,\n focusHighlightIndex: options.focusElement ?? -1,\n viewportExpansion: options.viewportExpansion ?? -1,\n debugMode: options.debugMode ?? false\n };\n\n // Execute JS in browser\n const evalPage = await page.evaluate(({ code, params }: { code: string; params: typeof args }) => {\n eval(code);\n return (window as any).buildDomTreeMain(params);\n }, { code: jsCode, params: args }) as BuildDomTreeEvalResult;\n\n return this.constructDomTree(evalPage);\n }\n\n private constructDomTree(evalPage: BuildDomTreeEvalResult): DomTreeResult {\n const jsNodeMap = evalPage.map;\n const jsRootId = evalPage.rootId;\n\n const selectorMap: Record<number, DOMElementNode> = {};\n const nodeMap = new Map<string, DOMElementNode | DOMTextNode>();\n const childrenMap = new Map<string, number[]>();\n\n for (const [id, nodeData] of Object.entries(jsNodeMap)) {\n const { node, childrenIds } = this.parseNode(nodeData);\n if (!node) continue;\n\n nodeMap.set(id, node);\n childrenMap.set(id, childrenIds);\n\n if (node instanceof DOMElementNode && node.highlight_index !== null && node.highlight_index !== undefined) {\n selectorMap[node.highlight_index] = node;\n }\n }\n\n for (const [idStr, node] of nodeMap.entries()) {\n if (node instanceof DOMElementNode) {\n const childIds = childrenMap.get(idStr) || [];\n for (const childId of childIds) {\n const childNode = nodeMap.get(String(childId));\n if (childNode) {\n childNode.parent = node;\n node.children.push(childNode);\n }\n }\n }\n }\n\n const rootNode = nodeMap.get(String(jsRootId)) as DOMElementNode | undefined;\n\n return { elementTree: rootNode, selectorMap };\n }\n\n private parseNode(nodeData: DOMElementData): { node: DOMElementNode | DOMTextNode | null; childrenIds: number[] } {\n if (!nodeData) return { node: null, childrenIds: [] };\n\n if (nodeData.type === 'TEXT_NODE') {\n const textNode = new DOMTextNode(\n nodeData.text || '',\n nodeData.isVisible || false,\n null\n );\n return { node: textNode, childrenIds: [] };\n }\n\n const elementNode = new DOMElementNode(nodeData);\n const childrenIds = nodeData.children || [];\n\n return { node: elementNode, childrenIds };\n }\n}\n"],"mappings":"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","names":["evalPage"]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DOM Node Classes - Port from Python views.py
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface Coordinates {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}
|
|
13
|
+
interface DOMElementData {
|
|
14
|
+
tagName?: string;
|
|
15
|
+
xpath?: string;
|
|
16
|
+
attributes?: Record<string, string>;
|
|
17
|
+
childrenTags?: string[];
|
|
18
|
+
isInteractive?: boolean;
|
|
19
|
+
isReference?: boolean;
|
|
20
|
+
isTopElement?: boolean;
|
|
21
|
+
isInViewport?: boolean;
|
|
22
|
+
isVisible?: boolean;
|
|
23
|
+
shadowRoot?: boolean;
|
|
24
|
+
highlightIndex?: number | null;
|
|
25
|
+
pageCoordinates?: Coordinates | null;
|
|
26
|
+
viewportCoordinates?: Coordinates | null;
|
|
27
|
+
children?: number[];
|
|
28
|
+
type?: string;
|
|
29
|
+
text?: string;
|
|
30
|
+
}
|
|
31
|
+
interface DomTreeResult {
|
|
32
|
+
elementTree: DOMElementNode | undefined;
|
|
33
|
+
selectorMap: Record<number, DOMElementNode>;
|
|
34
|
+
}
|
|
35
|
+
declare class DOMBaseNode {
|
|
36
|
+
is_visible: boolean;
|
|
37
|
+
parent: DOMElementNode | null;
|
|
38
|
+
constructor(isVisible: boolean, parent?: DOMElementNode | null);
|
|
39
|
+
}
|
|
40
|
+
declare class DOMTextNode extends DOMBaseNode {
|
|
41
|
+
text: string;
|
|
42
|
+
type: string;
|
|
43
|
+
constructor(text: string, isVisible: boolean, parent?: DOMElementNode | null);
|
|
44
|
+
has_parent_with_highlight_index(): boolean;
|
|
45
|
+
}
|
|
46
|
+
declare class DOMElementNode extends DOMBaseNode {
|
|
47
|
+
tag_name: string;
|
|
48
|
+
xpath: string;
|
|
49
|
+
attributes: Record<string, string>;
|
|
50
|
+
children: (DOMElementNode | DOMTextNode)[];
|
|
51
|
+
childrenTags: string[];
|
|
52
|
+
is_interactive: boolean;
|
|
53
|
+
is_reference: boolean;
|
|
54
|
+
is_top_element: boolean;
|
|
55
|
+
is_in_viewport: boolean;
|
|
56
|
+
shadow_root: boolean;
|
|
57
|
+
highlight_index: number | null | undefined;
|
|
58
|
+
page_coordinates: Coordinates | null;
|
|
59
|
+
viewport_coordinates: Coordinates | null;
|
|
60
|
+
private _css_selector;
|
|
61
|
+
constructor(data: DOMElementData);
|
|
62
|
+
get css_selector(): string;
|
|
63
|
+
get_meaningful_text(): string;
|
|
64
|
+
get_all_children_text(maxDepth?: number): string;
|
|
65
|
+
get_all_text_from_node(node: DOMElementNode | DOMTextNode): string;
|
|
66
|
+
clean_text(text: string): string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Port of DomService from Python service.py
|
|
70
|
+
*/
|
|
71
|
+
declare class DomService {
|
|
72
|
+
buildDomTree(page: Page, jsCode: string, options?: {
|
|
73
|
+
highlightElements?: boolean;
|
|
74
|
+
focusElement?: number;
|
|
75
|
+
viewportExpansion?: number;
|
|
76
|
+
debugMode?: boolean;
|
|
77
|
+
}): Promise<DomTreeResult>;
|
|
78
|
+
private constructDomTree;
|
|
79
|
+
private parseNode;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { type Coordinates, DOMBaseNode, type DOMElementData, DOMElementNode, DOMTextNode, DomService, type DomTreeResult };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DOM Node Classes - Port from Python views.py
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface Coordinates {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}
|
|
13
|
+
interface DOMElementData {
|
|
14
|
+
tagName?: string;
|
|
15
|
+
xpath?: string;
|
|
16
|
+
attributes?: Record<string, string>;
|
|
17
|
+
childrenTags?: string[];
|
|
18
|
+
isInteractive?: boolean;
|
|
19
|
+
isReference?: boolean;
|
|
20
|
+
isTopElement?: boolean;
|
|
21
|
+
isInViewport?: boolean;
|
|
22
|
+
isVisible?: boolean;
|
|
23
|
+
shadowRoot?: boolean;
|
|
24
|
+
highlightIndex?: number | null;
|
|
25
|
+
pageCoordinates?: Coordinates | null;
|
|
26
|
+
viewportCoordinates?: Coordinates | null;
|
|
27
|
+
children?: number[];
|
|
28
|
+
type?: string;
|
|
29
|
+
text?: string;
|
|
30
|
+
}
|
|
31
|
+
interface DomTreeResult {
|
|
32
|
+
elementTree: DOMElementNode | undefined;
|
|
33
|
+
selectorMap: Record<number, DOMElementNode>;
|
|
34
|
+
}
|
|
35
|
+
declare class DOMBaseNode {
|
|
36
|
+
is_visible: boolean;
|
|
37
|
+
parent: DOMElementNode | null;
|
|
38
|
+
constructor(isVisible: boolean, parent?: DOMElementNode | null);
|
|
39
|
+
}
|
|
40
|
+
declare class DOMTextNode extends DOMBaseNode {
|
|
41
|
+
text: string;
|
|
42
|
+
type: string;
|
|
43
|
+
constructor(text: string, isVisible: boolean, parent?: DOMElementNode | null);
|
|
44
|
+
has_parent_with_highlight_index(): boolean;
|
|
45
|
+
}
|
|
46
|
+
declare class DOMElementNode extends DOMBaseNode {
|
|
47
|
+
tag_name: string;
|
|
48
|
+
xpath: string;
|
|
49
|
+
attributes: Record<string, string>;
|
|
50
|
+
children: (DOMElementNode | DOMTextNode)[];
|
|
51
|
+
childrenTags: string[];
|
|
52
|
+
is_interactive: boolean;
|
|
53
|
+
is_reference: boolean;
|
|
54
|
+
is_top_element: boolean;
|
|
55
|
+
is_in_viewport: boolean;
|
|
56
|
+
shadow_root: boolean;
|
|
57
|
+
highlight_index: number | null | undefined;
|
|
58
|
+
page_coordinates: Coordinates | null;
|
|
59
|
+
viewport_coordinates: Coordinates | null;
|
|
60
|
+
private _css_selector;
|
|
61
|
+
constructor(data: DOMElementData);
|
|
62
|
+
get css_selector(): string;
|
|
63
|
+
get_meaningful_text(): string;
|
|
64
|
+
get_all_children_text(maxDepth?: number): string;
|
|
65
|
+
get_all_text_from_node(node: DOMElementNode | DOMTextNode): string;
|
|
66
|
+
clean_text(text: string): string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Port of DomService from Python service.py
|
|
70
|
+
*/
|
|
71
|
+
declare class DomService {
|
|
72
|
+
buildDomTree(page: Page, jsCode: string, options?: {
|
|
73
|
+
highlightElements?: boolean;
|
|
74
|
+
focusElement?: number;
|
|
75
|
+
viewportExpansion?: number;
|
|
76
|
+
debugMode?: boolean;
|
|
77
|
+
}): Promise<DomTreeResult>;
|
|
78
|
+
private constructDomTree;
|
|
79
|
+
private parseNode;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { type Coordinates, DOMBaseNode, type DOMElementData, DOMElementNode, DOMTextNode, DomService, type DomTreeResult };
|