ff-automationv2 2.2.29 → 2.2.31

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.
Files changed (113) hide show
  1. package/dist/ai/llmcalls/llmAction.js +49 -13
  2. package/dist/ai/llmcalls/parseLlmOputput.js +5 -5
  3. package/dist/ai/llmprompts/promptRegistry.js +4 -0
  4. package/dist/ai/llmprompts/systemPrompts/actionExtractorPrompt.js +39 -11
  5. package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtactors.js +6 -6
  6. package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtractor_Mob.js +32 -0
  7. package/dist/ai/llmprompts/systemPrompts/mobileKeywordExtractor.js +17 -8
  8. package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.d.ts +1 -0
  9. package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.js +22 -0
  10. package/dist/ai/llmprompts/systemPrompts/verifyActionExtractorPrompt.js +3 -1
  11. package/dist/ai/llmprompts/systemPrompts/visionPrompt.js +14 -6
  12. package/dist/ai/llmprompts/systemPrompts/visionPromptMobile.js +3 -0
  13. package/dist/ai/llmprompts/userPrompts/userPrompt.js +1 -0
  14. package/dist/automation/actions/executor.d.ts +4 -0
  15. package/dist/automation/actions/executor.js +20 -0
  16. package/dist/automation/actions/interaction/clear/clear.js +1 -1
  17. package/dist/automation/actions/interaction/clear/clearAndEnter.js +1 -1
  18. package/dist/automation/actions/interaction/click/click.js +10 -3
  19. package/dist/automation/actions/interaction/click/clickNtimes.js +1 -1
  20. package/dist/automation/actions/interaction/click/doubleClick.js +1 -1
  21. package/dist/automation/actions/interaction/click/rightClick.js +1 -1
  22. package/dist/automation/actions/interaction/elementlessActions/getOtp.d.ts +2 -0
  23. package/dist/automation/actions/interaction/elementlessActions/getOtp.js +101 -0
  24. package/dist/automation/actions/interaction/enterActions/enterInput.js +11 -6
  25. package/dist/automation/actions/interaction/enterActions/enterInputAndPress.js +2 -2
  26. package/dist/automation/actions/interaction/enterActions/enterusingJs.js +2 -2
  27. package/dist/automation/actions/interaction/enterActions/waitAndEnter.js +1 -1
  28. package/dist/automation/actions/interaction/upload/uploadfile.js +1 -1
  29. package/dist/automation/actions/interaction/verify/VerifyNavigateURL.js +38 -11
  30. package/dist/automation/actions/interface/FireFlinkResponseSchema.d.ts +12 -0
  31. package/dist/automation/actions/interface/FireFlinkResponseSchema.js +19 -3
  32. package/dist/automation/actions/interface/getOtpInterface.d.ts +15 -0
  33. package/dist/automation/actions/interface/getOtpInterface.js +2 -0
  34. package/dist/automation/browserSession/initiateBrowserSession.d.ts +1 -1
  35. package/dist/automation/browserSession/initiateBrowserSession.js +15 -7
  36. package/dist/automation/driverState.d.ts +2 -0
  37. package/dist/automation/driverState.js +4 -0
  38. package/dist/automation/mobileSession/initiateMobileSession.d.ts +4 -5
  39. package/dist/automation/mobileSession/initiateMobileSession.js +83 -19
  40. package/dist/core/constants/allAction.js +5 -1
  41. package/dist/core/constants/supportedActions.js +5 -2
  42. package/dist/core/interfaces/actionInterface.d.ts +4 -0
  43. package/dist/core/interfaces/browserConfigurationInterface.d.ts +0 -4
  44. package/dist/core/interfaces/browserConfigurationInterface.js +0 -1
  45. package/dist/core/interfaces/executionDetails.d.ts +6 -3
  46. package/dist/core/interfaces/fireflinkScriptPayloadInterface.d.ts +22 -16
  47. package/dist/core/interfaces/llmResponseInterface.d.ts +1 -0
  48. package/dist/core/interfaces/promptInterface.d.ts +1 -0
  49. package/dist/core/main/SessionManager.d.ts +9 -0
  50. package/dist/core/main/SessionManager.js +23 -0
  51. package/dist/core/main/actionHandlerFactory.js +261 -64
  52. package/dist/core/main/executionContext.d.ts +7 -1
  53. package/dist/core/main/executionContext.js +94 -3
  54. package/dist/core/main/runAutomationScript.d.ts +1 -0
  55. package/dist/core/main/runAutomationScript.js +912 -304
  56. package/dist/core/main/stepProcessor.js +7 -2
  57. package/dist/core/types/browserType.d.ts +3 -3
  58. package/dist/core/types/browserType.js +2 -2
  59. package/dist/core/types/messageType.d.ts +13 -0
  60. package/dist/core/types/messageType.js +15 -0
  61. package/dist/core/types/promptType.d.ts +2 -1
  62. package/dist/core/types/promptType.js +1 -0
  63. package/dist/domAnalysis/searchBest.js +15 -16
  64. package/dist/domAnalysis/simplifyAndFlatten.js +6 -4
  65. package/dist/fireflinkData/fireflinkLocators/getListOfLocators.d.ts +3 -0
  66. package/dist/fireflinkData/fireflinkLocators/getListOfLocators.js +23 -15
  67. package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.d.ts +3 -3
  68. package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.js +134 -118
  69. package/dist/fireflinkData/fireflinkLocators/types/locator.d.ts +11 -1
  70. package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.d.ts +1 -1
  71. package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.js +35 -9
  72. package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.d.ts +10 -10
  73. package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.js +56 -59
  74. package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.d.ts +1 -1
  75. package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.js +53 -29
  76. package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.d.ts +8 -8
  77. package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.js +113 -190
  78. package/dist/fireflinkData/fireflinkLocators/utils/xpath.d.ts +17 -26
  79. package/dist/fireflinkData/fireflinkLocators/utils/xpath.js +314 -786
  80. package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.d.ts +68 -70
  81. package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.js +498 -517
  82. package/dist/fireflinkData/fireflinkScript/appendScriptData.d.ts +1 -1
  83. package/dist/fireflinkData/fireflinkScript/appendScriptData.js +5 -8
  84. package/dist/fireflinkData/fireflinkScript/scriptGenrationData.d.ts +2 -2
  85. package/dist/fireflinkData/fireflinkScript/scriptGenrationData.js +17 -27
  86. package/dist/llmConfig/llmConfiguration.js +13 -6
  87. package/dist/service/api/fireflinkApi.service.d.ts +1 -1
  88. package/dist/service/api/fireflinkApi.service.js +1 -2
  89. package/dist/service/fireflink.service.d.ts +3 -3
  90. package/dist/service/fireflink.service.js +23 -21
  91. package/dist/service/kafka/fireflinkKafka.service.d.ts +1 -2
  92. package/dist/service/kafka/fireflinkKafka.service.js +6 -4
  93. package/dist/tests/test12.d.ts +0 -1
  94. package/dist/tests/test12.js +65 -78
  95. package/dist/tests/testkaf.d.ts +0 -1
  96. package/dist/tests/testkaf.js +51 -55
  97. package/dist/utils/InstancesDetails/getInstancesInfo.js +1 -1
  98. package/dist/utils/browserCap/capability.d.ts +5 -1
  99. package/dist/utils/browserCap/capability.js +91 -15
  100. package/dist/utils/helpers/domSanitizer.d.ts +1 -0
  101. package/dist/utils/helpers/domSanitizer.js +9 -0
  102. package/dist/utils/helpers/enterActionHelper.js +23 -4
  103. package/dist/utils/helpers/xpathcreation.js +2 -2
  104. package/dist/utils/javascript/jsFindElement.d.ts +1 -1
  105. package/dist/utils/javascript/jsFindElement.js +2 -2
  106. package/dist/utils/newTab/newTabTracker.js +18 -6
  107. package/dist/utils/workers/LocatorWorkerInterface.d.ts +22 -0
  108. package/dist/utils/workers/LocatorWorkerInterface.js +2 -0
  109. package/dist/utils/workers/LocatorWorkerPool.d.ts +13 -0
  110. package/dist/utils/workers/LocatorWorkerPool.js +89 -0
  111. package/dist/utils/workers/locatorWorker.d.ts +1 -0
  112. package/dist/utils/workers/locatorWorker.js +44 -0
  113. package/package.json +3 -1
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getElementsFromHTML = void 0;
3
+ exports.getAiElementsFromHTML = void 0;
4
4
  const xpath_js_1 = require("../utils/xpath.js");
