ff-dom 1.0.18-beta.1 → 1.0.18-beta.3

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.
@@ -3,8 +3,8 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  const reWhiteSpace$1 = /^[\S]+( [\S]+)*$/gi;
6
+ let cspEnabled = false;
6
7
  const xpathCache$1 = {};
7
- let multiElementReferenceMode = false;
8
8
  let relativeXPathCache = new Map();
9
9
  let modifiedElementAttributes$1 = [];
10
10
  let mutationObserver;
@@ -63,7 +63,7 @@ const getTextContent = (targetElement) => {
63
63
  const getFilteredText = (element) => {
64
64
  return element?.childNodes[0]?.nodeValue || "";
65
65
  };
66
- const getCountOfXPath = (xpath, element, docmt) => {
66
+ const getCountOfXPath = (xpath, element, docmt, multiElementReferenceMode = false) => {
67
67
  try {
68
68
  let count;
69
69
  // Check if result is cached
@@ -77,7 +77,23 @@ const getCountOfXPath = (xpath, element, docmt) => {
77
77
  count = owner.evaluate(`count(${xpath})`, docmt, null, XPathResult.NUMBER_TYPE, null).numberValue;
78
78
  xpathCache$1[xpath] = count;
79
79
  }
80
- if (multiElementReferenceMode && Array.isArray(element)) ;
80
+ if (multiElementReferenceMode && Array.isArray(element)) {
81
+ if (count > 1) {
82
+ const elementsFromXpath = getElementFromXpath(xpath, docmt, true);
83
+ let nodex, matchedCount = 0;
84
+ if (elementsFromXpath instanceof XPathResult) {
85
+ while ((nodex = elementsFromXpath?.iterateNext())) {
86
+ if (element.includes(nodex)) {
87
+ matchedCount += 1;
88
+ if (matchedCount === 2)
89
+ break;
90
+ }
91
+ }
92
+ }
93
+ if (matchedCount !== 2)
94
+ return 0;
95
+ }
96
+ }
81
97
  else {
82
98
  // Short-circuit if we only need to match one element
83
99
  if (count === 1) {
@@ -216,12 +232,6 @@ const getRelationship = (a, b) => {
216
232
  ? "self"
217
233
  : "";
218
234
  };
219
- const findRoot = (node) => {
220
- while (node && node.parentNode) {
221
- node = node.parentNode;
222
- }
223
- return node;
224
- };
225
235
  const isSvg = (element) => {
226
236
  return element instanceof SVGElement;
227
237
  };
@@ -463,9 +473,9 @@ const getRelativeXPath = (domNode, docmt, isIndex, isTarget = false, attributesA
463
473
  while (currentNode) {
464
474
  let xpathe = "";
465
475
  let hasUniqueAttr = false;
466
- let attributes = domNode === currentNode ? attributesArray : currentNode.attributes;
476
+ let attributes = domNode === currentNode ? attributesArray ?? currentNode.attributes : currentNode.attributes;
467
477
  // Loop through attributes to check for unique identifiers
468
- for (const attrName of attributes) {
478
+ for (const attrName of Array.from(attributes)) {
469
479
  if (checkBlockedAttributes(attrName, currentNode, isTarget)) {
470
480
  let attrValue = attrName.nodeValue;
471
481
  // Clean up attribute value
@@ -782,7 +792,7 @@ const getReferenceElementsXpath = (domNode, docmt, isTarget) => {
782
792
  }
783
793
  }
784
794
  if (domNode.attributes) {
785
- for (const attrName of domNode.attributes) {
795
+ for (const attrName of Array.from(domNode.attributes)) {
786
796
  if (checkBlockedAttributes(attrName, domNode, isTarget)) {
787
797
  let attrValue = attrName.nodeValue;
788
798
  if (attrValue) {
@@ -859,12 +869,12 @@ const getReferenceElementsXpath = (domNode, docmt, isTarget) => {
859
869
  }
860
870
  return xpaths1;
861
871
  };
862
- function parseXml(xmlStr) {
872
+ const parseXml = (xmlStr) => {
863
873
  if (window.DOMParser) {
864
874
  return new window.DOMParser().parseFromString(xmlStr, "text/xml");
865
875
  }
866
876
  return null;
867
- }
877
+ };
868
878
  const normalizeXPath = (xpath) => {
869
879
  // Replace text() = "value" or text()='value'
870
880
  xpath = xpath.replace(/text\(\)\s*=\s*(['"])(.*?)\1/g, "normalize-space(.)=$1$2$1");
@@ -912,6 +922,7 @@ const xpathUtils = {
912
922
  startObserver,
913
923
  stopObserver,
914
924
  modifiedElementAttributes: modifiedElementAttributes$1,
925
+ cspEnabled
915
926
  };
916
927
 
917
928
  let xpathData$1 = [];
@@ -994,7 +1005,7 @@ const getUniqueParentXpath = (domNode, docmt, node, isTarget, nodeXpath, isIndex
994
1005
  let currentNode = domNode;
995
1006
  while (currentNode && currentNode.nodeType === 1) {
996
1007
  const hasUniqueAttr = false;
997
- for (const attrName of currentNode.attributes) {
1008
+ for (const attrName of Array.from(currentNode.attributes)) {
998
1009
  if (checkBlockedAttributes(attrName, currentNode, isTarget)) {
999
1010
  let attrValue = attrName.nodeValue;
1000
1011
  attrValue = attrValue?.replace("removePointers", "") ?? "";
@@ -1100,7 +1111,7 @@ const getParentRelativeXpath = (domNode, docmt, node, isTarget) => {
1100
1111
  }
1101
1112
  // BASE CASE #2: Check for unique attributes
1102
1113
  let uniqueAttrFound = false;
1103
- for (const attr of currentNode.attributes) {
1114
+ for (const attr of Array.from(currentNode.attributes)) {
1104
1115
  if (checkBlockedAttributes(attr, currentNode, isTarget)) {
1105
1116
  let attrValue = attr.nodeValue;
1106
1117
  attrValue = attrValue?.replace("removePointers", "") ?? "";
@@ -1176,7 +1187,7 @@ const getChildRelativeXpath = (domNode, docmt, node) => {
1176
1187
  do {
1177
1188
  let uniqueAttrFound = false;
1178
1189
  for (currentNode = st.pop(); currentNode !== null;) {
1179
- for (const attr of currentNode.attributes) {
1190
+ for (const attr of Array.from(currentNode.attributes)) {
1180
1191
  if (checkBlockedAttributes(attr, currentNode, true)) {
1181
1192
  let attrValue = attr.nodeValue;
1182
1193
  attrValue = attrValue?.replace("removePointers", "") ?? "";
@@ -1258,7 +1269,7 @@ const getSiblingRelativeXPath = (domNode, docmt, isTarget, nodeXpath) => {
1258
1269
  const processSibling = (sibling, domNode, docmt, nodeXpath, axis, isTarget) => {
1259
1270
  try {
1260
1271
  if (sibling.hasAttributes()) {
1261
- for (const attr of sibling.attributes) {
1272
+ for (const attr of Array.from(sibling.attributes)) {
1262
1273
  let xpathe = intermediateXpathStep(sibling, {
1263
1274
  name: attr.name,
1264
1275
  value: attr.value,
@@ -1615,13 +1626,13 @@ const parseDOM = (element, doc, isIndex, isTarget) => {
1615
1626
  const docmt = targetElemt?.ownerDocument || doc;
1616
1627
  const tag = targetElemt.tagName;
1617
1628
  const { attributes } = targetElemt;
1618
- addAllXPathAttributes([...attributes], targetElemt, docmt, isIndex, isTarget);
1629
+ addAllXPathAttributes(Array.from(attributes), targetElemt, docmt, isIndex, isTarget);
1619
1630
  {
1620
1631
  if (xpathData$1.length) {
1621
1632
  const len = xpathData$1.length;
1622
1633
  for (let i = 0; i < len; i++) {
1623
1634
  let xpth = xpathData$1[i].value;
1624
- xpth = xpth.replace(tag, "*");
1635
+ xpth = "//*" + xpth.substring(xpth.indexOf("//") + 2 + tag.length);
1625
1636
  const count = getCountOfXPath(xpth, element, docmt);
1626
1637
  if (count === 1) {
1627
1638
  xpathData$1.push({
@@ -1634,7 +1645,7 @@ const parseDOM = (element, doc, isIndex, isTarget) => {
1634
1645
  }
1635
1646
  console.log(xpathData$1);
1636
1647
  if (!xpathData$1.length) {
1637
- addRelativeXpaths(targetElemt, docmt, isIndex, isTarget, [...targetElemt.attributes]);
1648
+ addRelativeXpaths(targetElemt, docmt, isIndex, isTarget, Array.from(targetElemt.attributes));
1638
1649
  }
1639
1650
  return xpathData$1;
1640
1651
  };
@@ -1656,13 +1667,12 @@ const xpath = {
1656
1667
  let xpathDataWithIndex = [];
1657
1668
  let xpathData = [];
1658
1669
  const reWhiteSpace = /^[\S]+( [\S]+)*$/gi;
1659
- const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex) => {
1670
+ const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex, multiElementReferenceMode = false) => {
1660
1671
  // debugger;
1661
1672
  const par1 = element1.parentElement;
1662
1673
  const par2 = element2.parentElement;
1663
1674
  let rel_xpath = [];
1664
1675
  let tempElement;
1665
- findRoot(element1);
1666
1676
  let finalXpaths = [];
1667
1677
  if (isIndex) {
1668
1678
  if (xpathDataWithIndex.length) {
@@ -1682,14 +1692,14 @@ const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex)
1682
1692
  // both are same
1683
1693
  if (element1.isSameNode(element2)) {
1684
1694
  // rel_xpath = xpath1 + "/self::" + element1.tagName;
1685
- rel_xpath = getXpathRelationExpression(element1, element2, "self", xpaths1, xpaths2, isIndex);
1695
+ rel_xpath = getXpathRelationExpression(element1, element2, "self", xpaths1, xpaths2, isIndex, multiElementReferenceMode);
1686
1696
  if (rel_xpath)
1687
1697
  finalXpaths = finalXpaths.concat(rel_xpath);
1688
1698
  }
1689
1699
  // parent
1690
1700
  tempElement = element1.parentElement;
1691
1701
  if (tempElement === element2) {
1692
- rel_xpath = getXpathRelationExpression(element1, element2, "parent", xpaths1, xpaths2, isIndex);
1702
+ rel_xpath = getXpathRelationExpression(element1, element2, "parent", xpaths1, xpaths2, isIndex, multiElementReferenceMode);
1693
1703
  if (rel_xpath)
1694
1704
  finalXpaths = finalXpaths.concat(rel_xpath);
1695
1705
  }
@@ -1697,7 +1707,7 @@ const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex)
1697
1707
  tempElement = element1.parentElement;
1698
1708
  while (tempElement !== null) {
1699
1709
  if (tempElement === element2) {
1700
- rel_xpath = getXpathRelationExpression(element1, element2, "ancestor", xpaths1, xpaths2, isIndex);
1710
+ rel_xpath = getXpathRelationExpression(element1, element2, "ancestor", xpaths1, xpaths2, isIndex, multiElementReferenceMode);
1701
1711
  if (rel_xpath) {
1702
1712
  finalXpaths = finalXpaths.concat(rel_xpath);
1703
1713
  break;
@@ -1709,7 +1719,7 @@ const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex)
1709
1719
  tempElement = element1;
1710
1720
  do {
1711
1721
  if (tempElement === element2) {
1712
- rel_xpath = getXpathRelationExpression(element1, element2, "ancestor-or-self", xpaths1, xpaths2, isIndex);
1722
+ rel_xpath = getXpathRelationExpression(element1, element2, "ancestor-or-self", xpaths1, xpaths2, isIndex, multiElementReferenceMode);
1713
1723
  if (rel_xpath) {
1714
1724
  finalXpaths = finalXpaths.concat(rel_xpath);
1715
1725
  break;
@@ -1721,7 +1731,7 @@ const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex)
1721
1731
  if (par1?.isSameNode(par2)) {
1722
1732
  for (let m = element1.nextElementSibling; m != null; m = m.nextElementSibling) {
1723
1733
  if (m != null && m.isSameNode(element2)) {
1724
- rel_xpath = getXpathRelationExpression(element1, element2, "following-sibling", xpaths1, xpaths2, isIndex);
1734
+ rel_xpath = getXpathRelationExpression(element1, element2, "following-sibling", xpaths1, xpaths2, isIndex, multiElementReferenceMode);
1725
1735
  if (rel_xpath) {
1726
1736
  finalXpaths = finalXpaths.concat(rel_xpath);
1727
1737
  break;
@@ -1730,7 +1740,7 @@ const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex)
1730
1740
  }
1731
1741
  for (let n = element1.previousElementSibling; n != null; n = n.previousElementSibling) {
1732
1742
  if (n != null && n.isSameNode(element2)) {
1733
- rel_xpath = getXpathRelationExpression(element1, element2, "preceding-sibling", xpaths1, xpaths2, isIndex);
1743
+ rel_xpath = getXpathRelationExpression(element1, element2, "preceding-sibling", xpaths1, xpaths2, isIndex, multiElementReferenceMode);
1734
1744
  if (rel_xpath) {
1735
1745
  finalXpaths = finalXpaths.concat(rel_xpath);
1736
1746
  break;
@@ -1742,7 +1752,7 @@ const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex)
1742
1752
  if (element1?.children?.length) {
1743
1753
  for (let m = element1.children[0]; m !== null; m = m?.nextElementSibling) {
1744
1754
  if (m === element2) {
1745
- rel_xpath = getXpathRelationExpression(element1, element2, "child", xpaths1, xpaths2, isIndex);
1755
+ rel_xpath = getXpathRelationExpression(element1, element2, "child", xpaths1, xpaths2, isIndex, multiElementReferenceMode);
1746
1756
  if (rel_xpath) {
1747
1757
  finalXpaths = finalXpaths.concat(rel_xpath);
1748
1758
  break;
@@ -1753,18 +1763,18 @@ const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex)
1753
1763
  // following
1754
1764
  const relation = element1.compareDocumentPosition(element2);
1755
1765
  if (relation === 2) {
1756
- rel_xpath = getXpathRelationExpression(element1, element2, "preceding", xpaths1, xpaths2, isIndex);
1766
+ rel_xpath = getXpathRelationExpression(element1, element2, "preceding", xpaths1, xpaths2, isIndex, multiElementReferenceMode);
1757
1767
  }
1758
1768
  if (relation === 4) {
1759
- rel_xpath = getXpathRelationExpression(element1, element2, "following", xpaths1, xpaths2, isIndex);
1769
+ rel_xpath = getXpathRelationExpression(element1, element2, "following", xpaths1, xpaths2, isIndex, multiElementReferenceMode);
1760
1770
  }
1761
1771
  if (rel_xpath) {
1762
1772
  finalXpaths = finalXpaths.concat(rel_xpath);
1763
1773
  }
1764
- const descendantXpath = getDescendantXpath([element1, element2], docmt, xpaths1, xpaths2, "descendant", isIndex);
1774
+ const descendantXpath = getDescendantXpath([element1, element2], docmt, xpaths1, xpaths2, "descendant", isIndex, multiElementReferenceMode);
1765
1775
  if (descendantXpath)
1766
1776
  finalXpaths = finalXpaths.concat(descendantXpath);
1767
- const descendantSelfXpath = getDescendantXpath([element1, element2], docmt, xpaths1, xpaths2, "descedant-or-self", isIndex);
1777
+ const descendantSelfXpath = getDescendantXpath([element1, element2], docmt, xpaths1, xpaths2, "descedant-or-self", isIndex, multiElementReferenceMode);
1768
1778
  if (descendantSelfXpath) {
1769
1779
  finalXpaths = finalXpaths.concat(descendantSelfXpath);
1770
1780
  }
@@ -1781,7 +1791,7 @@ const findRelativeXpath = (element1, element2, docmt, xpaths1, xpaths2, isIndex)
1781
1791
  return [finalXpaths[0]];
1782
1792
  }
1783
1793
  };
1784
- const descendantExpression = (refExpectElement, xpath2, relation, docmt, isIndex, expCommonParentXpathElements, step4, refCommonParentXpathElementLength) => {
1794
+ const descendantExpression = (refExpectElement, xpath2, relation, docmt, isIndex, expCommonParentXpathElements, step4, refCommonParentXpathElementLength = 0, multiElementReferenceMode = false) => {
1785
1795
  let finalExpectedElementXpath = "";
1786
1796
  if (xpath2.split(/\/(?=(?:[^']*\'[^\']*\')*[^\']*$)/g)?.length >=
1787
1797
  expCommonParentXpathElements.length) {
@@ -1795,7 +1805,7 @@ const descendantExpression = (refExpectElement, xpath2, relation, docmt, isIndex
1795
1805
  const traverseXpath = getTraverseXpathExpression(`${step4 +
1796
1806
  (refCommonParentXpathElementLength
1797
1807
  ? "]".repeat(refCommonParentXpathElementLength)
1798
- : "")}`, xpaths2Els, refExpectElement[refExpectElement.length - 1], refExpectElement, docmt, relation, isIndex);
1808
+ : "")}`, xpaths2Els, refExpectElement[refExpectElement.length - 1], refExpectElement, docmt, relation, isIndex, multiElementReferenceMode);
1799
1809
  if (traverseXpath) {
1800
1810
  return traverseXpath;
1801
1811
  }
@@ -1832,7 +1842,7 @@ const descendantExpression = (refExpectElement, xpath2, relation, docmt, isIndex
1832
1842
  }
1833
1843
  }
1834
1844
  };
1835
- const getDescendantXpath = (refExpectElement, docmt, xpaths1, xpaths2, relation, isIndex) => {
1845
+ const getDescendantXpath = (refExpectElement, docmt, xpaths1, xpaths2, relation, isIndex = false, multiElementReferenceMode = false) => {
1836
1846
  const refElement = refExpectElement[refExpectElement.length - 2];
1837
1847
  const expElement = refExpectElement[refExpectElement.length - 1];
1838
1848
  const expElementDocmnt = getShadowRoot(expElement) ?? expElement.ownerDocument;
@@ -1896,13 +1906,13 @@ const getDescendantXpath = (refExpectElement, docmt, xpaths1, xpaths2, relation,
1896
1906
  xpath2 = xpathData[i].value; // No need to modify the value
1897
1907
  }
1898
1908
  if (xpath2) {
1899
- return descendantExpression(refExpectElement, xpath2, relation, expElementDocmnt || docmt, isIndex, expCommonParentXpathElements, step4, refCommonParentXpathElementLength);
1909
+ return descendantExpression(refExpectElement, xpath2, relation, expElementDocmnt || docmt, isIndex, expCommonParentXpathElements, step4, refCommonParentXpathElementLength, multiElementReferenceMode);
1900
1910
  }
1901
1911
  }
1902
1912
  }
1903
1913
  if (refExpectElement[refExpectElement.length - 2].attributes) {
1904
- for (const attrName of refExpectElement[refExpectElement.length - 2]
1905
- .attributes) {
1914
+ for (const attrName of Array.from(refExpectElement[refExpectElement.length - 2]
1915
+ .attributes)) {
1906
1916
  if (checkBlockedAttributes(attrName, refExpectElement[refExpectElement.length - 2], false)) {
1907
1917
  let attrValue = attrName.nodeValue;
1908
1918
  if (attrValue) {
@@ -1923,13 +1933,13 @@ const getDescendantXpath = (refExpectElement, docmt, xpaths1, xpaths2, relation,
1923
1933
  else {
1924
1934
  xpath2 = xpathData[i].value; // No need to modify the value
1925
1935
  }
1926
- return descendantExpression(refExpectElement, xpath2, relation, expElementDocmnt || docmt, isIndex, expCommonParentXpathElements, step4, refCommonParentXpathElementLength);
1936
+ return descendantExpression(refExpectElement, xpath2, relation, expElementDocmnt || docmt, isIndex, expCommonParentXpathElements, step4, refCommonParentXpathElementLength, multiElementReferenceMode);
1927
1937
  }
1928
1938
  }
1929
1939
  }
1930
1940
  }
1931
- for (const attrName of refExpectElement[refExpectElement.length - 2]
1932
- .attributes) {
1941
+ for (const attrName of Array.from(refExpectElement[refExpectElement.length - 2]
1942
+ .attributes)) {
1933
1943
  if (checkBlockedAttributes(attrName, refExpectElement[refExpectElement.length - 2], false)) {
1934
1944
  let attrValue = attrName.nodeValue;
1935
1945
  if (attrValue) {
@@ -1954,7 +1964,7 @@ const getDescendantXpath = (refExpectElement, docmt, xpaths1, xpaths2, relation,
1954
1964
  else {
1955
1965
  xpath2 = xpathData[i].value; // No need to modify the value
1956
1966
  }
1957
- return descendantExpression(refExpectElement, xpath2, relation, expElementDocmnt || docmt, isIndex, expCommonParentXpathElements, step4, refCommonParentXpathElementLength);
1967
+ return descendantExpression(refExpectElement, xpath2, relation, expElementDocmnt || docmt, isIndex, expCommonParentXpathElements, step4, refCommonParentXpathElementLength, multiElementReferenceMode);
1958
1968
  }
1959
1969
  }
1960
1970
  }
@@ -1967,12 +1977,12 @@ const getDescendantXpath = (refExpectElement, docmt, xpaths1, xpaths2, relation,
1967
1977
  const traverseXpath = getTraverseXpathExpression(`${step4 +
1968
1978
  (refCommonParentXpathElementLength
1969
1979
  ? "]".repeat(refCommonParentXpathElementLength)
1970
- : "")}`, expCommonParentXpathElements.reverse(), refExpectElement[refExpectElement.length - 1], refExpectElement, docmt, relation, isIndex);
1980
+ : "")}`, expCommonParentXpathElements, refExpectElement[refExpectElement.length - 1], refExpectElement, docmt, relation, isIndex, multiElementReferenceMode);
1971
1981
  if (traverseXpath) {
1972
1982
  return traverseXpath;
1973
1983
  }
1974
1984
  };
1975
- const getXpathRelationExpression = (element1, element2, relation, xpath1, xpath2, isIndex) => {
1985
+ const getXpathRelationExpression = (element1, element2, relation, xpath1, xpath2, isIndex, multiElementReferenceMode) => {
1976
1986
  let xpaths1;
1977
1987
  let xpaths2;
1978
1988
  console.log('getXpathRelationExpression', relation);
@@ -2039,7 +2049,7 @@ const getXpathRelationExpression = (element1, element2, relation, xpath1, xpath2
2039
2049
  if (xpath2Elements.length > 1) {
2040
2050
  const traverseXpath = getTraverseXpathExpression(`${xpaths1[i].value.indexOf("//") !== 0
2041
2051
  ? replaceActualAttributes(xpaths1[i].value, element1)
2042
- : replaceActualAttributes(xpaths1[i].value.substring(xpaths1[i].value.indexOf("//") + 2), element1)}`, xpath2Elements, element2, [element1, element2], element2.ownerDocument, relation, isIndex);
2052
+ : replaceActualAttributes(xpaths1[i].value.substring(xpaths1[i].value.indexOf("//") + 2), element1)}`, xpath2Elements, element2, [element1, element2], element2.ownerDocument, relation, isIndex, multiElementReferenceMode);
2043
2053
  console.log('getXpathRelationExpression traverseXpath', traverseXpath);
2044
2054
  if (traverseXpath) {
2045
2055
  finalXpaths.concat(traverseXpath);
@@ -2079,7 +2089,7 @@ const getReferenceElementXpath = (element) => {
2079
2089
  xpaths1 = [
2080
2090
  {
2081
2091
  key: "",
2082
- value: getRelativeXPath(element, element.ownerDocument, false, false, [...element.attributes]),
2092
+ value: getRelativeXPath(element, element.ownerDocument, false, false, Array.from(element.attributes)),
2083
2093
  },
2084
2094
  ];
2085
2095
  }
@@ -2087,7 +2097,7 @@ const getReferenceElementXpath = (element) => {
2087
2097
  xpaths1 = [
2088
2098
  {
2089
2099
  key: "",
2090
- value: getRelativeXPath(element, element.ownerDocument, true, false, [...element.attributes]),
2100
+ value: getRelativeXPath(element, element.ownerDocument, true, false, Array.from(element.attributes)),
2091
2101
  },
2092
2102
  ];
2093
2103
  xpaths1 = xpaths1?.map((x) => x.value.charAt(0) == "(" &&
@@ -2112,9 +2122,9 @@ const getReferenceElementXpath = (element) => {
2112
2122
  });
2113
2123
  return xpaths1;
2114
2124
  };
2115
- const getTraverseXpathExpression = (xpathe1, absoluteXpathElements, element2, refExpectElement, docmt, relation, isIndex) => {
2125
+ const getTraverseXpathExpression = (xpathe1, absoluteXpathElements, element2, refExpectElement, docmt, relation, isIndex, multiElementReferenceMode) => {
2116
2126
  let finalExpectedElementXpath;
2117
- {
2127
+ if (!multiElementReferenceMode) {
2118
2128
  for (let x = 1; x <= absoluteXpathElements.length; x++) {
2119
2129
  const xpath2 = absoluteXpathElements
2120
2130
  .slice(absoluteXpathElements.length - x, absoluteXpathElements.length)
@@ -2144,6 +2154,32 @@ const getTraverseXpathExpression = (xpathe1, absoluteXpathElements, element2, re
2144
2154
  }
2145
2155
  }
2146
2156
  }
2157
+ else {
2158
+ const xpath2 = absoluteXpathElements.join("/");
2159
+ finalExpectedElementXpath = `//${xpathe1}/${relation}::${replaceActualAttributes(xpath2)}`;
2160
+ const rel_count = getCountOfXPath(finalExpectedElementXpath, element2, docmt);
2161
+ if (rel_count === 1) {
2162
+ return [
2163
+ {
2164
+ key: `dynamic ${relation}`,
2165
+ value: replaceTempAttributes(finalExpectedElementXpath),
2166
+ },
2167
+ ];
2168
+ }
2169
+ if (rel_count > 1) {
2170
+ if (isIndex) {
2171
+ finalExpectedElementXpath = findXpathWithIndex(finalExpectedElementXpath, refExpectElement[refExpectElement.length - 1], docmt, rel_count);
2172
+ if (finalExpectedElementXpath) {
2173
+ return [
2174
+ {
2175
+ key: `dynamic ${relation}${isIndex ? " index" : ""}`,
2176
+ value: replaceTempAttributes(finalExpectedElementXpath),
2177
+ },
2178
+ ];
2179
+ }
2180
+ }
2181
+ }
2182
+ }
2147
2183
  };
2148
2184
  const referenceXpath = {
2149
2185
  findRelativeXpath,