ff-automationv2 1.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.
Files changed (69) hide show
  1. package/ARCHITECTURE.md +112 -0
  2. package/FireFlink_Architecture.drawio +68 -0
  3. package/ONBOARDING.md +29 -0
  4. package/README.md +28 -0
  5. package/TECHNICAL_DEEP_DIVE.md +26 -0
  6. package/eslint.config.ts +29 -0
  7. package/package.json +51 -0
  8. package/src/ai/llmcalls/decodeApiKey.ts +14 -0
  9. package/src/ai/llmcalls/llmAction.ts +89 -0
  10. package/src/ai/llmcalls/parseLlmOputput.ts +69 -0
  11. package/src/ai/llmprompts/promptRegistry.ts +16 -0
  12. package/src/ai/llmprompts/systemPrompts/actionExtractorPrompt.ts +70 -0
  13. package/src/ai/llmprompts/systemPrompts/errorDescriptionPrompt.ts +23 -0
  14. package/src/ai/llmprompts/systemPrompts/fireflinkElementIndexExtactors.ts +198 -0
  15. package/src/ai/llmprompts/systemPrompts/userStoryToListPrompt.ts +24 -0
  16. package/src/ai/llmprompts/systemPrompts/visionPrompt.ts +28 -0
  17. package/src/ai/llmprompts/userPrompts/userPrompt.ts +41 -0
  18. package/src/automation/actions/executor.ts +75 -0
  19. package/src/automation/actions/interaction/click.ts +25 -0
  20. package/src/automation/actions/interaction/enterInput.ts +27 -0
  21. package/src/automation/actions/interface/interactionActionInterface.ts +27 -0
  22. package/src/automation/actions/interface/navigationActionInterface.ts +22 -0
  23. package/src/automation/actions/interface/waitActionInterface.ts +6 -0
  24. package/src/automation/actions/navigation/getTitle.ts +9 -0
  25. package/src/automation/actions/navigation/goBack.ts +9 -0
  26. package/src/automation/actions/navigation/navigate.ts +10 -0
  27. package/src/automation/actions/navigation/refresh.ts +9 -0
  28. package/src/automation/actions/wait/wait.ts +10 -0
  29. package/src/automation/browserSession/initiateBrowserSession.ts +81 -0
  30. package/src/core/constants/supportedActions.ts +8 -0
  31. package/src/core/interfaces/StableDomInterface.ts +6 -0
  32. package/src/core/interfaces/actionInterface.ts +13 -0
  33. package/src/core/interfaces/automationRunnerInterface.ts +3 -0
  34. package/src/core/interfaces/browserCapabilitiesInterface.ts +5 -0
  35. package/src/core/interfaces/browserConfigurationInterface.ts +3 -0
  36. package/src/core/interfaces/domAnalysisInterface.ts +34 -0
  37. package/src/core/interfaces/executionDetails.ts +29 -0
  38. package/src/core/interfaces/fireflinkScriptPayloadInterface.ts +39 -0
  39. package/src/core/interfaces/llmConfigurationInterface.ts +3 -0
  40. package/src/core/interfaces/llmResponseInterface.ts +38 -0
  41. package/src/core/interfaces/promptInterface.ts +21 -0
  42. package/src/core/interfaces/scriptGenrationDataInterface.ts +16 -0
  43. package/src/core/interfaces/toolsInterface.ts +5 -0
  44. package/src/core/main/actionHandlerFactory.ts +86 -0
  45. package/src/core/main/executionContext.ts +18 -0
  46. package/src/core/main/runAutomationScript.ts +177 -0
  47. package/src/core/main/stepProcessor.ts +28 -0
  48. package/src/core/types/llmResponseType.ts +11 -0
  49. package/src/core/types/promptMap.ts +7 -0
  50. package/src/core/types/promptType.ts +7 -0
  51. package/src/core/types/visionllmInputType.ts +4 -0
  52. package/src/domAnalysis/getRelaventElements.ts +24 -0
  53. package/src/domAnalysis/relativeElementsFromDom.ts +94 -0
  54. package/src/domAnalysis/searchBest.ts +159 -0
  55. package/src/domAnalysis/simplifyAndFlatten.ts +118 -0
  56. package/src/fireflinkData/fireflinkLocators/elementsFromHTML.ts +656 -0
  57. package/src/fireflinkData/fireflinkLocators/getListOfLocators.ts +31 -0
  58. package/src/fireflinkData/fireflinkLocators/typeList.ts +36 -0
  59. package/src/fireflinkData/fireflinkScript/scriptGenrationData.ts +30 -0
  60. package/src/index.ts +5 -0
  61. package/src/llmConfig/llmConfiguration.ts +26 -0
  62. package/src/service/fireflinkApi.service.ts +46 -0
  63. package/src/service/scriptRunner.service.ts +83 -0
  64. package/src/utils/DomExtraction/jsForAttributeInjection.ts +254 -0
  65. package/src/utils/javascript/jsFindElement.ts +161 -0
  66. package/src/utils/javascript/jsForShadowRoot.ts +216 -0
  67. package/src/utils/javascript/jsForToaster.ts +60 -0
  68. package/src/utils/logger/logData.ts +36 -0
  69. package/tsconfig.json +26 -0
