ff-dom 1.0.18-beta.5 → 1.0.18
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/index.browser.cjs +200 -199
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +200 -199
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cdn.js +200 -199
- package/dist/types/browser/browser/xpath.d.ts +5 -2
- package/dist/types/browser/utils/xpath.d.ts +4 -1
- package/dist/types/browser/utils/xpathHelpers.d.ts +2 -2
- package/dist/types/node/node/xpath.d.ts +1 -1
- package/dist/xpath.mjs +7 -6
- package/dist/xpath.mjs.map +1 -1
- package/package.json +1 -1
- package/src/node/xpath.ts +7 -6
- package/src/utils/getElementsFromHTML.ts +240 -240
- package/src/utils/xpath.ts +3 -1
- package/src/utils/xpathHelpers.ts +2 -2
package/src/node/xpath.ts
CHANGED
|
@@ -14,11 +14,11 @@ const injectScript = readFileSync(injectScriptPath, "utf-8");
|
|
|
14
14
|
async function createXPathAPI() {
|
|
15
15
|
puppeteer = await import('puppeteer');
|
|
16
16
|
|
|
17
|
-
let browser = await puppeteer.launch({ headless: true });
|
|
17
|
+
let browser = await puppeteer.launch({ headless: true, debugger: true });
|
|
18
18
|
let page = await browser.newPage();
|
|
19
19
|
|
|
20
20
|
const fromHTML = async (html: string) => {
|
|
21
|
-
await page?.setContent(html);
|
|
21
|
+
await page?.setContent(html.replace(/\\n/g, '').replaceAll(/\\t/g, '').replace(/\\"/g, '"'), { waitUntil: 'domcontentloaded' });
|
|
22
22
|
await page?.addScriptTag({ content: injectScript });
|
|
23
23
|
|
|
24
24
|
page?.on(
|
|
@@ -59,12 +59,13 @@ async function createXPathAPI() {
|
|
|
59
59
|
|
|
60
60
|
return {
|
|
61
61
|
autoHeal: async (data: ElementRecord, htmlString: string) => {
|
|
62
|
-
await page?.evaluate((datum: ElementRecord
|
|
62
|
+
return await page?.evaluate((datum: ElementRecord) => {
|
|
63
63
|
// @ts-ignore
|
|
64
64
|
let xpathAPI = window.XpathLib.createXPathAPI();
|
|
65
|
-
let
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
let xpaths = xpathAPI.getElementsFromHTML(datum, document);
|
|
66
|
+
// console.log(xpaths);
|
|
67
|
+
return xpaths;
|
|
68
|
+
}, data);
|
|
68
69
|
},
|
|
69
70
|
};
|
|
70
71
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ElementRecord, Locator } from "../types/locator.ts";
|
|
2
2
|
import { parseDOM } from "./xpath.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { normalizeXPath } from "./xpathHelpers.ts";
|
|
4
4
|
|
|
5
5
|
type ElementDetails = {
|
|
6
6
|
id?: string | null;
|
|
@@ -18,12 +18,30 @@ type ElementDetails = {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
const getElementFromShadowRoot = (
|
|
21
|
-
|
|
21
|
+
el: Element | ShadowRoot,
|
|
22
22
|
selector: string
|
|
23
23
|
): Element | null => {
|
|
24
|
-
const shadowRoot = (element as HTMLElement).shadowRoot;
|
|
25
|
-
if (shadowRoot && !selector.includes("dynamic")) {
|
|
26
|
-
|
|
24
|
+
// const shadowRoot = (element as HTMLElement).shadowRoot;
|
|
25
|
+
// if (shadowRoot && !selector.includes("dynamic")) {
|
|
26
|
+
// return shadowRoot.querySelector(selector);
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
const elements = Array.from(el.querySelectorAll('*'));
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
for (let i = 0; i < elements.length; i++) {
|
|
33
|
+
if (elements[i].shadowRoot) {
|
|
34
|
+
const { shadowRoot } = elements[i];
|
|
35
|
+
if (shadowRoot) {
|
|
36
|
+
getElementFromShadowRoot(shadowRoot, selector);
|
|
37
|
+
if (shadowRoot && !selector.includes("dynamic")) {
|
|
38
|
+
return shadowRoot.querySelector(selector);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.log(error);
|
|
27
45
|
}
|
|
28
46
|
return null;
|
|
29
47
|
};
|
|
@@ -65,17 +83,16 @@ const relations: string[] = [
|
|
|
65
83
|
];
|
|
66
84
|
|
|
67
85
|
function getElementFromXPath(
|
|
68
|
-
|
|
86
|
+
docmt: Document,
|
|
69
87
|
xpath: string
|
|
70
88
|
): Element | null {
|
|
71
|
-
|
|
72
|
-
const window = currentElement.ownerDocument.defaultView;
|
|
89
|
+
const window = docmt.defaultView;
|
|
73
90
|
if (!window) return null;
|
|
74
91
|
|
|
75
92
|
const xpathEvaluator = new window.XPathEvaluator();
|
|
76
93
|
const xpathResult = xpathEvaluator.evaluate(
|
|
77
94
|
xpath,
|
|
78
|
-
|
|
95
|
+
docmt,
|
|
79
96
|
null,
|
|
80
97
|
window.XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
81
98
|
null
|
|
@@ -86,19 +103,18 @@ function getElementFromXPath(
|
|
|
86
103
|
function checkReferenceElementIsValid(
|
|
87
104
|
locator: string,
|
|
88
105
|
relation: string,
|
|
89
|
-
|
|
106
|
+
docmt: Document
|
|
90
107
|
): string | null {
|
|
91
108
|
if (locator.includes(relation)) {
|
|
92
109
|
const locatotSplitArray: string[] = locator.split(relation);
|
|
93
110
|
const sourceLoc = locatotSplitArray[0].trim();
|
|
94
|
-
|
|
95
|
-
const window = currentElement.ownerDocument.defaultView;
|
|
111
|
+
const window = docmt.defaultView;
|
|
96
112
|
if (!window) return null;
|
|
97
113
|
if (!locator.includes("dynamic")) {
|
|
98
114
|
const xpathEvaluator = new window.XPathEvaluator();
|
|
99
115
|
const xpathResult = xpathEvaluator.evaluate(
|
|
100
116
|
sourceLoc,
|
|
101
|
-
|
|
117
|
+
docmt,
|
|
102
118
|
null,
|
|
103
119
|
window.XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
104
120
|
null
|
|
@@ -108,7 +124,7 @@ function checkReferenceElementIsValid(
|
|
|
108
124
|
if (sourceElement) {
|
|
109
125
|
const xpathResultComplete = xpathEvaluator.evaluate(
|
|
110
126
|
locator,
|
|
111
|
-
|
|
127
|
+
docmt,
|
|
112
128
|
null,
|
|
113
129
|
window.XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
114
130
|
null
|
|
@@ -135,10 +151,7 @@ const getElementsFromHTML = (
|
|
|
135
151
|
record: ElementRecord,
|
|
136
152
|
docmt: Document
|
|
137
153
|
): ElementDetails | null => {
|
|
138
|
-
const
|
|
139
|
-
// global.SVGElement = document.defaultView?.SVGElement!;
|
|
140
|
-
const tempDiv = document.createElement("div");
|
|
141
|
-
const elementsToRemove = document.querySelectorAll(
|
|
154
|
+
const elementsToRemove = docmt.querySelectorAll(
|
|
142
155
|
"script, style, link[rel='stylesheet'], meta, noscript, embed, object, param, source, svg"
|
|
143
156
|
);
|
|
144
157
|
|
|
@@ -148,7 +161,6 @@ const getElementsFromHTML = (
|
|
|
148
161
|
});
|
|
149
162
|
}
|
|
150
163
|
|
|
151
|
-
tempDiv.innerHTML = document.body.innerHTML;
|
|
152
164
|
const finalLocatorsSet: Set<string> = new Set();
|
|
153
165
|
let finalLocators: any[] = [];
|
|
154
166
|
|
|
@@ -247,170 +259,158 @@ const getElementsFromHTML = (
|
|
|
247
259
|
break locators;
|
|
248
260
|
}
|
|
249
261
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
);
|
|
264
|
-
}
|
|
262
|
+
try {
|
|
263
|
+
let targetElement: Element | null = null;
|
|
264
|
+
if (locator.value.startsWith("iframe")) {
|
|
265
|
+
const iframe = docmt.querySelector(
|
|
266
|
+
locator.value
|
|
267
|
+
) as HTMLIFrameElement;
|
|
268
|
+
if (iframe) {
|
|
269
|
+
const iframeDocument =
|
|
270
|
+
iframe.contentDocument || iframe.contentWindow?.document;
|
|
271
|
+
if (iframeDocument) {
|
|
272
|
+
targetElement = iframeDocument.querySelector(
|
|
273
|
+
locator.value.slice(6)
|
|
274
|
+
);
|
|
265
275
|
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
} else {
|
|
308
|
-
targetElement = currentElement.querySelector(trimmedSelector);
|
|
309
|
-
if (!targetElement) {
|
|
310
|
-
targetElement = getElementFromShadowRoot(
|
|
311
|
-
currentElement,
|
|
312
|
-
trimmedSelector
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (
|
|
318
|
-
!targetElement &&
|
|
319
|
-
isSvg(currentElement) &&
|
|
320
|
-
!locator.type.match("dynamic")
|
|
321
|
-
) {
|
|
322
|
-
targetElement = currentElement.querySelector(trimmedSelector);
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
const selectors = locator.value.split(">>>"); // Custom delimiter for shadow DOM
|
|
279
|
+
|
|
280
|
+
for (const selector of selectors) {
|
|
281
|
+
if (docmt) {
|
|
282
|
+
const trimmedSelector = selector.trim();
|
|
283
|
+
if (
|
|
284
|
+
locator.name.includes("id") ||
|
|
285
|
+
trimmedSelector.startsWith("#")
|
|
286
|
+
) {
|
|
287
|
+
targetElement = docmt.querySelector(
|
|
288
|
+
"#" + trimmedSelector
|
|
289
|
+
);
|
|
290
|
+
} else if (
|
|
291
|
+
locator.name.includes("className") ||
|
|
292
|
+
trimmedSelector.startsWith(".")
|
|
293
|
+
) {
|
|
294
|
+
targetElement = docmt.querySelector(
|
|
295
|
+
"." + trimmedSelector
|
|
296
|
+
);
|
|
297
|
+
} else if (
|
|
298
|
+
(locator.name.includes("xpath") ||
|
|
299
|
+
trimmedSelector.startsWith("//")) &&
|
|
300
|
+
!locator.type.match("dynamic")
|
|
301
|
+
) {
|
|
302
|
+
const normalizedXPath = normalizeXPath(trimmedSelector);
|
|
303
|
+
targetElement = getElementFromXPath(
|
|
304
|
+
docmt,
|
|
305
|
+
normalizedXPath
|
|
306
|
+
);
|
|
307
|
+
if (targetElement) {
|
|
308
|
+
createLocator(locator, {
|
|
309
|
+
value: trimmedSelector,
|
|
310
|
+
isRecorded: String(locator.isRecorded).includes("N")
|
|
311
|
+
? "N"
|
|
312
|
+
: "Y",
|
|
313
|
+
});
|
|
323
314
|
}
|
|
324
|
-
currentElement = targetElement;
|
|
325
315
|
} else {
|
|
326
|
-
|
|
327
|
-
|
|
316
|
+
targetElement = docmt.querySelector(trimmedSelector);
|
|
317
|
+
if (!targetElement) {
|
|
318
|
+
targetElement = getElementFromShadowRoot(
|
|
319
|
+
docmt.body,
|
|
320
|
+
trimmedSelector
|
|
321
|
+
);
|
|
322
|
+
}
|
|
328
323
|
}
|
|
324
|
+
} else {
|
|
325
|
+
console.error("Element not found at:", selector);
|
|
326
|
+
break;
|
|
329
327
|
}
|
|
330
328
|
}
|
|
329
|
+
}
|
|
331
330
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
});
|
|
331
|
+
const locatorExists = (name: string, value: string): boolean => {
|
|
332
|
+
const key = `${name}:${value}`;
|
|
333
|
+
return finalLocatorsSet.has(key);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
if (targetElement) {
|
|
337
|
+
const idValue = getId(targetElement);
|
|
338
|
+
if (idValue && !locatorExists("id", idValue)) {
|
|
339
|
+
record.locators.forEach((loc) => {
|
|
340
|
+
createLocator(loc, {
|
|
341
|
+
name: "id",
|
|
342
|
+
value: idValue,
|
|
343
|
+
isRecorded:
|
|
344
|
+
loc.value === idValue && loc.name === "id"
|
|
345
|
+
? loc.isRecorded
|
|
346
|
+
: "Y",
|
|
347
|
+
isSelfHealed:
|
|
348
|
+
loc.value === idValue && loc.name === "id"
|
|
349
|
+
? loc.isSelfHealed
|
|
350
|
+
: "Y",
|
|
353
351
|
});
|
|
354
|
-
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
355
354
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
});
|
|
355
|
+
const textValue = getVisibleText(targetElement);
|
|
356
|
+
if (textValue) {
|
|
357
|
+
record.locators.forEach((loc) => {
|
|
358
|
+
createLocator(loc, {
|
|
359
|
+
name: "linkText",
|
|
360
|
+
type: "static",
|
|
361
|
+
value: textValue,
|
|
362
|
+
isRecorded: loc.value === textValue ? loc.isRecorded : "Y",
|
|
363
|
+
isSelfHealed:
|
|
364
|
+
loc.value === textValue ? loc.isSelfHealed : "Y",
|
|
367
365
|
});
|
|
368
|
-
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
369
368
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
});
|
|
369
|
+
const nameLocator = getName(targetElement);
|
|
370
|
+
if (nameLocator && !locatorExists("name", nameLocator)) {
|
|
371
|
+
record.locators.forEach((loc) => {
|
|
372
|
+
createLocator(loc, {
|
|
373
|
+
name: "name",
|
|
374
|
+
type: "static",
|
|
375
|
+
value: nameLocator,
|
|
376
|
+
isRecorded:
|
|
377
|
+
loc.value === nameLocator && loc.name === "name"
|
|
378
|
+
? loc.isRecorded
|
|
379
|
+
: "Y",
|
|
380
|
+
isSelfHealed:
|
|
381
|
+
loc.value === nameLocator && loc.name === "name"
|
|
382
|
+
? loc.isSelfHealed
|
|
383
|
+
: "Y",
|
|
386
384
|
});
|
|
387
|
-
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
388
387
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
});
|
|
388
|
+
const classValue = getClassName(targetElement);
|
|
389
|
+
if (
|
|
390
|
+
classValue &&
|
|
391
|
+
classValue.trim() !== "" &&
|
|
392
|
+
!locatorExists("className", classValue)
|
|
393
|
+
) {
|
|
394
|
+
record.locators.forEach((loc) => {
|
|
395
|
+
createLocator(loc, {
|
|
396
|
+
name: "className",
|
|
397
|
+
value: classValue,
|
|
398
|
+
isRecorded:
|
|
399
|
+
loc.value === classValue && loc.name === "className"
|
|
400
|
+
? loc.isRecorded
|
|
401
|
+
: "Y",
|
|
402
|
+
isSelfHealed:
|
|
403
|
+
loc.value === classValue && loc.name === "className"
|
|
404
|
+
? loc.isSelfHealed
|
|
405
|
+
: "Y",
|
|
408
406
|
});
|
|
409
|
-
}
|
|
407
|
+
});
|
|
408
|
+
}
|
|
410
409
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
410
|
+
const xpathResults = parseDOM(targetElement, docmt, false, true);
|
|
411
|
+
xpathResults.forEach((result) => {
|
|
412
|
+
const fnValue = result.value;
|
|
413
|
+
if (fnValue && !locatorExists(result.key.replace('xpath by', '').trim(), fnValue)) {
|
|
414
414
|
record.locators.forEach((loc) => {
|
|
415
415
|
createLocator(loc, {
|
|
416
416
|
name: 'xpath',
|
|
@@ -419,87 +419,87 @@ const getElementsFromHTML = (
|
|
|
419
419
|
isSelfHealed: loc.value === fnValue ? loc.isSelfHealed : 'Y',
|
|
420
420
|
});
|
|
421
421
|
});
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
422
|
+
}
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
for (const locator of record.locators) {
|
|
426
|
+
try {
|
|
427
|
+
for (const loc of record.locators) {
|
|
428
|
+
if (!loc.value) continue;
|
|
429
|
+
|
|
430
|
+
for (const relation of relations) {
|
|
431
|
+
if (loc.value.includes(relation)) {
|
|
432
|
+
const relativeXpath = checkReferenceElementIsValid(
|
|
433
|
+
loc.value,
|
|
434
|
+
relation,
|
|
435
|
+
docmt
|
|
436
|
+
);
|
|
437
|
+
if (relativeXpath) {
|
|
438
|
+
createLocator(loc, {
|
|
439
|
+
name: "xpath",
|
|
440
|
+
value: relativeXpath,
|
|
441
|
+
isRecorded:
|
|
442
|
+
locator.isRecorded !== "" &&
|
|
443
|
+
locator.isRecorded !== null
|
|
444
|
+
? locator.isRecorded
|
|
445
|
+
: "Y",
|
|
446
|
+
});
|
|
447
|
+
break;
|
|
448
448
|
}
|
|
449
449
|
}
|
|
450
450
|
}
|
|
451
|
-
} catch (error) {
|
|
452
|
-
console.error("Error processing locator:", locator, error);
|
|
453
451
|
}
|
|
452
|
+
} catch (error) {
|
|
453
|
+
console.error("Error processing locator:", locator, error);
|
|
454
454
|
}
|
|
455
|
+
}
|
|
455
456
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const finalUniqueAutoHealedLocators: Locator[] =
|
|
462
|
-
finalAutoHealedLocators.reduce(
|
|
463
|
-
(unique: Locator[], locator: Locator) => {
|
|
464
|
-
if (
|
|
465
|
-
locator.value &&
|
|
466
|
-
!unique.some((l: Locator) => l.value === locator.value)
|
|
467
|
-
) {
|
|
468
|
-
unique.push(locator);
|
|
469
|
-
}
|
|
470
|
-
return unique;
|
|
471
|
-
},
|
|
472
|
-
[] as Locator[]
|
|
473
|
-
);
|
|
457
|
+
const finalAutoHealedLocators = finalLocators.map((obj) => ({
|
|
458
|
+
...obj,
|
|
459
|
+
value: cleanLocatorValue(obj.value, obj.name, obj.isRecorded),
|
|
460
|
+
}));
|
|
474
461
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
projectType: `${record.projectType}`,
|
|
486
|
-
isRecorded: `${record.isRecorded}`,
|
|
487
|
-
folder: `${record.folder}`,
|
|
488
|
-
parentId: `${record.parentId}`,
|
|
489
|
-
parentName: `${record.parentName}`,
|
|
490
|
-
platform: `${record.platform}`,
|
|
491
|
-
licenseId: `${record.licenseId}`,
|
|
492
|
-
licenseType: `${record.licenseType}`,
|
|
493
|
-
userId: `${record.userId}`,
|
|
462
|
+
const finalUniqueAutoHealedLocators: Locator[] =
|
|
463
|
+
finalAutoHealedLocators.reduce(
|
|
464
|
+
(unique: Locator[], locator: Locator) => {
|
|
465
|
+
if (
|
|
466
|
+
locator.value &&
|
|
467
|
+
!unique.some((l: Locator) => l.value === locator.value)
|
|
468
|
+
) {
|
|
469
|
+
unique.push(locator);
|
|
470
|
+
}
|
|
471
|
+
return unique;
|
|
494
472
|
},
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
473
|
+
[] as Locator[]
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
const jsonResult = [
|
|
477
|
+
{
|
|
478
|
+
name: `${record.name}`,
|
|
479
|
+
desc: `${record.desc}`,
|
|
480
|
+
type: `${record.type}`,
|
|
481
|
+
locators: finalUniqueAutoHealedLocators.filter(
|
|
482
|
+
(locator) => locator?.value != null && locator.value !== ""
|
|
483
|
+
),
|
|
484
|
+
isShared: `${record.isShared}`,
|
|
485
|
+
projectId: `${record.projectId}`,
|
|
486
|
+
projectType: `${record.projectType}`,
|
|
487
|
+
isRecorded: `${record.isRecorded}`,
|
|
488
|
+
folder: `${record.folder}`,
|
|
489
|
+
parentId: `${record.parentId}`,
|
|
490
|
+
parentName: `${record.parentName}`,
|
|
491
|
+
platform: `${record.platform}`,
|
|
492
|
+
licenseId: `${record.licenseId}`,
|
|
493
|
+
licenseType: `${record.licenseType}`,
|
|
494
|
+
userId: `${record.userId}`,
|
|
495
|
+
},
|
|
496
|
+
];
|
|
497
|
+
|
|
498
|
+
return jsonResult;
|
|
502
499
|
}
|
|
500
|
+
} catch (error) {
|
|
501
|
+
console.error("Error processing locator:", locator, error);
|
|
502
|
+
continue;
|
|
503
503
|
}
|
|
504
504
|
} catch (error) {
|
|
505
505
|
console.error("Error processing locator:", locator, error);
|
package/src/utils/xpath.ts
CHANGED
|
@@ -952,7 +952,7 @@ const addAllXPathAttributes = (
|
|
|
952
952
|
docmt: Document,
|
|
953
953
|
isIndex: boolean,
|
|
954
954
|
isTarget: boolean
|
|
955
|
-
) => {
|
|
955
|
+
): { key: string; value: string }[] => {
|
|
956
956
|
const attributesArray = attributes;
|
|
957
957
|
try {
|
|
958
958
|
attributesArray.map((attr) => {
|
|
@@ -1030,6 +1030,8 @@ const addAllXPathAttributes = (
|
|
|
1030
1030
|
} catch (error) {
|
|
1031
1031
|
console.log(error);
|
|
1032
1032
|
}
|
|
1033
|
+
|
|
1034
|
+
return xpathData;
|
|
1033
1035
|
};
|
|
1034
1036
|
|
|
1035
1037
|
export const parseDOM = (
|
|
@@ -1224,9 +1224,9 @@ export const getReferenceElementsXpath = (
|
|
|
1224
1224
|
return xpaths1;
|
|
1225
1225
|
};
|
|
1226
1226
|
|
|
1227
|
-
export const parseXml = (xmlStr: string): Document | null => {
|
|
1227
|
+
export const parseXml = (xmlStr: string, type: DOMParserSupportedType): Document | null => {
|
|
1228
1228
|
if (window.DOMParser) {
|
|
1229
|
-
return new window.DOMParser().parseFromString(xmlStr,
|
|
1229
|
+
return new window.DOMParser().parseFromString(xmlStr, type);
|
|
1230
1230
|
}
|
|
1231
1231
|
|
|
1232
1232
|
return null;
|