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