5
5
  const cssSelector_js_1 = require("../utils/cssSelector.js");
6
6
  const jsdom_1 = require("jsdom");
7
7
  const xpathHelpers_js_1 = require("../utils/xpathHelpers.js");
8
+ const domSanitizer_js_1 = require("../../../utils/helpers/domSanitizer.js");
8
9
  const logData_js_1 = require("../../../utils/logger/logData.js");
9
- const getElementFromCssSelector = (docmt, selector) => {
10
+ const getAiElementFromCssSelector = (docmt, selector) => {
10
11
  try {
11
12
  const found = docmt.querySelector(selector);
12
13
  if (found)
@@ -16,12 +17,12 @@ const getElementFromCssSelector = (docmt, selector) => {
16
17
  console.error("Invalid CSS selector:", selector, error);
17
18
  return null;
18
19
  }
19
- return getElementFromShadowRoot(docmt.body, selector);
20
+ return getAiElementFromShadowRoot(docmt.body, selector);
20
21
  };
21
- const isCssSelectorLocator = (locator) => {
22
+ const isAiCssSelectorLocator = (locator) => {
22
23
  return locator.name?.toLowerCase().includes("cssselector") ?? false;
23
24
  };
24
- const getElementFromShadowRoot = (el, selector) => {
25
+ const getAiElementFromShadowRoot = (el, selector) => {
25
26
  const shadowRoot = el.shadowRoot;
26
27
  if (shadowRoot && !selector.includes("dynamic")) {
27
28
  return shadowRoot.querySelector(selector);
@@ -32,7 +33,7 @@ const getElementFromShadowRoot = (el, selector) => {
32
33
  if (elements[i].shadowRoot) {
33
34
  const { shadowRoot } = elements[i];
34
35
  if (shadowRoot) {
35
- const nestedElement = getElementFromShadowRoot(shadowRoot, selector);
36
+ const nestedElement = getAiElementFromShadowRoot(shadowRoot, selector);
36
37
  if (nestedElement) {
37
38
  return nestedElement;
38
39
  }
@@ -48,32 +49,32 @@ const getElementFromShadowRoot = (el, selector) => {
48
49
  }
49
50
  return null;
50
51
  };
51
- const getId = (element) => {
52
+ const getaiId = (element) => {
52
53
  return element?.id || null;
53
54
  };
54
- const getClassName = (element) => {
55
- if (element instanceof element.ownerDocument.defaultView.SVGElement) {
55
+ const getAiClassName = (element) => {
56
+ const svgClass = element.ownerDocument?.defaultView?.SVGElement;
57
+ if (svgClass && element instanceof svgClass) {
56
58
  const cls = element.className;
57
59
  if (typeof cls === "string") {
58
60
  return cls;
59
61
  }
60
62
  return cls?.baseVal || null;
61
63
  }
62
- return element.className || null;
64
+ return element.getAttribute("class") || element.className || null;
63
65
  };
64
- const getVisibleText = (element) => {
66
+ const getAiVisibleText = (element) => {
65
67
  return element.textContent?.trim() || null;
66
68
  };
67
- const getName = (element) => {
68
- const elementEl = element;
69
- if (elementEl.hasAttribute("name")) {
70
- const attrValue = elementEl.getAttribute("name");
69
+ const getAiName = (element) => {
70
+ if (element.hasAttribute("name")) {
71
+ const attrValue = element.getAttribute("name");
71
72
  const name = `${attrValue}`;
72
73
  return name || null;
73
74
  }
74
75
  return null;
75
76
  };
76
- const relations = [
77
+ const aiRelations = [
77
78
  "/preceding-sibling",
78
79
  "/following-sibling",
79
80
  "/parent",
@@ -85,26 +86,23 @@ const relations = [
85
86
  "/preceding",
86
87
  "/following"
87
88
  ];
88
- function getElementFromXPath(docmt, xpath, platform) {
89
+ function getAiElementFromXPath(docmt, xpath, platform) {
89
90
  if (platform !== "web") {
90
91
  const ffMatch = xpath.match(/^\/\/\*\[@FF-inspecter="([^"]+)"\]$/);
91
92
  if (ffMatch) {
92
93
  return docmt.querySelector(`[FF-inspecter="${ffMatch[1]}"]`);
93
94
  }
94
95
  }
95
- return (0, xpathHelpers_js_1.evaluateXPath)(xpath, docmt, "first").singleNodeValue;
96
+ return (0, xpathHelpers_js_1.evaluateAiXPath)(xpath, docmt, "first").singleNodeValue;
96
97
  }
97
- function checkReferenceElementIsValid(locator, relation, docmt) {
98
+ function checkAiReferenceElementIsValid(locator, relation, docmt) {
98
99
  if (locator.includes(relation)) {
99
100
  const locatotSplitArray = locator.split(relation);
100
101
  const sourceLoc = locatotSplitArray[0].trim();
101
- const window = docmt.defaultView;
102
- if (!window)
103
- return null;
104
102
  if (!locator.includes("dynamic")) {
105
- const sourceElement = (0, xpathHelpers_js_1.evaluateXPath)(sourceLoc, docmt, "first").singleNodeValue;
103
+ const sourceElement = (0, xpathHelpers_js_1.evaluateAiXPath)(sourceLoc, docmt, "first").singleNodeValue;
106
104
  if (sourceElement) {
107
- const completeElement = (0, xpathHelpers_js_1.evaluateXPath)(locator, docmt, "first").singleNodeValue;
105
+ const completeElement = (0, xpathHelpers_js_1.evaluateAiXPath)(locator, docmt, "first").singleNodeValue;
108
106
  let relativeXpath;
109
107
  if (completeElement) {
110
108
  relativeXpath = locator;
@@ -123,12 +121,12 @@ function checkReferenceElementIsValid(locator, relation, docmt) {
123
121
  }
124
122
  return null;
125
123
  }
126
- const getElementsFromHTML = (record, htmlString, platform) => {
124
+ const getAiElementsFromHTML = (record, htmlString, platform) => {
127
125
  const virtualConsole = new jsdom_1.VirtualConsole();
128
126
  let docmt;
129
127
  if (platform === "web") {
130
128
  try {
131
- const dom = new jsdom_1.JSDOM(htmlString, {
129
+ const dom = new jsdom_1.JSDOM((0, domSanitizer_js_1.sanitizeWebDom)(htmlString), {
132
130
  resources: "usable",
133
131
  runScripts: "outside-only",
134
132
  pretendToBeVisual: true,
@@ -138,7 +136,7 @@ const getElementsFromHTML = (record, htmlString, platform) => {
138
136
  docmt = dom.window.document;
139
137
  }
140
138
  catch (e) {
141
- logData_js_1.logger.error("Unable to parse XML : ", e.message);
139
+ logData_js_1.logger.error("Unable to parse HTML : ", e.message);
142
140
  return null;
143
141
  }
144
142
  }
@@ -155,15 +153,15 @@ const getElementsFromHTML = (record, htmlString, platform) => {
155
153
  return null;
156
154
  }
157
155
  }
158
- const elementsToRemove = docmt.querySelectorAll("script, style, link[rel='stylesheet'], meta, noscript, embed, object, param, source");
159
- if (elementsToRemove) {
160
- elementsToRemove.forEach((tag) => {
156
+ const aiElementsToRemove = docmt.querySelectorAll("script, style, link[rel='stylesheet'], meta, noscript, embed, object, param, source");
157
+ if (aiElementsToRemove) {
158
+ aiElementsToRemove.forEach((tag) => {
161
159
  tag.remove();
162
160
  });
163
161
  }
164
- const finalLocatorsSet = new Set();
162
+ const finalAiLocatorsSet = new Set();
165
163
  const finalLocators = [];
166
- function createLocator(base, overrides = {}) {
164
+ function createAiLocator(base, overrides = {}) {
167
165
  const newLocator = {
168
166
  name: overrides.name ?? base?.name,
169
167
  type: overrides.type ?? base?.type,
@@ -172,12 +170,12 @@ const getElementsFromHTML = (record, htmlString, platform) => {
172
170
  status: overrides.status ?? base?.status,
173
171
  isRecorded: overrides.isRecorded ?? base?.isRecorded
174
172
  };
175
- newLocator.isSelfHealed = "Y";
176
- pushUniqueLocator(newLocator);
173
+ newLocator.isAiRecorded = "Y";
174
+ pushAiUniqueLocator(newLocator);
177
175
  }
178
- function resolveElement(ctx, locator, selector) {
179
- if (isCssSelectorLocator(locator)) {
180
- return getElementFromCssSelector(ctx, selector);
176
+ function resolveAiElement(ctx, locator, selector) {
177
+ if (isAiCssSelectorLocator(locator)) {
178
+ return getAiElementFromCssSelector(ctx, selector);
181
179
  }
182
180
  else if (locator.name.includes("id") || selector.startsWith("#")) {
183
181
  return ctx.querySelector("#" + (0, xpathHelpers_js_1.escapeAttrValue)(selector));
@@ -200,11 +198,11 @@ const getElementsFromHTML = (record, htmlString, platform) => {
200
198
  }
201
199
  else if ((locator.name.includes("xpath") || selector.startsWith("//")) &&
202
200
  !locator.type.match("dynamic")) {
203
- const el = getElementFromXPath(ctx, selector, platform);
201
+ const el = getAiElementFromXPath(ctx, selector, platform);
204
202
  if (el) {
205
- createLocator(locator, {
203
+ createAiLocator(locator, {
206
204
  value: selector,
207
- isRecorded: String(locator.isRecorded).includes("N") ? "N" : "Y"
205
+ isRecorded: "N"
208
206
  });
209
207
  }
210
208
  return el;
@@ -213,14 +211,14 @@ const getElementsFromHTML = (record, htmlString, platform) => {
213
211
  return ctx.querySelector(selector);
214
212
  }
215
213
  }
216
- function findInIframes(docmt, locator, selector) {
214
+ function aiFindInIframes(docmt, locator, selector) {
217
215
  const iframes = docmt.querySelectorAll("iframe");
218
216
  for (const iframe of iframes) {
219
217
  try {
220
218
  const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
221
219
  if (!iframeDoc)
222
220
  continue;
223
- const el = resolveElement(iframeDoc, locator, selector);
221
+ const el = resolveAiElement(iframeDoc, locator, selector);
224
222
  if (el)
225
223
  return el;
226
224
  }
@@ -230,15 +228,15 @@ const getElementsFromHTML = (record, htmlString, platform) => {
230
228
  }
231
229
  return null;
232
230
  }
233
- function pushUniqueLocator(obj) {
231
+ function pushAiUniqueLocator(obj) {
234
232
  const key = `${obj.name}:${obj.value}`;
235
- if (!finalLocatorsSet.has(key)) {
236
- finalLocatorsSet.add(key);
233
+ if (!finalAiLocatorsSet.has(key)) {
234
+ finalAiLocatorsSet.add(key);
237
235
  finalLocators.push(obj);
238
236
  }
239
237
  }
240
238
  /** Locator Value Cleaner (Handles Special Scenarios) **/
241
- const cleanLocatorValue = (val, type, isRecorded) => {
239
+ const cleanAiLocatorValue = (val, type) => {
242
240
  if (!val)
243
241
  return null;
244
242
  if (val.toLowerCase().includes('ff-inspecter') || val.toLowerCase().includes('ff-inspect')) {
@@ -266,7 +264,7 @@ const getElementsFromHTML = (record, htmlString, platform) => {
266
264
  if (type === "id" || type === "name") {
267
265
  cleaned = cleaned.replace(/['"]/g, "").trim();
268
266
  }
269
- if (platform === "web" && type === "xpath" && isRecorded === "Y" && !val.startsWith("//"))
267
+ if (platform === "web" && type === "xpath" && !val.startsWith("//"))
270
268
  return null;
271
269
  // Final check for empty strings
272
270
  if (!cleaned || /^['"]{2}$/.test(cleaned))
@@ -278,7 +276,7 @@ const getElementsFromHTML = (record, htmlString, platform) => {
278
276
  const recordedNLocators = record.locators.filter((l) => l.isRecorded === "N");
279
277
  if (recordedNLocators.length > 0) {
280
278
  for (const locator of recordedNLocators) {
281
- createLocator(locator);
279
+ createAiLocator(locator);
282
280
  }
283
281
  }
284
282
  const isDynamic = String(locator.value || locator.type || "");
@@ -286,7 +284,7 @@ const getElementsFromHTML = (record, htmlString, platform) => {
286
284
  isDynamic.match("dynamic") ||
287
285
  isDynamic.includes("{") ||
288
286
  isDynamic.includes("}")) {
289
- createLocator(locator);
287
+ createAiLocator(locator);
290
288
  continue;
291
289
  }
292
290
  // if (record.isShared.includes("Y")) {
@@ -302,110 +300,110 @@ const getElementsFromHTML = (record, htmlString, platform) => {
302
300
  }
303
301
  const trimmedSelector = selector.trim();
304
302
  //normal DOM
305
- targetElement = resolveElement(docmt, locator, trimmedSelector);
303
+ targetElement = resolveAiElement(docmt, locator, trimmedSelector);
306
304
  //iframe (if not found)
307
305
  if (!targetElement && platform === "web") {
308
- targetElement = findInIframes(docmt, locator, trimmedSelector);
306
+ targetElement = aiFindInIframes(docmt, locator, trimmedSelector);
309
307
  }
310
308
  //shadow DOM (if still not found)
311
309
  if (!targetElement && platform === "web") {
312
- targetElement = getElementFromShadowRoot(docmt.body, trimmedSelector);
310
+ targetElement = getAiElementFromShadowRoot(docmt.body, trimmedSelector);
313
311
  }
314
312
  if (!targetElement) {
315
313
  console.warn("Locator failed:", trimmedSelector);
316
314
  continue locators;
317
315
  }
318
316
  }
319
- const locatorExists = (name, value) => {
317
+ const locatorAiExists = (name, value) => {
320
318
  const key = `${name}:${value}`;
321
- return finalLocatorsSet.has(key);
319
+ return finalAiLocatorsSet.has(key);
322
320
  };
323
321
  if (targetElement) {
324
322
  const excludedAttributes = [];
325
- const idValue = getId(targetElement);
323
+ const idValue = getaiId(targetElement);
326
324
  const ffXpath = targetElement.getAttribute("ff-xpath");
327
325
  if (idValue &&
328
- !locatorExists("id", idValue) &&
329
- !(0, xpathHelpers_js_1.isNumberExist)(idValue)) {
326
+ !locatorAiExists("id", idValue) &&
327
+ !(0, xpathHelpers_js_1.isAiNumberExist)(idValue)) {
330
328
  const prevId = record.locators.find((l) => l.name === "id");
331
- if ((0, xpathHelpers_js_1.isUniqueInDOM)(docmt, "id", idValue, targetElement)) {
329
+ if ((0, xpathHelpers_js_1.isAiUniqueInDOM)(docmt, "id", idValue, targetElement)) {
332
330
  excludedAttributes.push("id");
333
- createLocator(prevId, {
331
+ createAiLocator(prevId, {
334
332
  name: "id",
335
333
  type: "static",
336
- isRecorded: "Y",
334
+ isRecorded: "N",
337
335
  value: idValue
338
336
  });
339
337
  }
340
338
  }
341
339
  const tagName = targetElement.tagName;
342
- if (tagName && !locatorExists("tagName", tagName)) {
340
+ if (tagName && platform === "web" && !locatorAiExists("tagName", tagName)) {
343
341
  const prevTag = record.locators.find((l) => l.name === "tagName");
344
- if ((0, xpathHelpers_js_1.isUniqueInDOM)(docmt, "tagName", tagName, targetElement)) {
342
+ if ((0, xpathHelpers_js_1.isAiUniqueInDOM)(docmt, "tagName", tagName, targetElement)) {
345
343
  excludedAttributes.push("tagName");
346
- createLocator(prevTag, {
344
+ createAiLocator(prevTag, {
347
345
  name: "tagName",
348
346
  type: "static",
349
- isRecorded: "Y",
347
+ isRecorded: "N",
350
348
  value: tagName
351
349
  });
352
350
  }
353
351
  }
354
- const textValue = getVisibleText(targetElement);
352
+ const textValue = getAiVisibleText(targetElement);
355
353
  if (targetElement.tagName.toLowerCase() === "a" &&
356
354
  textValue &&
357
- !(0, xpathHelpers_js_1.isNumberExist)(textValue)) {
355
+ !(0, xpathHelpers_js_1.isAiNumberExist)(textValue)) {
358
356
  const prevLinkText = record.locators.find((l) => l.name === "linkText");
359
- if ((0, xpathHelpers_js_1.isUniqueInDOM)(docmt, "linkText", textValue, targetElement)) {
357
+ if ((0, xpathHelpers_js_1.isAiUniqueInDOM)(docmt, "linkText", textValue, targetElement)) {
360
358
  excludedAttributes.push("linkText");
361
- createLocator(prevLinkText, {
359
+ createAiLocator(prevLinkText, {
362
360
  name: "linkText",
363
361
  type: "static",
364
- isRecorded: "Y",
362
+ isRecorded: "N",
365
363
  value: textValue
366
364
  });
367
365
  }
368
366
  }
369
- const nameLocator = getName(targetElement);
367
+ const nameLocator = getAiName(targetElement);
370
368
  if (nameLocator &&
371
- !locatorExists("name", nameLocator) &&
372
- !(0, xpathHelpers_js_1.isNumberExist)(nameLocator)) {
369
+ !locatorAiExists("name", nameLocator) &&
370
+ !(0, xpathHelpers_js_1.isAiNumberExist)(nameLocator)) {
373
371
  const prevName = record.locators.find((l) => l.name === "name");
374
- if ((0, xpathHelpers_js_1.isUniqueInDOM)(docmt, "name", nameLocator, targetElement)) {
372
+ if ((0, xpathHelpers_js_1.isAiUniqueInDOM)(docmt, "name", nameLocator, targetElement)) {
375
373
  excludedAttributes.push("name");
376
- createLocator(prevName, {
374
+ createAiLocator(prevName, {
377
375
  name: "name",
378
376
  type: "static",
379
- isRecorded: "Y",
377
+ isRecorded: "N",
380
378
  value: nameLocator
381
379
  });
382
380
  }
383
381
  }
384
- const classValue = getClassName(targetElement);
382
+ const classValue = getAiClassName(targetElement);
385
383
  if (classValue &&
386
384
  classValue.trim() !== "" &&
387
385
  !classValue.includes(" ") &&
388
- !locatorExists("className", classValue) &&
389
- !(0, xpathHelpers_js_1.isNumberExist)(classValue)) {
386
+ !locatorAiExists("className", classValue) &&
387
+ !(0, xpathHelpers_js_1.isAiNumberExist)(classValue)) {
390
388
  const prevClassLocator = record.locators.find((l) => l.name === "className");
391
- if ((0, xpathHelpers_js_1.isUniqueInDOM)(docmt, "className", classValue, targetElement)) {
389
+ if ((0, xpathHelpers_js_1.isAiUniqueInDOM)(docmt, "className", classValue, targetElement)) {
392
390
  excludedAttributes.push("className");
393
- createLocator(prevClassLocator, {
391
+ createAiLocator(prevClassLocator, {
394
392
  name: "className",
395
393
  type: "static",
396
- isRecorded: "Y",
394
+ isRecorded: "N",
397
395
  value: classValue
398
396
  });
399
397
  }
400
398
  }
401
- (0, cssSelector_js_1.parseCssSelectors)(targetElement, "single").forEach((cssSelector) => {
399
+ (0, cssSelector_js_1.parseAiCssSelectors)(targetElement, "single").forEach((cssSelector) => {
402
400
  if (cssSelector.value &&
403
- !locatorExists("cssSelector", cssSelector.value)) {
404
- createLocator(undefined, {
401
+ !locatorAiExists("cssSelector", cssSelector.value)) {
402
+ createAiLocator(undefined, {
405
403
  name: "cssSelector",
406
404
  value: cssSelector.value,
407
405
  type: "static",
408
- isRecorded: "Y"
406
+ isRecorded: "N"
409
407
  });
410
408
  }
411
409
  });
@@ -415,7 +413,7 @@ const getElementsFromHTML = (record, htmlString, platform) => {
415
413
  let xpathResults = [];
416
414
  try {
417
415
  xpathResults =
418
- (0, xpath_js_1.parseDOM)(targetElement, docmt, false, true, includedAttributes, [], platform) ??
416
+ (0, xpath_js_1.aiParseDOM)(targetElement, docmt, true, includedAttributes, platform) ??
419
417
  [];
420
418
  }
421
419
  catch (error) {
@@ -428,27 +426,35 @@ const getElementsFromHTML = (record, htmlString, platform) => {
428
426
  if (!result.value)
429
427
  return;
430
428
  if (result.key === "iosClassChain") {
431
- createLocator(undefined, {
432
- name: "class Chain",
429
+ createAiLocator(undefined, {
430
+ name: "iOSClassChain",
433
431
  value: result.value,
434
432
  type: "static",
435
- isRecorded: "Y"
433
+ isRecorded: "N"
436
434
  });
437
435
  }
438
436
  else if (result.key === "iosPredicateString") {
439
- createLocator(undefined, {
440
- name: "predicate String",
437
+ createAiLocator(undefined, {
438
+ name: "iOSNsPredicateString",
441
439
  value: result.value,
442
440
  type: "static",
443
- isRecorded: "Y"
441
+ isRecorded: "N"
444
442
  });
445
443
  }
444
+ // else if (result.key === "iosAccessibilityID") {
445
+ // createAiLocator(undefined, {
446
+ // name: "accessibilityId",
447
+ // value: result.value,
448
+ // type: "static",
449
+ // isRecorded: "N"
450
+ // });
451
+ // }
446
452
  else {
447
- createLocator(undefined, {
453
+ createAiLocator(undefined, {
448
454
  name: "xpath",
449
455
  value: result.value,
450
456
  type: "static",
451
- isRecorded: "Y"
457
+ isRecorded: "N"
452
458
  });
453
459
  }
454
460
  });
@@ -456,17 +462,14 @@ const getElementsFromHTML = (record, htmlString, platform) => {
456
462
  for (const loc of record.locators) {
457
463
  if (!loc.value)
458
464
  continue;
459
- for (const relation of relations) {
465
+ for (const relation of aiRelations) {
460
466
  if (loc.value.includes(relation)) {
461
- const relativeXpath = checkReferenceElementIsValid(loc.value, relation, docmt);
467
+ const relativeXpath = checkAiReferenceElementIsValid(loc.value, relation, docmt);
462
468
  if (relativeXpath) {
463
- createLocator(loc, {
469
+ createAiLocator(loc, {
464
470
  name: "xpath",
465
471
  value: relativeXpath,
466
- isRecorded: loc.isRecorded !== "" &&
467
- locator.isRecorded !== null
468
- ? locator.isRecorded
469
- : "Y"
472
+ isRecorded: "N"
470
473
  });
471
474
  break;
472
475
  }
@@ -479,14 +482,14 @@ const getElementsFromHTML = (record, htmlString, platform) => {
479
482
  }
480
483
  if (finalLocators.length < 5) {
481
484
  const fallbackCandidates = [
482
- { name: "id", value: getId(targetElement) },
483
- { name: "name", value: getName(targetElement) },
484
- { name: "className", value: getClassName(targetElement) },
485
+ { name: "id", value: getaiId(targetElement) },
486
+ { name: "name", value: getAiName(targetElement) },
487
+ { name: "className", value: getAiClassName(targetElement) },
485
488
  { name: "tagName", value: targetElement.tagName },
486
489
  {
487
490
  name: "linkText",
488
491
  value: targetElement.tagName.toLowerCase() === "a"
489
- ? getVisibleText(targetElement)
492
+ ? getAiVisibleText(targetElement)
490
493
  : null
491
494
  }
492
495
  ];
@@ -496,46 +499,59 @@ const getElementsFromHTML = (record, htmlString, platform) => {
496
499
  const { name, value } = candidate;
497
500
  if (!value)
498
501
  continue;
499
- if ((0, xpathHelpers_js_1.isNumberExist)(value))
502
+ if ((0, xpathHelpers_js_1.isAiNumberExist)(value))
500
503
  continue;
501
504
  if (name === "className" && value.includes(" "))
502
505
  continue;
503
- if ((0, xpathHelpers_js_1.isUniqueInDOM)(docmt, name, value, targetElement)) {
504
- createLocator(undefined, {
506
+ if ((0, xpathHelpers_js_1.isAiUniqueInDOM)(docmt, name, value, targetElement)) {
507
+ createAiLocator(undefined, {
505
508
  name,
506
509
  type: "static",
507
510
  value,
508
- isRecorded: "Y",
509
- isSelfHealed: "Y"
511
+ isRecorded: "N",
512
+ isAiRecorded: "Y"
510
513
  });
511
514
  }
512
515
  }
513
516
  if (finalLocators.length < 5) {
514
- (0, cssSelector_js_1.parseCssSelectors)(targetElement, "multiple").forEach((cssSelector) => {
517
+ (0, cssSelector_js_1.parseAiCssSelectors)(targetElement, "multiple").forEach((cssSelector) => {
515
518
  if (finalLocators.length > 4)
516
519
  return;
517
520
  if (!cssSelector.value)
518
521
  return;
519
- if (!(0, xpathHelpers_js_1.isUniqueInDOM)(docmt, "cssSelector", cssSelector.value, targetElement)) {
522
+ if (!(0, xpathHelpers_js_1.isAiUniqueInDOM)(docmt, "cssSelector", cssSelector.value, targetElement)) {
520
523
  return;
521
524
  }
522
- createLocator(undefined, {
525
+ createAiLocator(undefined, {
523
526
  name: "cssSelector",
524
527
  type: "static",
525
528
  value: cssSelector.value,
526
- isRecorded: "Y",
527
- isSelfHealed: "Y"
529
+ isRecorded: "N",
530
+ isAiRecorded: "Y"
528
531
  });
529
532
  });
530
533
  }
531
534
  }
532
535
  const finalAutoHealedLocators = finalLocators.map((obj) => ({
533
536
  ...obj,
534
- value: cleanLocatorValue(obj.value, obj.name, obj.isRecorded)
537
+ value: cleanAiLocatorValue(obj.value, obj.name)
535
538
  }));
539
+ const getLocatorPriority = (name) => {
540
+ const lower = (name || "").toLowerCase();
541
+ if (lower === "id")
542
+ return 1;
543
+ if (lower === "name")
544
+ return 2;
545
+ if (lower === "xpath")
546
+ return 3;
547
+ return 4;
548
+ };
549
+ const validLocators = finalAutoHealedLocators
550
+ .filter((locator) => locator?.value != null && locator.value !== "")
551
+ .sort((a, b) => getLocatorPriority(a.name) - getLocatorPriority(b.name));
536
552
  const jsonResult = [
537
553
  {
538
- locators: finalAutoHealedLocators.filter((locator) => locator?.value != null && locator.value !== ""),
554
+ locators: validLocators,
539
555
  // isShared: `${record.isShared}`,
540
556
  }
541
557
  ];
@@ -554,4 +570,4 @@ const getElementsFromHTML = (record, htmlString, platform) => {
554
570
  }
555
571
  return null;
556
572
  };
557
- exports.getElementsFromHTML = getElementsFromHTML;
573
+ exports.getAiElementsFromHTML = getAiElementsFromHTML;
@@ -5,7 +5,7 @@ export interface Locator {
5
5
  reference: string;
6
6
  status: string;
7
7
  isRecorded: string;
8
- isSelfHealed?: string;
8
+ isAiRecorded?: string;
9
9
  }
10
10
  export interface ElementRecord {
11
11
  locators: Locator[];
@@ -15,3 +15,13 @@ export type XPathEntry = {
15
15
  key: string;
16
16
  value: string;
17
17
  };
18
+ export interface AiDomContext {
19
+ tag: string;
20
+ attributes: Attr[];
21
+ normalizedText: string;
22
+ filteredText: string;
23
+ parent: Element | null;
24
+ ancestors: Element[];
25
+ previousSiblings: Element[];
26
+ nextSiblings: Element[];
27
+ }
@@ -1,2 +1,2 @@
1
1
  import { XPathEntry } from "../types/locator.js";
2
- export declare const generateAndroidLocators: (element: HTMLElement | Element, docmt: Document, isTarget: boolean) => XPathEntry[];
2
+ export declare const generateAiAndroidLocators: (element: HTMLElement | Element, docmt: Document, isTarget: boolean) => XPathEntry[];