@@ -0,0 +1,198 @@
1
+ type FFInspectorArgs = {
2
+ stepAction: string;
3
+ extractedDomJson: string;
4
+ priorAndNextSteps: string[];
5
+ isAlert?: boolean;
6
+ isDrag?: boolean;
7
+ };
8
+ export async function ffInspectorNumExtractor({
9
+ stepAction,
10
+ extractedDomJson,
11
+ priorAndNextSteps,
12
+ isAlert = false,
13
+ isDrag = false,
14
+ }: FFInspectorArgs
15
+ ): Promise<
16
+ string
17
+ > {
18
+ const clickActions = ["click", "doubleclick", "rightclick"];
19
+ const alertActions = [
20
+ "ClickOkOnAlertPopup",
21
+ "ClickCancelOnAlertPopup",
22
+ "EnterDataToAlert",
23
+ "GetTextPresentOnAlertPopup",
24
+ "VerifyAlertPopupIsDisplayed",
25
+ "VerifyAlertPopUpMessageContainsString",
26
+ "WaitTillAlertIsPresent",
27
+ "VerifyTextPresentOnAlertPopup"
28
+ ];
29
+ const elementType = ["button", "link"]
30
+
31
+ let prompt;
32
+
33
+ // ---------------- ALERT ----------------
34
+ if (isAlert) {
35
+ prompt = `
36
+ You are given a Selenium test step that requires interaction with a browser alert popup.
37
+
38
+ Rules:
39
+ - if the alert requires entering text or verification comparison, extract that text.
40
+ - If no input is needed, set "input_text" to "None".
41
+ - If step verifies text presence → VerifyTextPresentOnAlertPopup.
42
+ - If step verifies text contains → VerifyAlertPopUpMessageContainsString.
43
+ - Do not add explanations or extra text.
44
+ - Return ONE action from this list only: ${JSON.stringify(alertActions)}.
45
+ - Output must be valid JSON.
46
+ Respond only with JSON using this format:
47
+
48
+ {
49
+ "action": x,
50
+ "input_text": "text to enter" | "None"
51
+ }
52
+
53
+ `;
54
+ }
55
+
56
+ // ---------------- DRAG & DROP ----------------
57
+ else if (isDrag) {
58
+ prompt = `
59
+ You are an intelligent assistant that extracts structured UI action data.
60
+
61
+ Given a structured UI JSON representation with uniquely identified elements
62
+ (ff-inspect values like Fire-Flink-1, Fire-Flink-2... in DOM order),
63
+ locate the most appropriate elements for a drag-and-drop action.
64
+
65
+
66
+
67
+ Rules:
68
+ - Step: for the given step
69
+ - Use the simplified JSON to find elements.
70
+ - Identify source (drag) and destination (drop).
71
+ - If not found, return Fire-Flink-0 for both.
72
+ - Extract element names from step if possible.
73
+ - Respond with JSON only.
74
+ Simplified JSON:
75
+ ${extractedDomJson}
76
+
77
+ Respond only with JSON using this format:
78
+ {
79
+ "drag": "Fire-Flink-x",
80
+ "drop": "Fire-Flink-x",
81
+ "action": "Builtin_DragAndDropToElement",
82
+ "drag_element_name": "x",
83
+ "drop_element_name": "x"
84
+ }
85
+ `;
86
+ }
87
+
88
+ // ---------------- WAIT / SCROLL ----------------
89
+ else if (stepAction === "wait" || stepAction === "scroll") {
90
+ prompt = `
91
+ You are an intelligent assistant that extracts structured UI action data.
92
+
93
+
94
+
95
+ Rules:
96
+ - Step: for the given step
97
+ - Use context from test steps: ${JSON.stringify(priorAndNextSteps)}
98
+ - Use simplified JSON to find best FF-inspect match.
99
+ - Choose closest semantic + DOM-distance match.
100
+ - Default direction is down.
101
+ - Action:
102
+ - scroll → extract num_of_scrolls & direction
103
+ - wait → extract wait time (number only)
104
+ - No nulls; use empty strings if needed.
105
+ - The element type should be from this list ${elementType}
106
+
107
+ Simplified JSON:
108
+ ${extractedDomJson}
109
+
110
+ Return ONLY valid JSON:
111
+ {
112
+ "attribute_value": "Fire-Flink-x",
113
+ "action": "x",
114
+ "input_text": "seconds in Interger | input text",
115
+ "keyword": "x",
116
+ "num_of_scrolls": "0",
117
+ "direction": "down",
118
+ "elementType":"x"
119
+ }
120
+ `;
121
+ }
122
+
123
+ // ---------------- DEFAULT (CLICK / ENTER / UPLOAD etc.) ----------------
124
+ else {
125
+ prompt = `
126
+ You are a deterministic UI action extraction engine.
127
+
128
+ OBJECTIVE:
129
+ Identify the SINGLE best matching element from the Simplified JSON
130
+ for the given step and return structured automation data.
131
+
132
+ -----------------------------------------
133
+
134
+ CONTEXT STEPS:
135
+ ${JSON.stringify(priorAndNextSteps)}
136
+
137
+ CLICK ACTION WORDS:
138
+ ${JSON.stringify(clickActions)}
139
+
140
+ ALLOWED ELEMENT TYPES:
141
+ ${elementType}
142
+ -----------------------------------------
143
+
144
+ CRITICAL MATCHING LOGIC:
145
+
146
+ 1. First understand intent:
147
+ - click words → click
148
+ - enter/type/write → enter_text
149
+ - upload → upload
150
+ - drag_and_drop → drag_and_drop
151
+
152
+ 2. For ENTER actions:
153
+ DO NOT pick first input blindly.
154
+ Score candidates using priority:
155
+
156
+ Priority Order:
157
+ (1) Exact label text match
158
+ (2) Placeholder match
159
+ (3) Name attribute semantic match
160
+ (4) ID semantic match
161
+ (5) type="email" if step contains "email"
162
+ (6) DOM sibling label relationship
163
+
164
+ Choose highest scoring match.
165
+
166
+ If NO strong semantic match → return:
167
+ attribute_value = "Fire-Flink-0"
168
+
169
+ 3. For CLICK actions:
170
+ - Prefer exact text match
171
+ - If multiple, choose closest contextual match
172
+ - If icon + svg exists, prefer svg element
173
+
174
+ 4. Never hallucinate.
175
+ 5. Only use FF values from provided JSON.
176
+ 6. No null values. Use empty string "".
177
+ 7. Output must be valid JSON only.
178
+
179
+ -----------------------------------------
180
+ SIMPLIFIED JSON:
181
+ ${extractedDomJson}
182
+ -----------------------------------------
183
+
184
+ Respond ONLY with JSON:
185
+
186
+ {
187
+ "attribute_value": "Fire-Flink-x",
188
+ "action": "click | enter | upload | drag_and_drop",
189
+ "input_text": "",
190
+ "keyword": "",
191
+ "num_of_scrolls": "0",
192
+ "direction": "down",
193
+ "elementType": ""
194
+ }
195
+ `;
196
+ }
197
+ return prompt;
198
+ }
@@ -0,0 +1,24 @@
1
+
2
+ export async function buildStepExtractionPrompt(
3
+ ): Promise<string> {
4
+ const prompt = `
5
+ You are a structured automation assistant. Your task is to extract step data from a provided user story for web automation.
6
+
7
+ Requirements
8
+ Each step must be a single string (not a tuple or any other data type).
9
+ Preserve the original wording of each step.
10
+ You may rewrite for clarity or formatting consistency only.
11
+ Do not add new steps.
12
+ Do not remove any existing steps.
13
+ Do not introduce additional actions.
14
+ Do not include the example list in the response.
15
+ Do not include any extra text, commentary, markdown, or code fences.
16
+ Output Format
17
+
18
+ Respond strictly in valid JSON using the following structure:
19
+ {
20
+ "manaulSteps": ["step 1", "step 2", "step 3"]
21
+ }
22
+ `;
23
+ return prompt;
24
+ }
@@ -0,0 +1,28 @@
1
+
2
+ type visionPrompt = {
3
+ currentStep: string,
4
+ priorAndNextSteps: string[]
5
+ }
6
+ export async function visionPrompt(
7
+ { currentStep, priorAndNextSteps }: visionPrompt
8
+ ): Promise<string> {
9
+
10
+ const customPromptText = `
11
+ You are a precise automation assistant.
12
+ Context: ${priorAndNextSteps}
13
+ - Use the context to understand the step and select the closest semantic match to ${currentStep} and return only its index, else Fire-Flink-0.
14
+ - **If u can't find the element, return Fire-Flink-0. dont return any other elements index.**
15
+ - Using the provided annotated screenshot and ${currentStep}, identify the correct element index from the image.
16
+ - Match the index to the text or action described in ${currentStep} as accurately as possible.
17
+ - Return only the Fire-Flink-xx for the target element.
18
+ - Do not provide any additional text or explanation. The output must be strictly Fire-Flink-xx.
19
+ Now, Analyze the step:
20
+ Step: "${currentStep}"
21
+
22
+ Respond only with JSON using this format:
23
+ {fireflinkIndex: Fire-Flink-xx.}
24
+
25
+ `.trim();
26
+
27
+ return customPromptText;
28
+ }
@@ -0,0 +1,41 @@
1
+ import { PromptType } from "../../../core/types/promptType.js";
2
+ import { visionPromptMessage } from "../../../core/types/visionllmInputType.js";
3
+
4
+ export const userInputFormatters: {
5
+ [K in PromptType]: (
6
+ userInput: Record<string, any>
7
+ ) => string | visionPromptMessage;
8
+ } = {
9
+ [PromptType.USER_STORY_TO_LIST]: (userInput) =>
10
+ `Convert the following user story into steps:\n\n${JSON.stringify(userInput.userStory, null, 2)}`,
11
+
12
+ [PromptType.KEYWORD_EXTRACTOR]: (userInput) =>
13
+ `Extract keywords from the following input:\n\n${JSON.stringify(userInput.currentStep, null, 2)}`,
14
+
15
+ [PromptType.ERROR_DESCRIPTION]: (userInput) =>
16
+ `Analyze the following error context:\n\n${JSON.stringify(userInput.error, null, 2)}`,
17
+
18
+ [PromptType.FF_INSPECTOR]: (userInput) =>
19
+ `Inspect the DOM for the following action context:\n\n${JSON.stringify(userInput.currentStep, null, 2)}`,
20
+
21
+ [PromptType.VISION_PROMPT]: (userInput) => {
22
+ const content: visionPromptMessage = [
23
+ {
24
+ type: "text",
25
+ text: `Analyze the following step:\n\n${JSON.stringify(
26
+ userInput.currentStep,
27
+ null,
28
+ 2
29
+ )}`
30
+ },
31
+ {
32
+ type: "image_url",
33
+ image_url: {
34
+ url: String(userInput.imageBase64 ?? "")
35
+ }
36
+ }
37
+ ];
38
+ return content;
39
+ }
40
+
41
+ };
@@ -0,0 +1,75 @@
1
+ import type { IActionExecutor } from "../../core/interfaces/actionInterface.js";
2
+ import { navigate } from './navigation/navigate.js';
3
+ import { goBack } from './navigation/goBack.js';
4
+ import { pageRefresh } from './navigation/refresh.js';
5
+ import { click } from './interaction/click.js';
6
+ import { wait } from "./wait/wait.js"
7
+ import { enterInput } from "./interaction/enterInput.js";
8
+ import { ScriptDataAppender } from "../../fireflinkData/fireflinkScript/scriptGenrationData.js";
9
+ import { ElementGetter } from "../../fireflinkData/fireflinkLocators/getListOfLocators.js";
10
+ export class ActionExecutor implements IActionExecutor {
11
+ constructor(private readonly browser: WebdriverIO.Browser,
12
+ private scriptDataAppender: ScriptDataAppender,
13
+ private elementGetter: ElementGetter,
14
+ private platform: string) { }
15
+
16
+
17
+
18
+ async navigate(url: string): Promise<void> {
19
+ await navigate({
20
+ browser: this.browser,
21
+ url,
22
+ scriptDataAppender: this.scriptDataAppender
23
+ });
24
+ }
25
+
26
+ async goBack(): Promise<void> {
27
+ await goBack({
28
+ browser: this.browser,
29
+ scriptDataAppender: this.scriptDataAppender
30
+ });
31
+ }
32
+
33
+ async refresh(): Promise<void> {
34
+ await pageRefresh({
35
+ browser: this.browser,
36
+ scriptDataAppender: this.scriptDataAppender
37
+ });
38
+ }
39
+
40
+
41
+ async wait(time: string): Promise<void> {
42
+ await wait({
43
+ browser: this.browser,
44
+ time,
45
+ scriptDataAppender: this.scriptDataAppender
46
+ });
47
+ }
48
+ async click(pageDOM: string, selector: string, fireflinkIndex: string, elementName: string, elementType: string): Promise<void> {
49
+ await click({
50
+ browser: this.browser,
51
+ selector,
52
+ scriptDataAppender: this.scriptDataAppender,
53
+ elementGetter: this.elementGetter,
54
+ fireflinkIndex,
55
+ pageDOM,
56
+ elementName,
57
+ elementType,
58
+ platform: this.platform
59
+ });
60
+ }
61
+ async enterInput(selector: string, value: string, fireflinkIndex: string, pageDOM: string, elementName: string, elementType: string): Promise<void> {
62
+ await enterInput({
63
+ browser: this.browser,
64
+ selector: selector,
65
+ value,
66
+ scriptDataAppender: this.scriptDataAppender,
67
+ elementGetter: this.elementGetter,
68
+ fireflinkIndex,
69
+ pageDOM,
70
+ elementName,
71
+ elementType,
72
+ platform: this.platform
73
+ });
74
+ }
75
+ }
@@ -0,0 +1,25 @@
1
+ import { ClickInterface } from "../interface/interactionActionInterface.js";
2
+ export async function click(args: ClickInterface): Promise<void> {
3
+ try {
4
+ const element = await args.browser.$(args.selector);
5
+ await element.scrollIntoView({ block: 'center', inline: 'center' });
6
+ await element.click();
7
+ const ffElement: any = await args.elementGetter.getFireFlinkElement(
8
+ args.pageDOM,
9
+ `[ff-inspect="${args.fireflinkIndex}"]`
10
+ );
11
+ args.scriptDataAppender.add(
12
+ {
13
+ nlpName: 'Click',
14
+ stepInputs: [],
15
+ elementsData: [{
16
+ elementName: args.elementName,
17
+ type: args.elementType,
18
+ locators: ffElement.locators,
19
+ platform: args.platform
20
+ }]
21
+ });
22
+ } catch (error: any) {
23
+ throw new Error("Click action failed", { cause: error });
24
+ }
25
+ }
@@ -0,0 +1,27 @@
1
+ import { EnterInputInterface } from "../interface/interactionActionInterface.js";
2
+ export async function enterInput(args: EnterInputInterface): Promise<void> {
3
+ try {
4
+ const element = args.browser.$(args.selector);
5
+ await element.scrollIntoView({ block: 'center', inline: 'center' });
6
+ await element.setValue(args.value);
7
+ const ffElement: any = await args.elementGetter.getFireFlinkElement(
8
+ args.pageDOM,
9
+ `[ff-inspect="${args.fireflinkIndex}"]`
10
+ );
11
+ args.scriptDataAppender.add({
12
+ nlpName: 'SendKeys',
13
+ stepInputs: [args.value],
14
+ elementsData: [{
15
+ elementName: args.elementName,
16
+ type: args.elementType,
17
+ locators: ffElement.locators,
18
+ platform: args.platform
19
+ }]
20
+ });
21
+
22
+ }
23
+ catch (error: any) {
24
+ throw new Error("enter action failed", { cause: error });
25
+ }
26
+
27
+ }
@@ -0,0 +1,27 @@
1
+ import { ScriptDataAppender } from "../../../fireflinkData/fireflinkScript/scriptGenrationData.js";
2
+ import { ElementGetter } from "../../../fireflinkData/fireflinkLocators/getListOfLocators.js";
3
+ export interface ClickInterface {
4
+ browser: WebdriverIO.Browser;
5
+ selector: string;
6
+ scriptDataAppender: ScriptDataAppender;
7
+ elementGetter: ElementGetter;
8
+ fireflinkIndex: string;
9
+ pageDOM: string;
10
+ elementName: string;
11
+ elementType: any;
12
+ platform: string;
13
+ }
14
+
15
+
16
+ export interface EnterInputInterface {
17
+ browser: WebdriverIO.Browser;
18
+ selector: string;
19
+ value: string;
20
+ scriptDataAppender: ScriptDataAppender;
21
+ elementGetter: ElementGetter;
22
+ fireflinkIndex: string;
23
+ pageDOM: string;
24
+ elementName: string;
25
+ elementType: any;
26
+ platform: string;
27
+ }
@@ -0,0 +1,22 @@
1
+ import { ScriptDataAppender } from "../../../fireflinkData/fireflinkScript/scriptGenrationData.js";
2
+
3
+ export interface getTitleInterface {
4
+ browser: WebdriverIO.Browser;
5
+ scriptDataAppender: ScriptDataAppender;
6
+ }
7
+
8
+ export interface goBackInterface {
9
+ browser: WebdriverIO.Browser;
10
+ scriptDataAppender: ScriptDataAppender;
11
+ }
12
+
13
+ export interface navigateToUrlInterface {
14
+ browser: WebdriverIO.Browser;
15
+ scriptDataAppender: ScriptDataAppender;
16
+ url: string;
17
+ }
18
+
19
+ export interface refreshInterface {
20
+ browser: WebdriverIO.Browser;
21
+ scriptDataAppender: ScriptDataAppender;
22
+ }
@@ -0,0 +1,6 @@
1
+ import { ScriptDataAppender } from "../../../fireflinkData/fireflinkScript/scriptGenrationData.js";
2
+ export interface waitInterface {
3
+ browser: WebdriverIO.Browser;
4
+ scriptDataAppender: ScriptDataAppender;
5
+ time: string;
6
+ }
@@ -0,0 +1,9 @@
1
+ import { getTitleInterface } from "../interface/navigationActionInterface.js";
2
+ export async function getTitle(args: getTitleInterface): Promise<void> {
3
+ try {
4
+ const title = await args.browser.getTitle();
5
+ args.scriptDataAppender.add({ nlpName: 'getTitle', elementsData: [], stepInputs: [title] });
6
+ } catch (error: any) {
7
+ throw new Error("Get title action failed", { cause: error });
8
+ }
9
+ }
@@ -0,0 +1,9 @@
1
+ import { goBackInterface } from "../interface/navigationActionInterface.js";
2
+ export async function goBack(args: goBackInterface): Promise<void> {
3
+ try {
4
+ await args.browser.back();
5
+ args.scriptDataAppender.add({ nlpName: 'goBack', elementsData: [], stepInputs: [] });
6
+ } catch (error: any) {
7
+ throw new Error("Navigate action failed", { cause: error });
8
+ }
9
+ }
@@ -0,0 +1,10 @@
1
+ import { navigateToUrlInterface } from "../interface/navigationActionInterface.js";
2
+ export async function navigate(args: navigateToUrlInterface): Promise<void> {
3
+ try {
4
+ await args.browser.url(args.url);
5
+ args.scriptDataAppender.add({ nlpName: 'NavigateToURL', elementsData: [], stepInputs: [args.url] });
6
+
7
+ } catch (error: any) {
8
+ throw new Error("Navigate action failed", { cause: error });
9
+ }
10
+ }
@@ -0,0 +1,9 @@
1
+ import { refreshInterface } from "../interface/navigationActionInterface.js";
2
+ export async function pageRefresh(args: refreshInterface): Promise<void> {
3
+ try {
4
+ await args.browser.refresh();
5
+ args.scriptDataAppender.add({ nlpName: 'refresh', elementsData: [], stepInputs: [] });
6
+ } catch (error: any) {
7
+ throw new Error("Refresh action failed", { cause: error });
8
+ }
9
+ }
@@ -0,0 +1,10 @@
1
+ import { waitInterface } from "../interface/waitActionInterface.js";
2
+ export async function wait(args: waitInterface): Promise<void> {
3
+ try {
4
+ await args.browser.pause(Number(args.time) * 1000);
5
+ args.scriptDataAppender.add({ nlpName: 'Sleep', elementsData: [], stepInputs: [args.time] });
6
+
7
+ } catch (error: any) {
8
+ throw new Error("Navigate action failed", { cause: error });
9
+ }
10
+ }
@@ -0,0 +1,81 @@
1
+ import { remote } from "webdriverio";
2
+ import { browserCapabilities } from "../../core/interfaces/browserCapabilitiesInterface.js";
3
+
4
+ export class BrowserSession {
5
+ private browser: WebdriverIO.Browser | null = null;
6
+
7
+ private async openBrowser(capabilities: browserCapabilities): Promise<WebdriverIO.Browser> {
8
+ try {
9
+ const browser = await remote(
10
+ {
11
+ capabilities: {
12
+ browserName: capabilities.browserName,
13
+ },
14
+ logLevel: "silent"
15
+ }
16
+ );
17
+ browser.setTimeout({ 'pageLoad': capabilities.pageLoad, 'implicit': capabilities.implicit });
18
+ await browser.waitUntil(async () => {
19
+ const state = await browser.execute(() => document.readyState);
20
+ return state === "complete";
21
+ });
22
+
23
+ return browser;
24
+ } catch (error: any) {
25
+ throw new Error("Browser failed to open", { cause: error });
26
+ }
27
+ }
28
+
29
+
30
+ async open(capabilities: browserCapabilities): Promise<void> {
31
+ this.browser = await this.openBrowser(capabilities);
32
+
33
+ }
34
+
35
+ async close(): Promise<void> {
36
+ if (this.browser) {
37
+ await this.browser.deleteSession();
38
+ this.browser = null;
39
+ }
40
+ }
41
+
42
+ async getCurrentBrowser(): Promise<WebdriverIO.Browser> {
43
+ if (!this.browser) {
44
+ throw new Error("Browser is not initialized");
45
+ }
46
+ return this.browser;
47
+ }
48
+
49
+
50
+ async waitForStableDOM(timeout = 10000): Promise<void> {
51
+ if (!this.browser) throw new Error("Browser session not found");
52
+
53
+ let lastHTML = "";
54
+ let stableCount = 0;
55
+
56
+ try {
57
+ await this.browser.waitUntil(async () => {
58
+ if (!this.browser) return;
59
+ const currentHTML = await this.browser.execute(() =>
60
+ document.documentElement.outerHTML
61
+ );
62
+ if (currentHTML === lastHTML) {
63
+ stableCount++;
64
+ } else {
65
+ stableCount = 0;
66
+ }
67
+
68
+ lastHTML = currentHTML;
69
+
70
+ return stableCount >= 3;
71
+ }, {
72
+ timeout,
73
+ interval: 500
74
+ });
75
+ } catch {
76
+ return;
77
+ }
78
+ }
79
+
80
+
81
+ }
@@ -0,0 +1,8 @@
1
+ export const INPUTLESS_ACTIONS = [
2
+ "open",
3
+ "goBack",
4
+ "refresh",
5
+ "navigate"
6
+ ];
7
+
8
+ export const ELEMENTLESS_ACTION = ["wait"]
@@ -0,0 +1,6 @@
1
+ export interface StableDOM {
2
+ browser: WebdriverIO.Browser | null,
3
+ timeout: number,
4
+ idleMs: number
5
+
6
+ }
@@ -0,0 +1,13 @@
1
+
2
+
3
+ // Main action executor interface
4
+ export interface IActionExecutor {
5
+ navigate(url: string): Promise<void>;
6
+ goBack(): Promise<void>;
7
+ refresh(): Promise<void>;
8
+ wait(time: string): Promise<void>;
9
+ click(pageDOM: string, selector: string, fireflinkIndex: string, elementName: string, elementType: string): Promise<void>;
10
+ enterInput(selector: string, value: string, fireflinkIndex: string, pageDOM: string, elementName: string, elementType: string, platform: string): Promise<void>;
11
+ }
12
+
13
+
@@ -0,0 +1,3 @@
1
+ export interface IAutomationRunner {
2
+ run(): Promise<void>;
3
+ }
@@ -0,0 +1,5 @@
1
+ export interface browserCapabilities {
2
+ browserName: string;
3
+ pageLoad: number;
4
+ implicit: number;
5
+ }
@@ -0,0 +1,3 @@
1
+ export interface BrowserConfig {
2
+ browserName: string;
3
+ }