ff-automationv2 2.2.33 → 2.2.34-beta.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.
Files changed (37) hide show
  1. package/dist/automation/actions/interaction/clear/clear.js +4 -1
  2. package/dist/automation/actions/interaction/clear/clearAndEnter.js +4 -1
  3. package/dist/automation/actions/interaction/elementlessActions/getOtp.js +2 -2
  4. package/dist/automation/actions/interaction/enterActions/EnterInputIntoElementFromClipBoardInterface_mob.js +4 -1
  5. package/dist/automation/actions/interaction/enterActions/enterInput.js +5 -2
  6. package/dist/automation/actions/interaction/enterActions/enterInputAndPress.js +4 -1
  7. package/dist/automation/actions/interaction/enterActions/waitAndEnter.js +4 -1
  8. package/dist/automation/actions/interaction/get/getText.js +9 -2
  9. package/dist/automation/actions/interaction/iframe/switchToDefaultContent.js +1 -1
  10. package/dist/automation/actions/interaction/verify/VerifyElementNotContainsText.js +4 -1
  11. package/dist/automation/actions/interaction/verify/verifypartialtext.js +9 -2
  12. package/dist/automation/actions/interaction/verify/verifytext.js +9 -2
  13. package/dist/core/helpers/elementSelectorResolver.d.ts +1 -1
  14. package/dist/core/helpers/elementSelectorResolver.js +3 -2
  15. package/dist/core/helpers/runnerDomPipeline.d.ts +2 -2
  16. package/dist/core/helpers/runnerDomPipeline.js +20 -9
  17. package/dist/core/helpers/visionFallbackHandler.js +4 -4
  18. package/dist/core/interfaces/automationRunnerInterface.d.ts +1 -0
  19. package/dist/core/main/runAutomationScript.js +13 -3
  20. package/dist/fireflinkData/fireflinkLocators/getListOfLocators.d.ts +2 -1
  21. package/dist/fireflinkData/fireflinkLocators/getListOfLocators.js +2 -2
  22. package/dist/fireflinkData/fireflinkScript/appendScriptData.js +42 -6
  23. package/dist/fireflinkData/fireflinkScript/scriptGenrationData.d.ts +1 -0
  24. package/dist/fireflinkData/fireflinkScript/scriptGenrationData.js +1 -0
  25. package/dist/imageAnalysisWeb/annotateScreenshot.d.ts +1 -1
  26. package/dist/imageAnalysisWeb/annotateScreenshot.js +24 -10
  27. package/dist/imageAnalysisWeb/generateAnnotatedScreenshots.js +5 -2
  28. package/dist/tests/senario.d.ts +0 -0
  29. package/dist/tests/senario.js +1120 -0
  30. package/dist/tests/test12.d.ts +1 -0
  31. package/dist/tests/test12.js +34 -65
  32. package/dist/utils/DomExtraction/jsForAttributeInjection.js +23 -0
  33. package/dist/utils/helpers/xpathcreation.js +3 -0
  34. package/dist/utils/iframesExtraction/findElementUsingFF.js +1 -2
  35. package/dist/utils/iframesExtraction/switchToIframeByMeta.js +1 -1
  36. package/dist/utils/workers/locatorWorker.js +3 -1
  37. package/package.json +1 -1
