ff-dom 1.0.18-beta.6 → 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/dist/index.browser.cjs +197 -196
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +197 -196
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cdn.js +197 -196
- package/dist/types/browser/browser/xpath.d.ts +1 -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 +6 -5
- package/dist/xpath.mjs.map +1 -1
- package/package.json +1 -1
- package/src/node/xpath.ts +6 -5
- package/src/utils/getElementsFromHTML.ts +240 -240
- package/src/utils/xpathHelpers.ts +2 -2
package/dist/index.browser.cjs
CHANGED
|
@@ -869,9 +869,9 @@ const getReferenceElementsXpath = (domNode, docmt, isTarget) => {
|
|
|
869
869
|
}
|
|
870
870
|
return xpaths1;
|
|
871
871
|
};
|
|
872
|
-
const parseXml = (xmlStr) => {
|
|
872
|
+
const parseXml = (xmlStr, type) => {
|
|
873
873
|
if (window.DOMParser) {
|
|
874
|
-
return new window.DOMParser().parseFromString(xmlStr,
|
|
874
|
+
return new window.DOMParser().parseFromString(xmlStr, type);
|
|
875
875
|
}
|
|
876
876
|
return null;
|
|
877
877
|
};
|
|
@@ -2189,10 +2189,27 @@ const referenceXpath = {
|
|
|
2189
2189
|
getReferenceElementXpath,
|
|
2190
2190
|
};
|
|
2191
2191
|
|
|
2192
|
-
const getElementFromShadowRoot = (
|
|
2193
|
-
const shadowRoot = element.shadowRoot;
|
|
2194
|
-
if (shadowRoot && !selector.includes("dynamic")) {
|
|
2195
|
-
|
|
2192
|
+
const getElementFromShadowRoot = (el, selector) => {
|
|
2193
|
+
// const shadowRoot = (element as HTMLElement).shadowRoot;
|
|
2194
|
+
// if (shadowRoot && !selector.includes("dynamic")) {
|
|
2195
|
+
// return shadowRoot.querySelector(selector);
|
|
2196
|
+
// }
|
|
2197
|
+
const elements = Array.from(el.querySelectorAll('*'));
|
|
2198
|
+
try {
|
|
2199
|
+
for (let i = 0; i < elements.length; i++) {
|
|
2200
|
+
if (elements[i].shadowRoot) {
|
|
2201
|
+
const { shadowRoot } = elements[i];
|
|
2202
|
+
if (shadowRoot) {
|
|
2203
|
+
getElementFromShadowRoot(shadowRoot, selector);
|
|
2204
|
+
if (shadowRoot && !selector.includes("dynamic")) {
|
|
2205
|
+
return shadowRoot.querySelector(selector);
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
catch (error) {
|
|
2212
|
+
console.log(error);
|
|
2196
2213
|
}
|
|
2197
2214
|
return null;
|
|
2198
2215
|
};
|
|
@@ -2226,30 +2243,27 @@ const relations = [
|
|
|
2226
2243
|
"/preceding",
|
|
2227
2244
|
"/following",
|
|
2228
2245
|
];
|
|
2229
|
-
function getElementFromXPath(
|
|
2230
|
-
|
|
2231
|
-
const window = currentElement.ownerDocument.defaultView;
|
|
2246
|
+
function getElementFromXPath(docmt, xpath) {
|
|
2247
|
+
const window = docmt.defaultView;
|
|
2232
2248
|
if (!window)
|
|
2233
2249
|
return null;
|
|
2234
2250
|
const xpathEvaluator = new window.XPathEvaluator();
|
|
2235
|
-
const xpathResult = xpathEvaluator.evaluate(xpath,
|
|
2236
|
-
null, window.XPathResult.FIRST_ORDERED_NODE_TYPE, null);
|
|
2251
|
+
const xpathResult = xpathEvaluator.evaluate(xpath, docmt, null, window.XPathResult.FIRST_ORDERED_NODE_TYPE, null);
|
|
2237
2252
|
return xpathResult.singleNodeValue;
|
|
2238
2253
|
}
|
|
2239
|
-
function checkReferenceElementIsValid(locator, relation,
|
|
2254
|
+
function checkReferenceElementIsValid(locator, relation, docmt) {
|
|
2240
2255
|
if (locator.includes(relation)) {
|
|
2241
2256
|
const locatotSplitArray = locator.split(relation);
|
|
2242
2257
|
const sourceLoc = locatotSplitArray[0].trim();
|
|
2243
|
-
|
|
2244
|
-
const window = currentElement.ownerDocument.defaultView;
|
|
2258
|
+
const window = docmt.defaultView;
|
|
2245
2259
|
if (!window)
|
|
2246
2260
|
return null;
|
|
2247
2261
|
if (!locator.includes("dynamic")) {
|
|
2248
2262
|
const xpathEvaluator = new window.XPathEvaluator();
|
|
2249
|
-
const xpathResult = xpathEvaluator.evaluate(sourceLoc,
|
|
2263
|
+
const xpathResult = xpathEvaluator.evaluate(sourceLoc, docmt, null, window.XPathResult.FIRST_ORDERED_NODE_TYPE, null);
|
|
2250
2264
|
const sourceElement = xpathResult.singleNodeValue;
|
|
2251
2265
|
if (sourceElement) {
|
|
2252
|
-
const xpathResultComplete = xpathEvaluator.evaluate(locator,
|
|
2266
|
+
const xpathResultComplete = xpathEvaluator.evaluate(locator, docmt, null, window.XPathResult.FIRST_ORDERED_NODE_TYPE, null);
|
|
2253
2267
|
const completeElement = xpathResultComplete.singleNodeValue;
|
|
2254
2268
|
let relativeXpath;
|
|
2255
2269
|
if (completeElement) {
|
|
@@ -2270,16 +2284,12 @@ function checkReferenceElementIsValid(locator, relation, tempDiv) {
|
|
|
2270
2284
|
return null;
|
|
2271
2285
|
}
|
|
2272
2286
|
const getElementsFromHTML = (record, docmt) => {
|
|
2273
|
-
const
|
|
2274
|
-
// global.SVGElement = document.defaultView?.SVGElement!;
|
|
2275
|
-
const tempDiv = document.createElement("div");
|
|
2276
|
-
const elementsToRemove = document.querySelectorAll("script, style, link[rel='stylesheet'], meta, noscript, embed, object, param, source, svg");
|
|
2287
|
+
const elementsToRemove = docmt.querySelectorAll("script, style, link[rel='stylesheet'], meta, noscript, embed, object, param, source, svg");
|
|
2277
2288
|
if (elementsToRemove) {
|
|
2278
2289
|
elementsToRemove.forEach((tag) => {
|
|
2279
2290
|
tag.remove();
|
|
2280
2291
|
});
|
|
2281
2292
|
}
|
|
2282
|
-
tempDiv.innerHTML = document.body?.innerHTML;
|
|
2283
2293
|
const finalLocatorsSet = new Set();
|
|
2284
2294
|
let finalLocators = [];
|
|
2285
2295
|
function createLocator(base, overrides = {}) {
|
|
@@ -2353,135 +2363,126 @@ const getElementsFromHTML = (record, docmt) => {
|
|
|
2353
2363
|
if (record.isShared.includes("Y")) {
|
|
2354
2364
|
break locators;
|
|
2355
2365
|
}
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
targetElement = iframeDocument.querySelector(locator.value.slice(6));
|
|
2365
|
-
}
|
|
2366
|
+
try {
|
|
2367
|
+
let targetElement = null;
|
|
2368
|
+
if (locator.value.startsWith("iframe")) {
|
|
2369
|
+
const iframe = docmt.querySelector(locator.value);
|
|
2370
|
+
if (iframe) {
|
|
2371
|
+
const iframeDocument = iframe.contentDocument || iframe.contentWindow?.document;
|
|
2372
|
+
if (iframeDocument) {
|
|
2373
|
+
targetElement = iframeDocument.querySelector(locator.value.slice(6));
|
|
2366
2374
|
}
|
|
2367
2375
|
}
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
});
|
|
2395
|
-
}
|
|
2396
|
-
}
|
|
2397
|
-
}
|
|
2398
|
-
else {
|
|
2399
|
-
targetElement = currentElement.querySelector(trimmedSelector);
|
|
2400
|
-
if (!targetElement) {
|
|
2401
|
-
targetElement = getElementFromShadowRoot(currentElement, trimmedSelector);
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
2404
|
-
if (!targetElement &&
|
|
2405
|
-
isSvg(currentElement) &&
|
|
2406
|
-
!locator.type.match("dynamic")) {
|
|
2407
|
-
targetElement = currentElement.querySelector(trimmedSelector);
|
|
2376
|
+
}
|
|
2377
|
+
else {
|
|
2378
|
+
const selectors = locator.value.split(">>>"); // Custom delimiter for shadow DOM
|
|
2379
|
+
for (const selector of selectors) {
|
|
2380
|
+
if (docmt) {
|
|
2381
|
+
const trimmedSelector = selector.trim();
|
|
2382
|
+
if (locator.name.includes("id") ||
|
|
2383
|
+
trimmedSelector.startsWith("#")) {
|
|
2384
|
+
targetElement = docmt.querySelector("#" + trimmedSelector);
|
|
2385
|
+
}
|
|
2386
|
+
else if (locator.name.includes("className") ||
|
|
2387
|
+
trimmedSelector.startsWith(".")) {
|
|
2388
|
+
targetElement = docmt.querySelector("." + trimmedSelector);
|
|
2389
|
+
}
|
|
2390
|
+
else if ((locator.name.includes("xpath") ||
|
|
2391
|
+
trimmedSelector.startsWith("//")) &&
|
|
2392
|
+
!locator.type.match("dynamic")) {
|
|
2393
|
+
const normalizedXPath = normalizeXPath(trimmedSelector);
|
|
2394
|
+
targetElement = getElementFromXPath(docmt, normalizedXPath);
|
|
2395
|
+
if (targetElement) {
|
|
2396
|
+
createLocator(locator, {
|
|
2397
|
+
value: trimmedSelector,
|
|
2398
|
+
isRecorded: String(locator.isRecorded).includes("N")
|
|
2399
|
+
? "N"
|
|
2400
|
+
: "Y",
|
|
2401
|
+
});
|
|
2408
2402
|
}
|
|
2409
|
-
currentElement = targetElement;
|
|
2410
2403
|
}
|
|
2411
2404
|
else {
|
|
2412
|
-
|
|
2413
|
-
|
|
2405
|
+
targetElement = docmt.querySelector(trimmedSelector);
|
|
2406
|
+
if (!targetElement) {
|
|
2407
|
+
targetElement = getElementFromShadowRoot(docmt.body, trimmedSelector);
|
|
2408
|
+
}
|
|
2414
2409
|
}
|
|
2415
2410
|
}
|
|
2411
|
+
else {
|
|
2412
|
+
console.error("Element not found at:", selector);
|
|
2413
|
+
break;
|
|
2414
|
+
}
|
|
2416
2415
|
}
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2416
|
+
}
|
|
2417
|
+
const locatorExists = (name, value) => {
|
|
2418
|
+
const key = `${name}:${value}`;
|
|
2419
|
+
return finalLocatorsSet.has(key);
|
|
2420
|
+
};
|
|
2421
|
+
if (targetElement) {
|
|
2422
|
+
const idValue = getId(targetElement);
|
|
2423
|
+
if (idValue && !locatorExists("id", idValue)) {
|
|
2424
|
+
record.locators.forEach((loc) => {
|
|
2425
|
+
createLocator(loc, {
|
|
2426
|
+
name: "id",
|
|
2427
|
+
value: idValue,
|
|
2428
|
+
isRecorded: loc.value === idValue && loc.name === "id"
|
|
2429
|
+
? loc.isRecorded
|
|
2430
|
+
: "Y",
|
|
2431
|
+
isSelfHealed: loc.value === idValue && loc.name === "id"
|
|
2432
|
+
? loc.isSelfHealed
|
|
2433
|
+
: "Y",
|
|
2435
2434
|
});
|
|
2436
|
-
}
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2435
|
+
});
|
|
2436
|
+
}
|
|
2437
|
+
const textValue = getVisibleText(targetElement);
|
|
2438
|
+
if (textValue) {
|
|
2439
|
+
record.locators.forEach((loc) => {
|
|
2440
|
+
createLocator(loc, {
|
|
2441
|
+
name: "linkText",
|
|
2442
|
+
type: "static",
|
|
2443
|
+
value: textValue,
|
|
2444
|
+
isRecorded: loc.value === textValue ? loc.isRecorded : "Y",
|
|
2445
|
+
isSelfHealed: loc.value === textValue ? loc.isSelfHealed : "Y",
|
|
2447
2446
|
});
|
|
2448
|
-
}
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
const nameLocator = getName(targetElement);
|
|
2450
|
+
if (nameLocator && !locatorExists("name", nameLocator)) {
|
|
2451
|
+
record.locators.forEach((loc) => {
|
|
2452
|
+
createLocator(loc, {
|
|
2453
|
+
name: "name",
|
|
2454
|
+
type: "static",
|
|
2455
|
+
value: nameLocator,
|
|
2456
|
+
isRecorded: loc.value === nameLocator && loc.name === "name"
|
|
2457
|
+
? loc.isRecorded
|
|
2458
|
+
: "Y",
|
|
2459
|
+
isSelfHealed: loc.value === nameLocator && loc.name === "name"
|
|
2460
|
+
? loc.isSelfHealed
|
|
2461
|
+
: "Y",
|
|
2463
2462
|
});
|
|
2464
|
-
}
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2463
|
+
});
|
|
2464
|
+
}
|
|
2465
|
+
const classValue = getClassName(targetElement);
|
|
2466
|
+
if (classValue &&
|
|
2467
|
+
classValue.trim() !== "" &&
|
|
2468
|
+
!locatorExists("className", classValue)) {
|
|
2469
|
+
record.locators.forEach((loc) => {
|
|
2470
|
+
createLocator(loc, {
|
|
2471
|
+
name: "className",
|
|
2472
|
+
value: classValue,
|
|
2473
|
+
isRecorded: loc.value === classValue && loc.name === "className"
|
|
2474
|
+
? loc.isRecorded
|
|
2475
|
+
: "Y",
|
|
2476
|
+
isSelfHealed: loc.value === classValue && loc.name === "className"
|
|
2477
|
+
? loc.isSelfHealed
|
|
2478
|
+
: "Y",
|
|
2480
2479
|
});
|
|
2481
|
-
}
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
const xpathResults = parseDOM(targetElement, docmt, false, true);
|
|
2483
|
+
xpathResults.forEach((result) => {
|
|
2484
|
+
const fnValue = result.value;
|
|
2485
|
+
if (fnValue && !locatorExists(result.key.replace('xpath by', '').trim(), fnValue)) {
|
|
2485
2486
|
record.locators.forEach((loc) => {
|
|
2486
2487
|
createLocator(loc, {
|
|
2487
2488
|
name: 'xpath',
|
|
@@ -2490,71 +2491,71 @@ const getElementsFromHTML = (record, docmt) => {
|
|
|
2490
2491
|
isSelfHealed: loc.value === fnValue ? loc.isSelfHealed : 'Y',
|
|
2491
2492
|
});
|
|
2492
2493
|
});
|
|
2493
|
-
}
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2494
|
+
}
|
|
2495
|
+
});
|
|
2496
|
+
for (const locator of record.locators) {
|
|
2497
|
+
try {
|
|
2498
|
+
for (const loc of record.locators) {
|
|
2499
|
+
if (!loc.value)
|
|
2500
|
+
continue;
|
|
2501
|
+
for (const relation of relations) {
|
|
2502
|
+
if (loc.value.includes(relation)) {
|
|
2503
|
+
const relativeXpath = checkReferenceElementIsValid(loc.value, relation, docmt);
|
|
2504
|
+
if (relativeXpath) {
|
|
2505
|
+
createLocator(loc, {
|
|
2506
|
+
name: "xpath",
|
|
2507
|
+
value: relativeXpath,
|
|
2508
|
+
isRecorded: locator.isRecorded !== "" &&
|
|
2509
|
+
locator.isRecorded !== null
|
|
2510
|
+
? locator.isRecorded
|
|
2511
|
+
: "Y",
|
|
2512
|
+
});
|
|
2513
|
+
break;
|
|
2513
2514
|
}
|
|
2514
2515
|
}
|
|
2515
2516
|
}
|
|
2516
2517
|
}
|
|
2517
|
-
catch (error) {
|
|
2518
|
-
console.error("Error processing locator:", locator, error);
|
|
2519
|
-
}
|
|
2520
2518
|
}
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
}));
|
|
2525
|
-
const finalUniqueAutoHealedLocators = finalAutoHealedLocators.reduce((unique, locator) => {
|
|
2526
|
-
if (locator.value &&
|
|
2527
|
-
!unique.some((l) => l.value === locator.value)) {
|
|
2528
|
-
unique.push(locator);
|
|
2529
|
-
}
|
|
2530
|
-
return unique;
|
|
2531
|
-
}, []);
|
|
2532
|
-
const jsonResult = [
|
|
2533
|
-
{
|
|
2534
|
-
name: `${record.name}`,
|
|
2535
|
-
desc: `${record.desc}`,
|
|
2536
|
-
type: `${record.type}`,
|
|
2537
|
-
locators: finalUniqueAutoHealedLocators.filter((locator) => locator?.value != null && locator.value !== ""),
|
|
2538
|
-
isShared: `${record.isShared}`,
|
|
2539
|
-
projectId: `${record.projectId}`,
|
|
2540
|
-
projectType: `${record.projectType}`,
|
|
2541
|
-
isRecorded: `${record.isRecorded}`,
|
|
2542
|
-
folder: `${record.folder}`,
|
|
2543
|
-
parentId: `${record.parentId}`,
|
|
2544
|
-
parentName: `${record.parentName}`,
|
|
2545
|
-
platform: `${record.platform}`,
|
|
2546
|
-
licenseId: `${record.licenseId}`,
|
|
2547
|
-
licenseType: `${record.licenseType}`,
|
|
2548
|
-
userId: `${record.userId}`,
|
|
2549
|
-
},
|
|
2550
|
-
];
|
|
2551
|
-
return jsonResult;
|
|
2519
|
+
catch (error) {
|
|
2520
|
+
console.error("Error processing locator:", locator, error);
|
|
2521
|
+
}
|
|
2552
2522
|
}
|
|
2523
|
+
const finalAutoHealedLocators = finalLocators.map((obj) => ({
|
|
2524
|
+
...obj,
|
|
2525
|
+
value: cleanLocatorValue(obj.value, obj.name, obj.isRecorded),
|
|
2526
|
+
}));
|
|
2527
|
+
const finalUniqueAutoHealedLocators = finalAutoHealedLocators.reduce((unique, locator) => {
|
|
2528
|
+
if (locator.value &&
|
|
2529
|
+
!unique.some((l) => l.value === locator.value)) {
|
|
2530
|
+
unique.push(locator);
|
|
2531
|
+
}
|
|
2532
|
+
return unique;
|
|
2533
|
+
}, []);
|
|
2534
|
+
const jsonResult = [
|
|
2535
|
+
{
|
|
2536
|
+
name: `${record.name}`,
|
|
2537
|
+
desc: `${record.desc}`,
|
|
2538
|
+
type: `${record.type}`,
|
|
2539
|
+
locators: finalUniqueAutoHealedLocators.filter((locator) => locator?.value != null && locator.value !== ""),
|
|
2540
|
+
isShared: `${record.isShared}`,
|
|
2541
|
+
projectId: `${record.projectId}`,
|
|
2542
|
+
projectType: `${record.projectType}`,
|
|
2543
|
+
isRecorded: `${record.isRecorded}`,
|
|
2544
|
+
folder: `${record.folder}`,
|
|
2545
|
+
parentId: `${record.parentId}`,
|
|
2546
|
+
parentName: `${record.parentName}`,
|
|
2547
|
+
platform: `${record.platform}`,
|
|
2548
|
+
licenseId: `${record.licenseId}`,
|
|
2549
|
+
licenseType: `${record.licenseType}`,
|
|
2550
|
+
userId: `${record.userId}`,
|
|
2551
|
+
},
|
|
2552
|
+
];
|
|
2553
|
+
return jsonResult;
|
|
2553
2554
|
}
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2555
|
+
}
|
|
2556
|
+
catch (error) {
|
|
2557
|
+
console.error("Error processing locator:", locator, error);
|
|
2558
|
+
continue;
|
|
2558
2559
|
}
|
|
2559
2560
|
}
|
|
2560
2561
|
catch (error) {
|