automation_model 1.0.581-dev → 1.0.581-stage

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.
@@ -0,0 +1,116 @@
1
+ export async function findHighestWithSameInnerText(cssSelector, scope, web) {
2
+ await web._highlightElements(scope, cssSelector);
3
+ const element = await scope.locator(cssSelector).first();
4
+ if (!element) {
5
+ throw new Error("header element not found");
6
+ }
7
+ const innerText = await element.innerText();
8
+ // climb to the parent element until the innerText is changing, get the top element with the same innerText
9
+ let climb = 0;
10
+ let topElement = element;
11
+ let elementCss = cssSelector;
12
+ while (true) {
13
+ climb++;
14
+ // create a climb xpath: 1: .. 2: ../.. etc.
15
+ const climbXpath = "xpath=" + "../".repeat(climb).slice(0, -1);
16
+ const climbCss = elementCss + " >> " + climbXpath;
17
+ const climbElement = await scope.locator(climbCss).first();
18
+ if (!climbElement) {
19
+ break;
20
+ }
21
+ const climbInnerText = await climbElement.innerText();
22
+ if (climbInnerText !== innerText) {
23
+ break;
24
+ }
25
+ topElement = climbElement;
26
+ elementCss = climbCss;
27
+ }
28
+ return { element: topElement, cssSelector: elementCss, climb: climb, innerText: innerText };
29
+ }
30
+ export async function findCellRectangle(headerResult, rowResult, web, info) {
31
+ await web.scrollIfNeeded(rowResult.element, info);
32
+ // find the header cell and the row cell location
33
+ const headerRect = await headerResult.element.boundingBox();
34
+ const rowRect = await rowResult.element.boundingBox();
35
+ if (!headerRect || !rowRect) {
36
+ throw new Error("element not found");
37
+ }
38
+ // found there rectengle of cell that is in the header horizontal and the row vertical
39
+ return {
40
+ x: headerRect.x,
41
+ y: rowRect.y,
42
+ width: headerRect.width,
43
+ height: rowRect.height,
44
+ };
45
+ }
46
+ export async function _findCellArea(headerText, rowText, web, state) {
47
+ const headerFoundElements = await web.findTextInAllFrames({}, {}, headerText, state);
48
+ if (headerFoundElements.length === 0) {
49
+ throw new Error("header not found");
50
+ }
51
+ if (headerFoundElements.length > 1) {
52
+ throw new Error("multiple headers found");
53
+ }
54
+ const rowFoundElements = await web.findTextInAllFrames({}, {}, rowText, state);
55
+ if (rowFoundElements.length === 0) {
56
+ throw new Error("row not found");
57
+ }
58
+ if (rowFoundElements.length > 1) {
59
+ throw new Error("multiple rows found");
60
+ }
61
+ const headerScope = headerFoundElements[0].frame;
62
+ const headerResult = await findHighestWithSameInnerText(`[data-blinq-id-${headerFoundElements[0].randomToken}]`, headerScope, web);
63
+ const rowScope = rowFoundElements[0].frame;
64
+ const rowResult = await findHighestWithSameInnerText(`[data-blinq-id-${rowFoundElements[0].randomToken}]`, rowScope, web);
65
+ return await findCellRectangle(headerResult, rowResult, web, state.info);
66
+ }
67
+ export async function findElementsInArea(cssSelector, area, web, options) {
68
+ if (!cssSelector) {
69
+ cssSelector = "*";
70
+ }
71
+ const frames = await web.page.frames();
72
+ const elements = [];
73
+ for (const scope of frames) {
74
+ const count = await scope.locator(cssSelector).count();
75
+ for (let i = 0; i < count; i++) {
76
+ const element = await scope.locator(cssSelector).nth(i);
77
+ elements.push(element);
78
+ }
79
+ }
80
+ const foundElements = [];
81
+ let hTollarance = 10;
82
+ let vTollarance = 10;
83
+ if (options && options.hTollarance && options.vTollarance) {
84
+ hTollarance = options.hTollarance;
85
+ vTollarance = options.vTollarance;
86
+ }
87
+ for (const element of elements) {
88
+ const rect = await element.boundingBox();
89
+ if (!rect) {
90
+ continue;
91
+ }
92
+ if (rect.x >= area.x - hTollarance &&
93
+ rect.x + rect.width <= area.x + area.width + hTollarance &&
94
+ rect.y >= area.y - vTollarance &&
95
+ rect.y + rect.height <= area.y + area.height + vTollarance) {
96
+ foundElements.push(element);
97
+ }
98
+ }
99
+ if (foundElements.length === 0) {
100
+ // find elements that intersect with the area
101
+ for (const element of elements) {
102
+ const rect = await element.boundingBox();
103
+ if (!rect) {
104
+ continue;
105
+ }
106
+ if (rect.x + rect.width >= area.x &&
107
+ rect.x <= area.x + area.width &&
108
+ rect.y + rect.height >= area.y &&
109
+ rect.y <= area.y + area.height) {
110
+ foundElements.push(element);
111
+ }
112
+ }
113
+ }
114
+ return foundElements;
115
+ }
116
+ //# sourceMappingURL=table_helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table_helper.js","sourceRoot":"","sources":["../../src/table_helper.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,WAAmB,EAAE,KAAU,EAAE,GAAQ;IAC1F,MAAM,GAAG,CAAC,kBAAkB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,CAAC;IACzD,IAAI,CAAC,OAAO,EAAE;QACZ,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;KAC7C;IACD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;IAC5C,2GAA2G;IAC3G,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,UAAU,GAAG,OAAO,CAAC;IACzB,IAAI,UAAU,GAAG,WAAW,CAAC;IAC7B,OAAO,IAAI,EAAE;QACX,KAAK,EAAE,CAAC;QACR,4CAA4C;QAC5C,MAAM,UAAU,GAAG,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;QAClD,MAAM,YAAY,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;QAC3D,IAAI,CAAC,YAAY,EAAE;YACjB,MAAM;SACP;QACD,MAAM,cAAc,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,CAAC;QACtD,IAAI,cAAc,KAAK,SAAS,EAAE;YAChC,MAAM;SACP;QACD,UAAU,GAAG,YAAY,CAAC;QAC1B,UAAU,GAAG,QAAQ,CAAC;KACvB;IACD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC9F,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAAiB,EAAE,SAAc,EAAE,GAAQ,EAAE,IAAS;IAC5F,MAAM,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClD,iDAAiD;IACjD,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAC5D,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACtD,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,EAAE;QAC3B,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;KACtC;IACD,sFAAsF;IACtF,OAAO;QACL,CAAC,EAAE,UAAU,CAAC,CAAC;QACf,CAAC,EAAE,OAAO,CAAC,CAAC;QACZ,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC;AACJ,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAkB,EAAE,OAAe,EAAE,GAAQ,EAAE,KAAU;IAC3F,MAAM,mBAAmB,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;IACrF,IAAI,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE;QACpC,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;KACrC;IACD,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE;QAClC,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;KAC3C;IACD,MAAM,gBAAgB,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/E,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE;QACjC,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;KAClC;IACD,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;QAC/B,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;KACxC;IACD,MAAM,WAAW,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACjD,MAAM,YAAY,GAAG,MAAM,4BAA4B,CACrD,kBAAkB,mBAAmB,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,EACvD,WAAW,EACX,GAAG,CACJ,CAAC;IACF,MAAM,QAAQ,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC3C,MAAM,SAAS,GAAG,MAAM,4BAA4B,CAClD,kBAAkB,gBAAgB,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,EACpD,QAAQ,EACR,GAAG,CACJ,CAAC;IACF,OAAO,MAAM,iBAAiB,CAAC,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;AAC3E,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,WAAmB,EAAE,IAAS,EAAE,GAAQ,EAAE,OAAY;IAC7F,IAAI,CAAC,WAAW,EAAE;QAChB,WAAW,GAAG,GAAG,CAAC;KACnB;IACD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,EAAE,CAAC;IACpB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;QAC1B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,CAAC;QACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;YAC9B,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACxD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SACxB;KACF;IACD,MAAM,aAAa,GAAG,EAAE,CAAC;IACzB,IAAI,WAAW,GAAG,EAAE,CAAC;IACrB,IAAI,WAAW,GAAG,EAAE,CAAC;IACrB,IAAI,OAAO,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE;QACzD,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QAClC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;KACnC;IACD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;QAC9B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI,EAAE;YACT,SAAS;SACV;QACD,IACE,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,WAAW;YAC9B,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,GAAG,WAAW;YACxD,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,WAAW;YAC9B,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,WAAW,EAC1D;YACA,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SAC7B;KACF;IACD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;QAC9B,6CAA6C;QAC7C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;YAC9B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;YACzC,IAAI,CAAC,IAAI,EAAE;gBACT,SAAS;aACV;YACD,IACE,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;gBAC7B,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK;gBAC7B,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC;gBAC9B,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAC9B;gBACA,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;aAC7B;SACF;KACF;IACD,OAAO,aAAa,CAAC;AACvB,CAAC"}
@@ -2,8 +2,10 @@ import { BrowserContext, Page, Browser as PlaywrightBrowser } from "playwright";
2
2
  import { Environment } from "./environment.js";