@@ -9,7 +9,10 @@ async function clear(args) {
9
9
  case "android":
10
10
  case "ios":
11
11
  try {
12
- const { ffNumber, xpathPath } = (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
12
+ const isWebView = args.pageDOM?.includes("ff-inspect");
13
+ const { ffNumber, xpathPath } = isWebView
14
+ ? (0, enterActionHelper_js_1.enterActionHelper)(args.pageDOM, args.fireflinkIndex)
15
+ : (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
13
16
  await args.driver.$(xpathPath).clearValue();
14
17
  const ffElementNumber = `Fire-Flink-${ffNumber}`;
15
18
  (0, appendScriptData_js_1.appendScriptData)({
@@ -10,7 +10,10 @@ async function clearAndEnter(args) {
10
10
  case "android":
11
11
  case "ios":
12
12
  try {
13
- const { ffNumber, xpathPath } = (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
13
+ const isWebView = args.pageDOM?.includes("ff-inspect");
14
+ const { ffNumber, xpathPath } = isWebView
15
+ ? (0, enterActionHelper_js_1.enterActionHelper)(args.pageDOM, args.fireflinkIndex)
16
+ : (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
14
17
  const element = args.driver.$(xpathPath);
15
18
  await element.clearValue();
16
19
  await element.setValue(args.value);
@@ -46,7 +46,7 @@ async function GetOtpAction(args) {
46
46
  (0, appendScriptData_js_1.appendScriptData)({
47
47
  scriptDataAppender: args.scriptDataAppender,
48
48
  nlpName: "MOB_FetchOtpFromMessages",
49
- stepInputs: [existingSms.address, timeFrom + "s", waitTime],
49
+ stepInputs: [existingSms.address, timeFrom + "s", waitTime, _regex],
50
50
  platform: "android",
51
51
  returnTypeVariableName: args.returnTypeVariableName
52
52
  });
@@ -84,7 +84,7 @@ async function GetOtpAction(args) {
84
84
  (0, appendScriptData_js_1.appendScriptData)({
85
85
  scriptDataAppender: args.scriptDataAppender,
86
86
  nlpName: "MOB_FetchOtpFromMessages",
87
- stepInputs: [latestSms.address, timeFrom + "s", waitTime],
87
+ stepInputs: [latestSms.address, timeFrom + "s", waitTime, regex],
88
88
  platform: "android",
89
89
  returnTypeVariableName: args.returnTypeVariableName
90
90
  });
@@ -7,7 +7,10 @@ const logData_js_1 = require("../../../../utils/logger/logData.js");
7
7
  const saveStepInputData_js_1 = require("../../../../utils/helpers/saveStepInputData.js");
8
8
  async function MOB_EnterInputIntoElementFromClipBoard(args) {
9
9
  try {
10
- const { ffNumber, xpathPath } = (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
10
+ const isWebView = args.pageDOM?.includes("ff-inspect");
11
+ const { ffNumber, xpathPath } = isWebView
12
+ ? (0, enterActionHelper_js_1.enterActionHelper)(args.pageDOM, args.fireflinkIndex)
13
+ : (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
11
14
  const element = await args.driver.$(xpathPath);
12
15
  const base64Value = await args.driver.getClipboard('plaintext');
13
16
  const value = Buffer.from(base64Value, 'base64').toString('utf-8');
@@ -44,7 +44,10 @@ async function enterInput(args) {
44
44
  case "android":
45
45
  case "ios":
46
46
  try {
47
- const { ffNumber, xpathPath } = (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
47
+ const isWebView = args.pageDOM?.includes("ff-inspect");
48
+ const { ffNumber, xpathPath } = isWebView
49
+ ? (0, enterActionHelper_js_1.enterActionHelper)(args.pageDOM, args.fireflinkIndex)
50
+ : (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
48
51
  const element = await args.driver.$(xpathPath);
49
52
  if (args.stepIndex + 1 < args.filteredSteps.length &&
50
53
  args.filteredSteps[args.stepIndex].toLowerCase().includes("enter")) {
@@ -54,7 +57,7 @@ async function enterInput(args) {
54
57
  else {
55
58
  await element.setValue(args.value);
56
59
  }
57
- if (args.platform === "android") {
60
+ if (args.platform === "android" && !isWebView) {
58
61
  try {
59
62
  const text = await element.getAttribute("text");
60
63
  if (text !== args.value) {
@@ -8,7 +8,10 @@ async function enterInputAndPress(args) {
8
8
  switch (args.platform) {
9
9
  case "android":
10
10
  try {
11
- const { ffNumber, xpathPath } = (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
11
+ const isWebView = args.pageDOM?.includes("ff-inspect");
12
+ const { ffNumber, xpathPath } = isWebView
13
+ ? (0, enterActionHelper_js_1.enterActionHelper)(args.pageDOM, args.fireflinkIndex)
14
+ : (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
12
15
  const element = await args.driver.$(xpathPath);
13
16
  const parts = String(args.value).split(",");
14
17
  const inputValue = parts[0]?.trim() || "";
@@ -19,7 +19,10 @@ async function waitAndEnter(args) {
19
19
  // ---------------- ANDROID ----------------
20
20
  case "android":
21
21
  try {
22
- const { ffNumber, xpathPath } = (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
22
+ const isWebView = args.pageDOM?.includes("ff-inspect");
23
+ const { ffNumber, xpathPath } = isWebView
24
+ ? (0, enterActionHelper_js_1.enterActionHelper)(args.pageDOM, args.fireflinkIndex)
25
+ : (0, enterActionHelper_js_1.enterActionHelperMob)(args.pageDOM, args.fireflinkIndex);
23
26
  const { inputValue, waitTimeSeconds } = parseValue(args.value);
24
27
  const element = await args.driver.$(xpathPath);
25
28
  // Wait before typing
@@ -11,8 +11,15 @@ const getText = async (args) => {
11
11
  case "ios":
12
12
  try {
13
13
  const element = await args.driver.$(args.selector);
14
- const attrName = args.platform === "ios" ? "value" : "text";
15
- const _text = await element.getAttribute(attrName);
14
+ const isWebView = args.pageDOM?.includes("ff-inspect");
15
+ let _text = null;
16
+ if (isWebView) {
17
+ _text = await element.getText();
18
+ }
19
+ else {
20
+ const attrName = args.platform === "ios" ? "value" : "text";
21
+ _text = await element.getAttribute(attrName);
22
+ }
16
23
  logData_js_1.logger.info("Text", _text);
17
24
  (0, saveStepInputData_js_1.saveStepInputData)(args, _text);
18
25
  (0, appendScriptData_js_1.appendScriptData)({
@@ -4,7 +4,7 @@ exports.switchToDefaultContent = switchToDefaultContent;
4
4
  const appendScriptData_js_1 = require("../../../../fireflinkData/fireflinkScript/appendScriptData.js");
5
5
  async function switchToDefaultContent(args) {
6
6
  try {
7
- await args.driver.switchToFrame(null);
7
+ await args.driver.switchFrame(null);
8
8
  (0, appendScriptData_js_1.appendScriptData)({
9
9
  scriptDataAppender: args.scriptDataAppender,
10
10
  nlpName: "SwitchToDefaultContent"
@@ -7,7 +7,10 @@ async function verifyElementNotContainsText(args) {
7
7
  case "android":
8
8
  try {
9
9
  const element = await args.driver.$(args.selector);
10
- const expected = await element.getAttribute("text");
10
+ const isWebView = args.pageDOM?.includes("ff-inspect");
11
+ const expected = isWebView
12
+ ? (await element.getText()) || ""
13
+ : (await element.getAttribute("text")) || "";
11
14
  const caseSensitive = false;
12
15
  if (expected == args.value) {
13
16
  throw new Error(`Element do contain the text. Expected: not containing "${args.value}", Actual: contains "${expected}"`);
@@ -10,8 +10,15 @@ async function verifyPartialText(args) {
10
10
  case "ios":
11
11
  try {
12
12
  const element = await args.driver.$(args.selector);
13
- const attributeName = args.platform === "ios" ? "value" : "text";
14
- const actual = (await element.getAttribute(attributeName)) || "";
13
+ const isWebView = args.pageDOM?.includes("ff-inspect");
14
+ let actual;
15
+ if (isWebView) {
16
+ actual = (await element.getText()) || "";
17
+ }
18
+ else {
19
+ const attributeName = args.platform === "ios" ? "value" : "text";
20
+ actual = (await element.getAttribute(attributeName)) || "";
21
+ }
15
22
  const expected = args.value;
16
23
  if (!actual?.includes(expected)) {
17
24
  throw new Error(`Element does not contain the expected text. Expected to contain: "${args.value}", Actual: "${actual}"`);
@@ -10,8 +10,15 @@ async function verifyText(args) {
10
10
  case "ios":
11
11
  try {
12
12
  const element = await args.driver.$(args.selector);
13
- const attributeName = args.platform === "ios" ? "value" : "text";
14
- const text = (await element.getAttribute(attributeName)) || "";
13
+ const isWebView = args.pageDOM?.includes("ff-inspect");
14
+ let text;
15
+ if (isWebView) {
16
+ text = (await element.getText()) || "";
17
+ }
18
+ else {
19
+ const attributeName = args.platform === "ios" ? "value" : "text";
20
+ text = (await element.getAttribute(attributeName)) || "";
21
+ }
15
22
  const expected = (args.value || "").toLowerCase();
16
23
  const isMatched = text.toLowerCase().trim() === expected.trim();
17
24
  logData_js_1.logger.info("text", { text });
@@ -3,7 +3,7 @@ import { ShadowIframeResult } from "../interfaces/automationRunnerInterface.js";
3
3
  export { ShadowIframeResult };
4
4
  export declare function generateUniqueName(currentName: string | undefined, usedNames: string[]): string | undefined;
5
5
  export declare function normalizeSvgSelector(selector: string): string;
6
- export declare function resolveElementSelector(doc: any, domInfo: any, fireflinkIndex: string, platform: PlatformType, driver: any): Promise<{
6
+ export declare function resolveElementSelector(doc: any, domInfo: any, fireflinkIndex: string, platform: PlatformType, driver: any, fallbackAttempt: number, driverContext?: any): Promise<{
7
7
  selector: string;
8
8
  doc: any;
9
9
  domInfo: any;
@@ -31,11 +31,11 @@ function normalizeSvgSelector(selector) {
31
31
  }
32
32
  return selector;
33
33
  }
34
- async function resolveElementSelector(doc, domInfo, fireflinkIndex, platform, driver) {
34
+ async function resolveElementSelector(doc, domInfo, fireflinkIndex, platform, driver, fallbackAttempt, driverContext) {
35
35
  let selector;
36
36
  let updatedDoc = doc;
37
37
  let updatedDomInfo = domInfo;
38
- if (platform === "web") {
38
+ if (platform === "web" || (driverContext && fallbackAttempt > 1)) {
39
39
  if (!updatedDoc) {
40
40
  logData_js_1.logger.info("doc is undefined. Rebuilding document from domInfo.");
41
41
  if (!updatedDomInfo || !updatedDomInfo.dom) {
@@ -57,6 +57,7 @@ async function resolveElementSelector(doc, domInfo, fireflinkIndex, platform, dr
57
57
  selector = result.xpathPath;
58
58
  }
59
59
  selector = normalizeSvgSelector(selector);
60
+ selector = selector.replace(/\/div\[0\]\/div\[0\]/g, "/div[1]").replace(/\/div\[0\]/g, "/div[1]");
60
61
  return { selector, doc: updatedDoc, domInfo: updatedDomInfo };
61
62
  }
62
63
  async function handleShadowAndIframe(driver, stepAction, selector, fireflinkIndex, domInfo, actionHandlers, elementName, elementType) {
@@ -4,6 +4,6 @@ import { DomCaptureResult, DomProcessResult } from "../interfaces/automationRunn
4
4
  export { DomCaptureResult, DomProcessResult };
5
5
  export declare class RunnerDomPipeline {
6
6
  static parseDomDocument(domHtml: string, platform: PlatformType): any;
7
- static captureAndParseDom(driver: any, platform: PlatformType, stepCount: number, action: string, isRetry?: boolean): Promise<DomCaptureResult>;
8
- static processRelevantDom(domProcessor: DomProcessingEngine, domInfo: any, keywords: any, stepCount: number, action: string, currentStep: string, platform: PlatformType, driver: any, isRetry?: boolean): Promise<DomProcessResult>;
7
+ static captureAndParseDom(driver: any, platform: PlatformType, stepCount: number, action: string, isRetry?: boolean, driverContext?: any): Promise<DomCaptureResult>;
8
+ static processRelevantDom(domProcessor: DomProcessingEngine, domInfo: any, keywords: any, stepCount: number, action: string, currentStep: string, platform: PlatformType, driver: any, isRetry?: boolean, driverContext?: any): Promise<DomProcessResult>;
9
9
  }
@@ -19,7 +19,7 @@ class RunnerDomPipeline {
19
19
  return parser.window.document;
20
20
  }
21
21
  }
22
- static async captureAndParseDom(driver, platform, stepCount, action, isRetry = false) {
22
+ static async captureAndParseDom(driver, platform, stepCount, action, isRetry = false, driverContext) {
23
23
  try {
24
24
  let domInfo;
25
25
  let doc;
@@ -32,12 +32,23 @@ class RunnerDomPipeline {
32
32
  doc = RunnerDomPipeline.parseDomDocument(domInfo.dom, "web");
33
33
  }
34
34
  else {
35
- domInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOMForMobile)(driver);
36
- const fileName = isRetry
37
- ? `annotated-dom-Mob-retry-${stepCount}`
38
- : `annotated-dom-Mob-${stepCount}`;
39
- logData_js_1.logger.saveDOM(domInfo.dom, fileName);
40
- doc = RunnerDomPipeline.parseDomDocument(domInfo.dom, platform);
35
+ if (driverContext) {
36
+ await driver.switchContext(driverContext);
37
+ domInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOM)(driver);
38
+ const fileName = isRetry
39
+ ? `annotated-dom-retry-webview-${stepCount}`
40
+ : `annotated-dom-${stepCount}`;
41
+ logData_js_1.logger.saveDOM(domInfo.dom, fileName);
42
+ doc = RunnerDomPipeline.parseDomDocument(domInfo.dom, "web");
43
+ }
44
+ else {
45
+ domInfo = await (0, jsForAttributeInjection_js_1.getAnnotatedDOMForMobile)(driver);
46
+ const fileName = isRetry
47
+ ? `annotated-dom-Mob-retry-${stepCount}`
48
+ : `annotated-dom-Mob-${stepCount}`;
49
+ logData_js_1.logger.saveDOM(domInfo.dom, fileName);
50
+ doc = RunnerDomPipeline.parseDomDocument(domInfo.dom, platform);
51
+ }
41
52
  }
42
53
  return { domInfo, doc };
43
54
  }
@@ -48,11 +59,11 @@ class RunnerDomPipeline {
48
59
  throw error;
49
60
  }
50
61
  }
51
- static async processRelevantDom(domProcessor, domInfo, keywords, stepCount, action, currentStep, platform, driver, isRetry = false) {
62
+ static async processRelevantDom(domProcessor, domInfo, keywords, stepCount, action, currentStep, platform, driver, isRetry = false, driverContext) {
52
63
  try {
53
64
  let extractedRelevantDom;
54
65
  let toonDom;
55
- if (platform === "web") {
66
+ if (platform === "web" || driverContext) {
56
67
  extractedRelevantDom = await domProcessor.webProcess({
57
68
  keywords: keywords,
58
69
  rawDom: domInfo?.dom,
@@ -10,7 +10,7 @@ const runnerPostActionHelper_js_1 = require("./runnerPostActionHelper.js");
10
10
  const runnerDomPipeline_js_1 = require("./runnerDomPipeline.js");
11
11
  const logData_js_1 = require("../../utils/logger/logData.js");
12
12
  async function executeVisionFallback(params) {
13
- const { driver, platform, action, step, stepAction, inputValue, stepCount, fallbackAttempt, priorAndNextSteps, listOfSteps, currentElementName, extractorElementName, stepElementType, iframeDomHtml, beforeHandles, context, stepProcessor, actionHandlers, reporter, causeError, } = params;
13
+ const { driver, platform, action, step, stepAction, inputValue, stepCount, fallbackAttempt, priorAndNextSteps, listOfSteps, currentElementName, extractorElementName, stepElementType, iframeDomHtml, beforeHandles, context, stepProcessor, actionHandlers, reporter, causeError, driverContext } = params;
14
14
  let domInfo = params.domInfo;
15
15
  let doc = params.doc;
16
16
  logData_js_1.logger.error(`execution failed for step "${step}": ${causeError} and going for vision`);
@@ -20,7 +20,7 @@ async function executeVisionFallback(params) {
20
20
  if (action === "scroll") {
21
21
  throw new Error("Scroll action failed element not found", { cause: causeError });
22
22
  }
23
- if (platform === "web") {
23
+ if (platform === "web" || (driverContext && fallbackAttempt > 1)) {
24
24
  annotatedScreenshot = await (0, generateAnnotatedScreenshots_js_1.generateAnnotatedScreenshots)(driver);
25
25
  }
26
26
  else {
@@ -36,7 +36,7 @@ async function executeVisionFallback(params) {
36
36
  bounds = visionResult.boxes;
37
37
  }
38
38
  let stepResultVision;
39
- if (platform === "web") {
39
+ if (platform === "web" || (driverContext && fallbackAttempt > 1)) {
40
40
  stepResultVision = await stepProcessor.getLLMResponse({
41
41
  platform,
42
42
  type: promptType_js_1.PromptType.VISION_PROMPT,
@@ -73,7 +73,7 @@ async function executeVisionFallback(params) {
73
73
  throw new Error(`vision unable to find element for step "${step}"`, { cause: causeError });
74
74
  }
75
75
  let xpath;
76
- if (platform === "android" || platform === "ios") {
76
+ if ((platform === "android" || platform === "ios") && (driverContext && fallbackAttempt < 2)) {
77
77
  const index = Number(fireflinkIndex.split("-").pop());
78
78
  const box = bounds[index - 1];
79
79
  if (!box) {
@@ -52,6 +52,7 @@ export interface VisionFallbackParams {
52
52
  actionHandlers: Record<string, any>;
53
53
  reporter: RunnerKafkaReporter;
54
54
  causeError: any;
55
+ driverContext?: any;
55
56
  }
56
57
  export interface VisionFallbackResult {
57
58
  preCapturedDomInfo: any | null;
@@ -205,6 +205,7 @@ class AutomationRunner {
205
205
  currentPlatform = context.activePlatform;
206
206
  (0, platformContext_js_1.setPlatform)(currentPlatform);
207
207
  let stepResult;
208
+ let driverContext = null;
208
209
  let stepAction;
209
210
  let fireflinkIndex;
210
211
  let selector;
@@ -383,6 +384,8 @@ class AutomationRunner {
383
384
  }
384
385
  else {
385
386
  driver = await context.mobileSession.getCurrentDriver();
387
+ const contexts = await driver.getContexts();
388
+ driverContext = contexts.find((context) => String(context).startsWith("WEBVIEW")) || null;
386
389
  }
387
390
  }
388
391
  catch (error) {
@@ -518,10 +521,10 @@ class AutomationRunner {
518
521
  selector = "";
519
522
  iframeDomHtml = null;
520
523
  beforeHandles = null;
521
- const retryDomResult = await runnerDomPipeline_js_1.RunnerDomPipeline.captureAndParseDom(driver, currentPlatform, stepCount, action, true);
524
+ const retryDomResult = await runnerDomPipeline_js_1.RunnerDomPipeline.captureAndParseDom(driver, currentPlatform, stepCount, action, true, driverContext);
522
525
  domInfo = retryDomResult.domInfo;
523
526
  doc = retryDomResult.doc;
524
- const retryRelevantResult = await runnerDomPipeline_js_1.RunnerDomPipeline.processRelevantDom(domProcessor, domInfo, keywords, stepCount, action, currentStep, currentPlatform, driver, true);
527
+ const retryRelevantResult = await runnerDomPipeline_js_1.RunnerDomPipeline.processRelevantDom(domProcessor, domInfo, keywords, stepCount, action, currentStep, currentPlatform, driver, true, driverContext);
525
528
  extractedRelevantDom = retryRelevantResult.extractedRelevantDom;
526
529
  const retryToonDom = retryRelevantResult.toonDom;
527
530
  const retryActionResolution = await (0, stepActionInspector_js_1.resolveStepActionFromDom)(stepProcessor, currentPlatform, action, retryToonDom, priorAndNextSteps, currentStep, null);
@@ -560,7 +563,7 @@ class AutomationRunner {
560
563
  logData_js_1.logger.error(`element not found for step "${step}"`);
561
564
  throw new Error(`element not found for step "${step}"`);
562
565
  }
563
- const selectorResult = await (0, elementSelectorResolver_js_1.resolveElementSelector)(doc, domInfo, fireflinkIndex, currentPlatform, driver);
566
+ const selectorResult = await (0, elementSelectorResolver_js_1.resolveElementSelector)(doc, domInfo, fireflinkIndex, currentPlatform, driver, fallbackAttempt, driverContext);
564
567
  selector = selectorResult.selector;
565
568
  doc = selectorResult.doc;
566
569
  domInfo = selectorResult.domInfo;
@@ -598,6 +601,9 @@ class AutomationRunner {
598
601
  });
599
602
  preCapturedDomInfo = await (0, runnerPostActionHelper_js_1.handlePostActionWeb)(currentPlatform, driver, action, beforeHandles, context.scriptAppender, stepCount);
600
603
  if (fallbackAttempt === 2) {
604
+ if (driverContext) {
605
+ await driver.switchContext("NATIVE_APP");
606
+ }
601
607
  await reporter.sendRetry("Retry successful. Moving on to the next step.");
602
608
  }
603
609
  break;
@@ -632,11 +638,15 @@ class AutomationRunner {
632
638
  actionHandlers,
633
639
  reporter,
634
640
  causeError: error,
641
+ driverContext,
635
642
  });
636
643
  if (visionResult.retryNeeded) {
637
644
  continue;
638
645
  }
639
646
  preCapturedDomInfo = visionResult.preCapturedDomInfo;
647
+ if (driverContext) {
648
+ await driver.switchContext("NATIVE_APP");
649
+ }
640
650
  break;
641
651
  }
642
652
  }
@@ -1,6 +1,7 @@
1
+ import { platform } from "../../core/types/scriptTypesType.js";
1
2
  import { LocatorWorkerPool } from "../../utils/workers/LocatorWorkerPool.js";
2
3
  export declare class ElementGetter {
3
4
  private readonly workerPool;
4
5
  constructor(workerPool: LocatorWorkerPool);
5
- getFireFlinkElement(html: string, attribute: string): Promise<any>;
6
+ getFireFlinkElement(html: string, attribute: string, targetPlatform?: platform): Promise<any>;
6
7
  }
@@ -8,8 +8,8 @@ class ElementGetter {
8
8
  constructor(workerPool) {
9
9
  this.workerPool = workerPool;
10
10
  }
11
- async getFireFlinkElement(html, attribute) {
12
- const platform = (0, platformContext_js_1.getPlatform)();
11
+ async getFireFlinkElement(html, attribute, targetPlatform) {
12
+ const platform = targetPlatform || (html?.includes("ff-inspect") ? "web" : (0, platformContext_js_1.getPlatform)());
13
13
  // const formattedAttribute = attribute.replace('[', '//*[@');
14
14
  try {
15
15
  const result = await this.workerPool.getFireFlinkElement(html, attribute, platform);
@@ -3,10 +3,37 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.appendScriptData = appendScriptData;
4
4
  const logData_js_1 = require("../../utils/logger/logData.js");
5
5
  async function appendScriptData(args) {
6
+ const isMobile = args.platform === "android" || args.platform === "ios";
7
+ const isWebView = args.pageDOM?.includes("ff-inspect");
8
+ if (isMobile) {
9
+ if (args.scriptDataAppender.currentMobileView === undefined) {
10
+ args.scriptDataAppender.currentMobileView = "NATIVE";
11
+ }
12
+ if (isWebView && args.scriptDataAppender.currentMobileView !== "WEBVIEW") {
13
+ args.scriptDataAppender.add(async () => ({
14
+ nlpName: "MOB_SwitchToView",
15
+ stepInputs: ["WEBVIEW"],
16
+ elementsData: []
17
+ }));
18
+ args.scriptDataAppender.currentMobileView = "WEBVIEW";
19
+ }
20
+ else if (args.pageDOM && !isWebView && args.scriptDataAppender.currentMobileView === "WEBVIEW") {
21
+ args.scriptDataAppender.add(async () => ({
22
+ nlpName: "MOB_SwitchToNativeView",
23
+ stepInputs: [],
24
+ elementsData: []
25
+ }));
26
+ args.scriptDataAppender.currentMobileView = "NATIVE";
27
+ }
28
+ }
6
29
  args.scriptDataAppender.add(async () => {
7
- const searchAttribute = args.platform === "web"
8
- ? `[ff-inspect="${args.ffNumber}"]`
9
- : `[FF-inspecter="${args.ffNumber}"]`;
30
+ const isWebView = args.pageDOM?.includes("ff-inspect");
31
+ const effectivePlatform = isWebView ? "web" : args.platform;
32
+ const searchAttribute = args.ffNumber
33
+ ? (effectivePlatform === "web"
34
+ ? `[ff-inspect="${args.ffNumber}"]`
35
+ : `[FF-inspecter="${args.ffNumber}"]`)
36
+ : args.selector;
10
37
  const data = {
11
38
  nlpName: args.nlpName
12
39
  };
@@ -19,9 +46,12 @@ async function appendScriptData(args) {
19
46
  if (args.elementName) {
20
47
  let locators;
21
48
  try {
22
- const ffElement = await args.elementGetter.getFireFlinkElement(args.pageDOM, searchAttribute);
49
+ if (!searchAttribute) {
50
+ throw new Error("searchAttribute is not found");
51
+ }
52
+ const ffElement = await args.elementGetter.getFireFlinkElement(args.pageDOM, searchAttribute, effectivePlatform);
23
53
  // locators = [{ name: "xpath", value: args.selector }];
24
- if (ffElement?.locators?.length === 0) {
54
+ if (!ffElement?.locators || ffElement.locators.length === 0) {
25
55
  throw new Error("locators is not found");
26
56
  }
27
57
  else {
@@ -30,7 +60,13 @@ async function appendScriptData(args) {
30
60
  }
31
61
  catch (error) {
32
62
  logData_js_1.logger.info(`Element is not found ${error.message}`);
33
- locators = [{ name: "xpath", value: args.selector }];
63
+ locators = [{
64
+ name: "xpath",
65
+ type: "static",
66
+ value: args.selector,
67
+ isRecorded: "N",
68
+ isAiRecorded: "Y"
69
+ }];
34
70
  }
35
71
  data.elementsData = [{
36
72
  name: args.elementName,
@@ -1,5 +1,6 @@
1
1
  import { IScriptGenerationData } from "../../core/interfaces/scriptGenrationDataInterface.js";
2
2
  export declare class ScriptDataAppender {
3
+ currentMobileView: "NATIVE" | "WEBVIEW";
3
4
  private data;
4
5
  private pending;
5
6
  private errorNLP;
@@ -4,6 +4,7 @@ exports.ScriptDataAppender = void 0;
4
4
  const platformSyntax_js_1 = require("../../utils/helpers/platformSyntax.js");
5
5
  class ScriptDataAppender {
6
6
  constructor() {
7
+ this.currentMobileView = "NATIVE";
7
8
  this.data = [];
8
9
  this.pending = [];
9
10
  this.errorNLP = "";
@@ -1,2 +1,2 @@
1
1
  import { NodeItem } from "./screenshotInterface.js";
2
- export declare function annotateScreenshot(screenshotBase64: string, nodes: NodeItem[]): Promise<Buffer>;
2
+ export declare function annotateScreenshot(screenshotBase64: string, deviceWidth: number, deviceHeight: number, nodes: NodeItem[]): Promise<Buffer>;
@@ -59,10 +59,16 @@ function findFreeTagPosition(box, tagW, tagH, elementBoxes, usedTagRects, imgWid
59
59
  usedTagRects.push([fallbackX, fallbackY, fallbackX + tagW, fallbackY + tagH]);
60
60
  return { x: fallbackX, y: fallbackY };
61
61
  }
62
- async function annotateScreenshot(screenshotBase64, nodes) {
62
+ async function annotateScreenshot(screenshotBase64, deviceWidth, deviceHeight, nodes) {
63
63
  const buffer = Buffer.from(screenshotBase64, "base64");
64
64
  const image = await (0, canvas_1.loadImage)(buffer);
65
- const scale = image.width / 1920;
65
+ // Actual screenshot resolution
66
+ const screenshotWidth = image.width;
67
+ const screenshotHeight = image.height;
68
+ // Device / WebView resolution from which bbox coordinates are coming
69
+ const scaleX = screenshotWidth / deviceWidth;
70
+ const scaleY = screenshotHeight / deviceHeight;
71
+ const scale = Math.min(scaleX, scaleY);
66
72
  const fontSize = Math.max(16, Math.floor(20 * scale));
67
73
  const canvas = (0, canvas_1.createCanvas)(image.width, image.height);
68
74
  const ctx = canvas.getContext("2d");
@@ -71,20 +77,28 @@ async function annotateScreenshot(screenshotBase64, nodes) {
71
77
  ctx.textBaseline = "middle";
72
78
  ctx.textAlign = "center";
73
79
  const usedTagRects = [];
80
+ /*
81
+ * Convert all bounding boxes from device/WebView
82
+ * coordinates to screenshot coordinates.
83
+ */
74
84
  const elementBoxes = nodes.map((n) => [
75
- Math.floor(n.bbox.x),
76
- Math.floor(n.bbox.y),
77
- Math.floor(n.bbox.x + n.bbox.w),
78
- Math.floor(n.bbox.y + n.bbox.h),
85
+ Math.floor(n.bbox.x * scaleX),
86
+ Math.floor(n.bbox.y * scaleY),
87
+ Math.floor((n.bbox.x + n.bbox.w) * scaleX),
88
+ Math.floor((n.bbox.y + n.bbox.h) * scaleY),
79
89
  ]);
80
90
  nodes.forEach((item, i) => {
81
91
  const color = COLORS[i % COLORS.length];
82
92
  const colorStr = `rgb(${color[0]},${color[1]},${color[2]})`;
83
93
  const label = item.ff.split("-").pop() || "";
84
- const x1 = Math.floor(item.bbox.x);
85
- const y1 = Math.floor(item.bbox.y);
86
- const x2 = Math.floor(item.bbox.x + item.bbox.w);
87
- const y2 = Math.floor(item.bbox.y + item.bbox.h);
94
+ /*
95
+ * Convert current node bbox to actual
96
+ * screenshot coordinates.
97
+ */
98
+ const x1 = Math.floor(item.bbox.x * scaleX);
99
+ const y1 = Math.floor(item.bbox.y * scaleY);
100
+ const x2 = Math.floor((item.bbox.x + item.bbox.w) * scaleX);
101
+ const y2 = Math.floor((item.bbox.y + item.bbox.h) * scaleY);
88
102
  ctx.strokeStyle = colorStr;
89
103
  ctx.lineWidth = Math.max(2, Math.floor(2 * scale));
90
104
  ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);
@@ -14,13 +14,16 @@ async function generateAnnotatedScreenshots(driver) {
14
14
  // driver.execute(JS_PRIMARY),
15
15
  // // driver.execute(JS_SECONDARY),
16
16
  // ]);
17
+ const windowSize = await driver.getWindowSize();
18
+ const deviceWidth = windowSize.width;
19
+ const deviceHeight = windowSize.height;
17
20
  const primary = primaryRaw ?? [];
18
21
  let secondary = secondaryRaw ?? [];
19
22
  const primaryIds = new Set(primary.map((item) => item.ff));
20
23
  secondary = secondary.filter((item) => !primaryIds.has(item.ff));
21
24
  const [primaryAnnotated, secondaryAnnotated] = await Promise.all([
22
- (0, annotateScreenshot_js_1.annotateScreenshot)(screenshot, primary),
23
- (0, annotateScreenshot_js_1.annotateScreenshot)(screenshot, secondary)
25
+ (0, annotateScreenshot_js_1.annotateScreenshot)(screenshot, deviceWidth, deviceHeight, primary),
26
+ (0, annotateScreenshot_js_1.annotateScreenshot)(screenshot, deviceWidth, deviceHeight, secondary)
24
27
  ]);
25
28
  // Uncomment only when debugging
26
29
  logData_js_1.logger.saveImage(primaryAnnotated, "annotated_primary.png");
File without changes