automation_model 1.0.22 → 1.0.24

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 (2) hide show
  1. package/bin/stable_browser.js +104 -94
  2. package/package.json +1 -1
@@ -15,61 +15,86 @@ class StableBrowser {
15
15
  timeout: 60000,
16
16
  });
17
17
  }
18
- async _checkUnique(locator, info) {
19
- info.log.push("check unique");
20
- let count = await locator.count();
21
- info.log.push("count=" + count);
22
- if (count > 1) {
23
- this.logger.error("Found more than one element for locator" + JSON.stringify(locator.toString()));
24
- for (let i = 0; i < count; i++) {
25
- let loc = locator.nth(i);
26
- if ((await loc.isVisible()) && (await loc.isEnabled())) {
27
- info.box = await loc.boundingBox();
28
- return loc;
29
- }
18
+ _getLocator(locator, scope) {
19
+ if (locator.role) {
20
+ if (locator.role[1].nameReg) {
21
+ locator.role[1].name = reg_parser(locator.role[1].nameReg);
22
+ delete locator.role[1].nameReg;
30
23
  }
24
+ return scope.getByRole(locator.role[0], locator.role[1]);
31
25
  }
32
- if (count === 1) {
33
- info.box = await locator.boundingBox();
26
+ if (locator.css) {
27
+ return scope.locator(locator.css);
34
28
  }
35
- return locator;
29
+ if (locator.text) {
30
+ return scope.getByText(locator.text);
31
+ }
32
+ throw new Error("unknown locator type");
36
33
  }
37
- async _locate(selector, scope, info) {
38
- try {
39
- if (Array.isArray(selector)) {
40
- let currentScope = scope;
41
34
 
42
- for (let i = 0; i < selector.length; i++) {
43
- currentScope = await this._locate(selector[i], currentScope, info);
35
+ async _collectLocatorInformation(locators, index, scope, foundLocators) {
36
+ if (index === locators.length) {
37
+ return;
38
+ }
39
+ const locator = this._getLocator(locators[index], scope);
40
+ let count = await locator.count();
41
+ let visibleCount = 0;
42
+ let visibleLocator = null;
43
+ for (let j = 0; j < count; j++) {
44
+ if ((await locator.nth(j).isVisible()) && (await locator.nth(j).isEnabled())) {
45
+ visibleCount++;
46
+ if (index === locators.length - 1) {
47
+ foundLocators.push(locator.nth(j));
48
+ } else {
49
+ this._collectLocatorInformation(locators, index + 1, locator.nth(j), foundLocators);
44
50
  }
45
- return currentScope;
46
51
  }
47
- if (typeof selector === "object") {
48
- info.log.push("try selector " + JSON.stringify(selector));
49
- if (selector.css) {
50
- return await this._checkUnique(scope.locator(selector.css), info);
51
- }
52
- if (selector.role) {
53
- if (selector.role[1].nameReg) {
54
- selector.role[1].name = reg_parser(selector.role[1].nameReg);
55
- delete selector.role[1].nameReg;
56
- }
57
- return await this._checkUnique(scope.getByRole(selector.role[0], selector.role[1]), info);
52
+ }
53
+ }
54
+ async _locate(selectors, info, timeout = 10000) {
55
+ let locatorsByPriority = [];
56
+ let startTime = performance.now();
57
+ let locatorsCount = 0;
58
+ while (true) {
59
+ locatorsCount = 0;
60
+ for (let i = 0; i < selectors.length; i++) {
61
+ let selectorList = selectors[i];
62
+
63
+ let foundLocators = [];
64
+ try {
65
+ await this._collectLocatorInformation(selectorList, 0, this.page, foundLocators);
66
+ } catch (e) {
67
+ foundLocators = [];
68
+ await this._collectLocatorInformation(selectorList, 0, this.page, foundLocators);
58
69
  }
59
- if (selector.text) {
60
- return await this._checkUnique(scope.getByText(selector.text), info);
70
+
71
+ info.log.push("total elements found " + foundLocators.length);
72
+ if (foundLocators.length === 1) {
73
+ info.log.push("found unique element");
74
+ info.box = await foundLocators[0].boundingBox();
75
+ return foundLocators[0];
61
76
  }
62
- } else if (typeof selector === "string" && selector.startsWith("TEXT=")) {
63
- info.log.push("try getByText");
64
- return await this.page.getByText(selector.substring("TEXT=".length));
65
- } else {
66
- info.log.push("try direct css selector");
67
- return await this.page.locator(selector);
77
+ locatorsByPriority.push(foundLocators);
78
+ locatorsCount += foundLocators.length;
79
+ }
80
+ if (locatorsCount > 0) {
81
+ break;
82
+ }
83
+ if (performance.now() - startTime > timeout) {
84
+ break;
85
+ }
86
+ await new Promise((resolve) => setTimeout(resolve, 1000));
87
+ }
88
+ this.logger.info("failed to locate unique element, total elements found " + locatorsCount);
89
+ info.log.push("failed to locate unique element, total elements found " + locatorsCount);
90
+ for (let i = 0; i < locatorsByPriority.length; i++) {
91
+ let locators = locatorsByPriority[i];
92
+ if (locators.length > 0) {
93
+ info.box = await locators[0].boundingBox();
94
+ return locators[0];
68
95
  }
69
- throw new Error(`Unknown locator type ${type}`);
70
- } catch (e) {
71
- console.log("invalid locator object, will try to parse as text");
72
96
  }
97
+ throw new Error("failed to locate first element no elements found");
73
98
  }
74
99
 
75
100
  async click(selector, options = {}) {
@@ -77,22 +102,20 @@ class StableBrowser {
77
102
  info.log = [];
78
103
  info.operation = "click";
79
104
  info.selector = selector;
80
- for (let i = 0; i < selector.length; i++) {
81
- info.log.push("try selector " + i);
82
- try {
83
- let element = await this._locate(selector[i], this.page, info);
84
- await this._screenShot(options);
85
- await element.click({ timeout: 10000 });
86
- return info;
87
- } catch (e) {
88
- if (i === selector.length - 1) {
89
- this.logger.error("click failed " + JSON.stringify(info));
90
- Object.assign(e, { info: info });
91
- await this._screenShot(options);
92
- throw e;
93
- }
94
- this.logger.info("click failed, will try next selector");
95
- }
105
+
106
+ try {
107
+ let element = await this._locate(selector, info);
108
+
109
+ await this._screenShot(options);
110
+ await element.click({ timeout: 10000 });
111
+ return info;
112
+ } catch (e) {
113
+ this.logger.error("click failed " + JSON.stringify(info));
114
+ Object.assign(e, { info: info });
115
+ await this._screenShot(options);
116
+ throw e;
117
+
118
+ this.logger.info("click failed, will try next selector");
96
119
  }
97
120
  }
98
121
  async fill(selector, value, options = {}) {
@@ -101,23 +124,17 @@ class StableBrowser {
101
124
  info.operation = "fill";
102
125
  info.selector = selector;
103
126
  info.value = value;
104
- for (let i = 0; i < selector.length; i++) {
105
- info.log.push("try selector " + i);
106
- try {
107
- let element = await this._locate(selector[i], this.page, info);
108
- await this._screenShot(options);
109
- await element.fill(value, { timeout: 10000 });
110
- await element.dispatchEvent("change");
111
- return info;
112
- } catch (e) {
113
- if (i === selector.length - 1) {
114
- this.logger.error("fill failed " + JSON.stringify(info));
115
- Object.assign(e, { info: info });
116
- await this._screenShot(options);
117
- throw e;
118
- }
119
- this.logger.info("click failed, will try next selector");
120
- }
127
+ try {
128
+ let element = await this._locate(selector, info);
129
+ await this._screenShot(options);
130
+ await element.fill(value, { timeout: 10000 });
131
+ await element.dispatchEvent("change");
132
+ return info;
133
+ } catch (e) {
134
+ this.logger.error("fill failed " + JSON.stringify(info));
135
+ Object.assign(e, { info: info });
136
+ await this._screenShot(options);
137
+ throw e;
121
138
  }
122
139
  }
123
140
  async _screenShot(options = {}) {
@@ -130,24 +147,17 @@ class StableBrowser {
130
147
  info.log = [];
131
148
  info.operation = "verify";
132
149
  info.selector = selector;
133
- for (let i = 0; i < selector.length; i++) {
134
- try {
135
- const element = await this._locate(selector[0], this.page, info);
136
- await this._screenShot(options);
137
- await expect(element).toHaveCount(1, { timeout: 10000 });
138
- return info;
139
- } catch (e) {
140
- if (i === selector.length - 1) {
141
- this.logger.error("verify failed " + JSON.stringify(info));
142
- Object.assign(e, { info: info });
143
- await this._screenShot(options);
144
- throw e;
145
- }
146
- this.logger.info("click failed, will try next selector");
147
- }
150
+ try {
151
+ const element = await this._locate(selector, info);
152
+ await this._screenShot(options);
153
+ await expect(element).toHaveCount(1, { timeout: 10000 });
154
+ return info;
155
+ } catch (e) {
156
+ this.logger.error("verify failed " + JSON.stringify(info));
157
+ Object.assign(e, { info: info });
158
+ await this._screenShot(options);
159
+ throw e;
148
160
  }
149
-
150
- //await expect(element !== undefined).toBeTruthy();
151
161
  }
152
162
  async waitForPageLoad(options = {}) {
153
163
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "automation_model",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "description": "An automation infrastructure module to be use for generative AI automation projects.",
5
5
  "main": "bin/index.js",
6
6
  "type": "module",