3
3
  import { StableBrowser } from "./stable_browser.js";
4
4
  import { Api } from "./api.js";
5
+ import { InitScripts } from "./generation_scripts.js";
5
6
  declare class TestContext {
6
7
  stable: StableBrowser | null;
8
+ web: StableBrowser | null;
7
9
  browser: PlaywrightBrowser | null;
8
10
  playContext: BrowserContext | null;
9
11
  page: Page | null;
@@ -14,6 +16,7 @@ declare class TestContext {
14
16
  headless: boolean;
15
17
  browserName: string | null;
16
18
  browserObject: any;
19
+ initScripts: InitScripts | null;
17
20
  constructor();
18
21
  }
19
22
  export { TestContext };
@@ -1,5 +1,6 @@
1
1
  class TestContext {
2
2
  stable = null;
3
+ web = null;
3
4
  browser = null;
4
5
  playContext = null;
5
6
  page = null;
@@ -10,6 +11,7 @@ class TestContext {
10
11
  headless = false;
11
12
  browserName = null;
12
13
  browserObject = null;
14
+ initScripts = null;
13
15
  constructor() { }
14
16
  }
15
17
  export { TestContext };
@@ -1 +1 @@
1
- {"version":3,"file":"test_context.js","sourceRoot":"","sources":["../../src/test_context.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW;IACf,MAAM,GAAyB,IAAI,CAAC;IACpC,OAAO,GAA6B,IAAI,CAAC;IACzC,WAAW,GAA0B,IAAI,CAAC;IAC1C,IAAI,GAAgB,IAAI,CAAC;IACzB,WAAW,GAAuB,IAAI,CAAC;IACvC,YAAY,GAAkB,IAAI,CAAC;IACnC,GAAG,GAAe,IAAI,CAAC;IACvB,QAAQ,GAAG,KAAK,CAAC;IACjB,QAAQ,GAAG,KAAK,CAAC;IACjB,WAAW,GAAkB,IAAI,CAAC;IAClC,aAAa,GAAQ,IAAI,CAAC;IAC1B,gBAAe,CAAC;CACjB;AACD,OAAO,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"test_context.js","sourceRoot":"","sources":["../../src/test_context.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW;IACf,MAAM,GAAyB,IAAI,CAAC;IACpC,GAAG,GAAyB,IAAI,CAAC;IACjC,OAAO,GAA6B,IAAI,CAAC;IACzC,WAAW,GAA0B,IAAI,CAAC;IAC1C,IAAI,GAAgB,IAAI,CAAC;IACzB,WAAW,GAAuB,IAAI,CAAC;IACvC,YAAY,GAAkB,IAAI,CAAC;IACnC,GAAG,GAAe,IAAI,CAAC;IACvB,QAAQ,GAAG,KAAK,CAAC;IACjB,QAAQ,GAAG,KAAK,CAAC;IACjB,WAAW,GAAkB,IAAI,CAAC;IAClC,aAAa,GAAQ,IAAI,CAAC;IAC1B,WAAW,GAAuB,IAAI,CAAC;IACvC,gBAAe,CAAC;CACjB;AACD,OAAO,EAAE,WAAW,EAAE,CAAC"}
package/lib/utils.d.ts CHANGED
@@ -1,7 +1,10 @@
1
1
  declare function encrypt(text: string, key?: string | null): string;
2
- declare function decrypt(encryptedText: string, key?: string | null, totpWait?: boolean): Promise<string>;
2
+ declare function getTestDataValue(key: string, environment?: string): any;
3
+ declare function decrypt(encryptedText: string, key?: string | null, totpWait?: boolean): string;
4
+ export declare function testForRegex(text: string): boolean;
3
5
  declare function _convertToRegexQuery(text: string, isRegex: boolean, fullMatch: boolean, ignoreCase: boolean): string;
4
- declare function replaceWithLocalTestData(value: string, world: any, _decrypt?: boolean, totpWait?: boolean, context?: any, stable?: any): Promise<string>;
6
+ declare function _getDataFile(world?: any, context?: any, web?: any): string;
7
+ declare function replaceWithLocalTestData(value: string, world: any, _decrypt?: boolean, totpWait?: boolean, context?: any, web?: any): Promise<string>;
5
8
  declare function maskValue(value: string): string;
6
9
  declare function _copyContext(from: any, to: any): void;
7
10
  declare function scrollPageToLoadLazyElements(page: any): Promise<void>;
@@ -11,7 +14,10 @@ declare function getWebLogFile(logFolder: string): string;
11
14
  declare function _fixLocatorUsingParams(locator: any, _params: Params): any;
12
15
  declare function _isObject(value: any): any;
13
16
  declare function scanAndManipulate(currentObj: any, _params: Params): void;
17
+ declare function extractStepExampleParameters(step: any): any;
18
+ export declare function performAction(action: string, element: any, options: any, web: any, state: any, _params: Params): Promise<void>;
14
19
  declare const KEYBOARD_EVENTS: string[];
15
20
  declare function unEscapeString(str: string): string;
16
21
  declare function _getServerUrl(): string;
17
- export { encrypt, decrypt, replaceWithLocalTestData, maskValue, _copyContext, scrollPageToLoadLazyElements, _fixUsingParams, getWebLogFile, _fixLocatorUsingParams, _isObject, scanAndManipulate, KEYBOARD_EVENTS, unEscapeString, Params, _getServerUrl, _convertToRegexQuery, };
22
+ declare function tryParseJson(input: any): any;
23
+ export { encrypt, decrypt, replaceWithLocalTestData, maskValue, _copyContext, scrollPageToLoadLazyElements, _fixUsingParams, getWebLogFile, _fixLocatorUsingParams, _isObject, scanAndManipulate, KEYBOARD_EVENTS, unEscapeString, Params, _getServerUrl, _convertToRegexQuery, extractStepExampleParameters, _getDataFile, tryParseJson, getTestDataValue, };
package/lib/utils.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import CryptoJS from "crypto-js";
2
- import objectPath from "object-path";
3
2
  import path from "path";
4
3
  import { TOTP } from "totp-generator";
5
4
  import fs from "fs";
5
+ import axios from "axios";
6
+ import objectPath from "object-path";
6
7
  // Function to encrypt a string
7
8
  function encrypt(text, key = null) {
8
9
  if (!key) {
@@ -10,8 +11,25 @@ function encrypt(text, key = null) {
10
11
  }
11
12
  return CryptoJS.AES.encrypt(text, key).toString();
12
13
  }
14
+ function getTestDataValue(key, environment = "*") {
15
+ const blinqEnvPath = "data/data.json";
16
+ const envPath = path.resolve(process.cwd(), blinqEnvPath);
17
+ const envJson = JSON.parse(fs.readFileSync(envPath, "utf-8"));
18
+ const dataArray = envJson[environment];
19
+ const item = dataArray.find((item) => item.key === key);
20
+ if (!item) {
21
+ throw new Error(`Key ${key} not found in data.json`);
22
+ }
23
+ if (item.DataType === "string") {
24
+ return item.value;
25
+ }
26
+ else if (item.DataType === "secret" || item.DataType === "totp") {
27
+ return decrypt(item.value, null, false);
28
+ }
29
+ throw new Error(`Unsupported data type for key ${key}`);
30
+ }
13
31
  // Function to decrypt a string
14
- async function decrypt(encryptedText, key = null, totpWait = true) {
32
+ function decrypt(encryptedText, key = null, totpWait = true) {
15
33
  if (!key) {
16
34
  key = _findKey();
17
35
  }
@@ -23,13 +41,13 @@ async function decrypt(encryptedText, key = null, totpWait = true) {
23
41
  const bytes = CryptoJS.AES.decrypt(encryptedText, key);
24
42
  encryptedText = bytes.toString(CryptoJS.enc.Utf8);
25
43
  let { otp, expires } = TOTP.generate(encryptedText);
26
- if (totpWait) {
27
- // expires is in unix time, check if we have at least 10 seconds left, if it's less than wait for the expires time
28
- if (expires - Date.now() < 10000) {
29
- await new Promise((resolve) => setTimeout(resolve, (expires - Date.now() + 1000) % 30000));
30
- ({ otp, expires } = TOTP.generate(encryptedText));
31
- }
32
- }
44
+ // if (totpWait) {
45
+ // // expires is in unix time, check if we have at least 10 seconds left, if it's less than wait for the expires time
46
+ // if (expires - Date.now() < 10000) {
47
+ // await new Promise((resolve) => setTimeout(resolve, (expires - Date.now() + 1000) % 30000));
48
+ // ({ otp, expires } = TOTP.generate(encryptedText));
49
+ // }
50
+ // }
33
51
  return otp;
34
52
  }
35
53
  if (encryptedText.startsWith("mask:")) {
@@ -38,6 +56,22 @@ async function decrypt(encryptedText, key = null, totpWait = true) {
38
56
  const bytes = CryptoJS.AES.decrypt(encryptedText, key);
39
57
  return bytes.toString(CryptoJS.enc.Utf8);
40
58
  }
59
+ export function testForRegex(text) {
60
+ const regexEndPattern = /\/([gimuy]*)$/;
61
+ if (text.startsWith("/")) {
62
+ const match = regexEndPattern.test(text);
63
+ if (match) {
64
+ try {
65
+ const regex = new RegExp(text.substring(1, text.lastIndexOf("/")), text.match(regexEndPattern)[1]);
66
+ return true;
67
+ }
68
+ catch {
69
+ // not regex
70
+ }
71
+ }
72
+ }
73
+ return false;
74
+ }
41
75
  function _convertToRegexQuery(text, isRegex, fullMatch, ignoreCase) {
42
76
  let query = "internal:text=/";
43
77
  let queryEnd = "/";
@@ -48,6 +82,7 @@ function _convertToRegexQuery(text, isRegex, fullMatch, ignoreCase) {
48
82
  if (match) {
49
83
  try {
50
84
  const regex = new RegExp(text.substring(1, text.lastIndexOf("/")), text.match(regexEndPattern)[1]);
85
+ text = text.replace(/"/g, '\\"');
51
86
  return "internal:text=" + text;
52
87
  }
53
88
  catch {
@@ -66,15 +101,40 @@ function _convertToRegexQuery(text, isRegex, fullMatch, ignoreCase) {
66
101
  pattern = parts.join("\\s*");
67
102
  }
68
103
  if (fullMatch) {
69
- pattern = "^" + pattern + "$";
104
+ pattern = "^\\s*" + pattern + "\\s*$";
70
105
  }
71
106
  if (ignoreCase) {
72
107
  queryEnd += "i";
73
108
  }
74
109
  return query + pattern + queryEnd;
75
110
  }
76
- function escapeRegex(s) {
77
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
111
+ function escapeRegex(str) {
112
+ // Special regex characters that need to be escaped
113
+ const specialChars = [
114
+ "/",
115
+ ".",
116
+ "*",
117
+ "+",
118
+ "?",
119
+ "^",
120
+ "$",
121
+ "(",
122
+ ")",
123
+ "[",
124
+ "]",
125
+ "{",
126
+ "}",
127
+ "|",
128
+ "\\",
129
+ "-",
130
+ "'",
131
+ '"',
132
+ ">", // added to avoid confusion with pw selectorsxw
133
+ ];
134
+ // Create a regex that will match all special characters
135
+ const escapedRegex = new RegExp(specialChars.map((char) => `\\${char}`).join("|"), "g");
136
+ // Escape special characters by prefixing them with a backslash
137
+ return str.replace(escapedRegex, "\\$&");
78
138
  }
79
139
  function _findKey() {
80
140
  if (process.env.PROJECT_ID) {
@@ -88,13 +148,13 @@ function _findKey() {
88
148
  // extract the base folder name
89
149
  return path.basename(folder);
90
150
  }
91
- function _getDataFile(world = null, context = null, stable = null) {
151
+ function _getDataFile(world = null, context = null, web = null) {
92
152
  let dataFile = null;
93
153
  if (world && world.reportFolder) {
94
154
  dataFile = path.join(world.reportFolder, "data.json");
95
155
  }
96
- else if (stable && stable.reportFolder) {
97
- dataFile = path.join(stable.reportFolder, "data.json");
156
+ else if (web && web.reportFolder) {
157
+ dataFile = path.join(web.reportFolder, "data.json");
98
158
  }
99
159
  else if (context && context.reportFolder) {
100
160
  dataFile = path.join(context.reportFolder, "data.json");
@@ -104,37 +164,148 @@ function _getDataFile(world = null, context = null, stable = null) {
104
164
  }
105
165
  return dataFile;
106
166
  }
107
- function _getTestData(world = null, context = null, stable = null) {
108
- const dataFile = _getDataFile(world, context, stable);
167
+ function _getTestDataFile(world = null, context = null, web = null) {
168
+ let dataFile = null;
169
+ if (world && world.reportFolder) {
170
+ dataFile = path.join(world.reportFolder, "data.json");
171
+ }
172
+ else if (web && web.reportFolder) {
173
+ dataFile = path.join(web.reportFolder, "data.json");
174
+ }
175
+ else if (context && context.reportFolder) {
176
+ dataFile = path.join(context.reportFolder, "data.json");
177
+ }
178
+ else if (fs.existsSync(path.join("data", "data.json"))) {
179
+ dataFile = path.join("data", "data.json");
180
+ }
181
+ else {
182
+ dataFile = "data.json";
183
+ }
184
+ return dataFile;
185
+ }
186
+ function _getTestData(world = null, context = null, web = null) {
187
+ const dataFile = _getTestDataFile(world, context, web);
109
188
  let data = {};
110
189
  if (fs.existsSync(dataFile)) {
111
190
  data = JSON.parse(fs.readFileSync(dataFile, "utf8"));
112
191
  }
113
192
  return data;
114
193
  }
115
- async function replaceWithLocalTestData(value, world, _decrypt = true, totpWait = true, context = null, stable = null) {
194
+ async function replaceWithLocalTestData(value, world, _decrypt = true, totpWait = true, context = null, web = null) {
116
195
  if (!value) {
117
196
  return value;
118
197
  }
198
+ let env = "";
199
+ if (context && context.environment) {
200
+ env = context.environment.name;
201
+ }
119
202
  // find all the accurance of {{(.*?)}} and replace with the value
120
203
  let regex = /{{(.*?)}}/g;
121
204
  let matches = value.match(regex);
122
205
  if (matches) {
123
- const testData = _getTestData(world, context, stable);
206
+ const testData = _getTestData(world, context, web);
124
207
  for (let i = 0; i < matches.length; i++) {
125
208
  let match = matches[i];
126
209
  let key = match.substring(2, match.length - 2);
127
- let newValue = objectPath.get(testData, key, null);
128
- if (newValue !== null) {
129
- value = value.replace(match, newValue);
210
+ if (key && key.trim().startsWith("date:")) {
211
+ const dateQuery = key.substring(5);
212
+ const parts = dateQuery.split(">>");
213
+ const returnTemplate = parts[1] || null;
214
+ let serviceUrl = _getServerUrl();
215
+ const config = {
216
+ method: "post",
217
+ url: `${serviceUrl}/api/runs/find-date/find`,
218
+ headers: {
219
+ "x-source": "true",
220
+ "Content-Type": "application/json",
221
+ Authorization: `Bearer ${process.env.TOKEN}`,
222
+ },
223
+ data: JSON.stringify({
224
+ value: parts[0],
225
+ }),
226
+ };
227
+ let result = await axios.request(config);
228
+ //console.log(JSON.stringify(frameDump[0]));
229
+ if (result.status !== 200 || !result.data || result.data.status !== true || !result.data.result) {
230
+ console.error("Failed to find date");
231
+ throw new Error("Failed to find date");
232
+ }
233
+ value = formatDate(result.data.result, returnTemplate);
234
+ }
235
+ else {
236
+ let newValue = replaceTestDataValue(env, key, testData);
237
+ if (newValue !== null) {
238
+ value = value.replace(match, newValue);
239
+ }
240
+ else {
241
+ newValue = replaceTestDataValue("*", key, testData);
242
+ if (newValue !== null) {
243
+ value = value.replace(match, newValue);
244
+ }
245
+ }
130
246
  }
131
247
  }
132
248
  }
133
249
  if ((value.startsWith("secret:") || value.startsWith("totp:") || value.startsWith("mask:")) && _decrypt) {
134
- return await decrypt(value, null, totpWait);
250
+ return decrypt(value, null, totpWait);
251
+ }
252
+ // check if the value is ${}
253
+ if (value.startsWith("${") && value.endsWith("}")) {
254
+ value = evaluateString(value, context.examplesRow);
135
255
  }
136
256
  return value;
137
257
  }
258
+ function replaceTestDataValue(env, key, testData) {
259
+ const path = key.split(".");
260
+ const value = objectPath.get(testData, path);
261
+ if (value && !Array.isArray(value)) {
262
+ return value;
263
+ }
264
+ const dataArray = testData[env];
265
+ if (!dataArray) {
266
+ return null;
267
+ }
268
+ for (const obj of dataArray) {
269
+ if (obj.key !== key) {
270
+ continue;
271
+ }
272
+ if (obj.DataType === "secret") {
273
+ return decrypt(`secret:${obj.value}`, null);
274
+ }
275
+ if (obj.DataType === "totp") {
276
+ return `totp:${obj.value}`;
277
+ }
278
+ return obj.value;
279
+ }
280
+ return null;
281
+ }
282
+ function evaluateString(template, parameters) {
283
+ if (!parameters) {
284
+ parameters = {};
285
+ }
286
+ try {
287
+ return new Function(...Object.keys(parameters), `return \`${template}\`;`)(...Object.values(parameters));
288
+ }
289
+ catch (e) {
290
+ console.error(e);
291
+ return template;
292
+ }
293
+ }
294
+ function formatDate(dateStr, format) {
295
+ if (!format) {
296
+ return dateStr;
297
+ }
298
+ // Split the input date string
299
+ const [dd, mm, yyyy] = dateStr.split("-");
300
+ // Define replacements
301
+ const replacements = {
302
+ dd: dd,
303
+ mm: mm,
304
+ yyyy: yyyy,
305
+ };
306
+ // Replace format placeholders with actual values
307
+ return format.replace(/dd|mm|yyyy/g, (match) => replacements[match]);
308
+ }
138
309
  function maskValue(value) {
139
310
  if (!value) {
140
311
  return value;
@@ -223,6 +394,118 @@ function scanAndManipulate(currentObj, _params) {
223
394
  }
224
395
  }
225
396
  }
397
+ function extractStepExampleParameters(step) {
398
+ if (!step ||
399
+ !step.gherkinDocument ||
400
+ !step.pickle ||
401
+ !step.pickle.astNodeIds ||
402
+ !(step.pickle.astNodeIds.length > 1) ||
403
+ !step.gherkinDocument.feature ||
404
+ !step.gherkinDocument.feature.children) {
405
+ return {};
406
+ }
407
+ try {
408
+ const scenarioId = step.pickle.astNodeIds[0];
409
+ const exampleId = step.pickle.astNodeIds[1];
410
+ // find the scenario in the gherkin document
411
+ const scenario = step.gherkinDocument.feature.children.find((child) => child.scenario.id === scenarioId).scenario;
412
+ if (!scenario || !scenario.examples || !scenario.examples[0].tableBody) {
413
+ return {};
414
+ }
415
+ // find the table body in the examples
416
+ const row = scenario.examples[0].tableBody.find((r) => r.id === exampleId);
417
+ if (!row) {
418
+ return {};
419
+ }
420
+ // extract the cells values (row.cells.value) into an array
421
+ const values = row.cells.map((cell) => cell.value);
422
+ // extract the table headers keys (scenario.examples.tableHeader.cells.value) into an array
423
+ const keys = scenario.examples[0].tableHeader.cells.map((cell) => cell.value);
424
+ // create a dictionary of the keys and values
425
+ const params = {};
426
+ for (let i = 0; i < keys.length; i++) {
427
+ params[keys[i]] = values[i];
428
+ }
429
+ return params;
430
+ }
431
+ catch (e) {
432
+ console.error(e);
433
+ return {};
434
+ }
435
+ }
436
+ export async function performAction(action, element, options, web, state, _params) {
437
+ let usedOptions;
438
+ if (!options) {
439
+ options = {};
440
+ }
441
+ if (!element) {
442
+ throw new Error("Element not found");
443
+ }
444
+ switch (action) {
445
+ case "click":
446
+ // copy any of the following options to usedOptions: button, clickCount, delay, modifiers, force, position, trial
447
+ usedOptions = ["button", "clickCount", "delay", "modifiers", "force", "position", "trial", "timeout"].reduce((acc, key) => {
448
+ if (options[key]) {
449
+ acc[key] = options[key];
450
+ }
451
+ return acc;
452
+ }, {});
453
+ if (!usedOptions.timeout) {
454
+ usedOptions.timeout = 10000;
455
+ if (usedOptions.position) {
456
+ usedOptions.timeout = 1000;
457
+ }
458
+ }
459
+ try {
460
+ await element.click(usedOptions);
461
+ }
462
+ catch (e) {
463
+ if (usedOptions.position) {
464
+ // find the element bounding box
465
+ const rect = await element.boundingBox();
466
+ // calculate the x and y position
467
+ const x = rect.x + rect.width / 2 + (usedOptions.position.x || 0);
468
+ const y = rect.y + rect.height / 2 + (usedOptions.position.y || 0);
469
+ // click on the x and y position
470
+ await web.page.mouse.click(x, y);
471
+ }
472
+ else {
473
+ if (state && state.selectors) {
474
+ state.element = await web._locate(state.selectors, state.info, _params);
475
+ element = state.element;
476
+ }
477
+ await element.dispatchEvent("click");
478
+ }
479
+ }
480
+ break;
481
+ case "hover":
482
+ usedOptions = ["position", "trial", "timeout"].reduce((acc, key) => {
483
+ acc[key] = options[key];
484
+ return acc;
485
+ }, {});
486
+ try {
487
+ await element.hover(usedOptions);
488
+ await new Promise((resolve) => setTimeout(resolve, 1000));
489
+ }
490
+ catch (e) {
491
+ if (state && state.selectors) {
492
+ state.info.log += "hover failed, will try again" + "\n";
493
+ state.element = await web._locate(state.selectors, state.info, _params);
494
+ element = state.element;
495
+ }
496
+ usedOptions.timeout = 10000;
497
+ await element.hover(usedOptions);
498
+ await new Promise((resolve) => setTimeout(resolve, 1000));
499
+ }
500
+ break;
501
+ case "hover+click":
502
+ await performAction("hover", element, options, web, state, _params);
503
+ await performAction("click", element, options, web, state, _params);
504
+ break;
505
+ default:
506
+ throw new Error(`Action ${action} not supported`);
507
+ }
508
+ }
226
509
  const KEYBOARD_EVENTS = [
227
510
  "ALT",
228
511
  "AltGraph",
@@ -382,7 +665,28 @@ function _getServerUrl() {
382
665
  else if (process.env.NODE_ENV_BLINQ === "stage") {
383
666
  serviceUrl = "https://stage.api.blinq.io";
384
667
  }
668
+ else if (process.env.NODE_ENV_BLINQ === "prod") {
669
+ serviceUrl = "https://api.blinq.io";
670
+ }
671
+ else if (!process.env.NODE_ENV_BLINQ) {
672
+ serviceUrl = "https://api.blinq.io";
673
+ }
674
+ else {
675
+ serviceUrl = process.env.NODE_ENV_BLINQ;
676
+ }
385
677
  return serviceUrl;
386
678
  }
387
- export { encrypt, decrypt, replaceWithLocalTestData, maskValue, _copyContext, scrollPageToLoadLazyElements, _fixUsingParams, getWebLogFile, _fixLocatorUsingParams, _isObject, scanAndManipulate, KEYBOARD_EVENTS, unEscapeString, _getServerUrl, _convertToRegexQuery, };
679
+ function tryParseJson(input) {
680
+ if (typeof input === "string") {
681
+ try {
682
+ return JSON.parse(input);
683
+ }
684
+ catch {
685
+ // If parsing fails, return the original input (assumed to be plain text or another format)
686
+ return input;
687
+ }
688
+ }
689
+ return input;
690
+ }
691
+ export { encrypt, decrypt, replaceWithLocalTestData, maskValue, _copyContext, scrollPageToLoadLazyElements, _fixUsingParams, getWebLogFile, _fixLocatorUsingParams, _isObject, scanAndManipulate, KEYBOARD_EVENTS, unEscapeString, _getServerUrl, _convertToRegexQuery, extractStepExampleParameters, _getDataFile, tryParseJson, getTestDataValue, };
388
692
  //# sourceMappingURL=utils.js.map