automation_model 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.
@@ -0,0 +1,64 @@
1
+ import { getContext } from "./init_browser.js";
2
+ import { StableBrowser } from "./stable_browser.js";
3
+ class AutoPage {
4
+ constructor() {
5
+ this.name = null;
6
+ this.path = null;
7
+ this.elements = {};
8
+ this.context = null;
9
+ this.login_required = false;
10
+ this.url_navigate = true;
11
+ this.stable = null;
12
+ }
13
+
14
+ /**
15
+ * Add element to the elements dictionary
16
+ * @param {string} name - Name of the element
17
+ * @param {string} locator - Locator of the element
18
+ * @returns {void}
19
+ * @memberof Page
20
+ * @example
21
+ * page.addElement('username', 'input[name="username"]');
22
+ */
23
+ addElement(name, locator) {
24
+ this.elements[name] = locator;
25
+ }
26
+ /**
27
+ * init context
28
+ */
29
+ static async init(navigate = true) {
30
+ const instance = new this();
31
+ instance.context = await getContext();
32
+ instance.page = instance.context.page;
33
+ instance.browser = instance.context.browser;
34
+ instance.stable = instance.context.stable;
35
+ if (navigate) {
36
+ await instance.navigate();
37
+ }
38
+ return instance;
39
+ }
40
+ static async initFromContext(context, navigate = true) {
41
+ const instance = new this();
42
+ instance.context = context;
43
+ instance.page = instance.context.page;
44
+ instance.browser = instance.context.browser;
45
+ instance.environment = instance.context.environment;
46
+ instance.stable = instance.context.stable;
47
+ if (navigate) {
48
+ await instance.navigate();
49
+ }
50
+ return instance;
51
+ }
52
+
53
+ /**
54
+ * Navigate to the page
55
+ * synchronize waiting the page to be loaded
56
+ * @param {Environment} environment - Environment object
57
+ */
58
+ async navigate() {
59
+ //console.log("navigate", this.context.environment.baseUrl + this.path);
60
+ await this.stable.goto(this.context.environment.baseUrl + this.path);
61
+ await this.stable.waitForPageLoad();
62
+ }
63
+ }
64
+ export default AutoPage;
@@ -0,0 +1,85 @@
1
+ import { chromium } from "playwright";
2
+ class BrowserManager {
3
+ constructor() {
4
+ this.browsers = [];
5
+ }
6
+
7
+ async closeAll() {
8
+ await Promise.all(this.browsers.map((browser) => browser.close()));
9
+ this.browsers = [];
10
+ }
11
+ async closeBrowser(browser) {
12
+ if (browser !== null) {
13
+ await browser.close();
14
+ for (let i = 0; i < this.browsers.length; i++) {
15
+ if (
16
+ this.browsers[i].browser === browser ||
17
+ this.browsers[i] === browser
18
+ ) {
19
+ this.browsers.splice(i, 1);
20
+ i--;
21
+ break;
22
+ }
23
+ }
24
+ }
25
+ }
26
+
27
+ async createBrowser() {
28
+ const browser = new Browser();
29
+ await browser.init();
30
+ this.browsers.push(browser);
31
+ return browser;
32
+ }
33
+ async getBrowser() {
34
+ if (this.browsers.length === 0) {
35
+ return await this.createBrowser();
36
+ }
37
+ return this.browsers[0];
38
+ }
39
+ }
40
+ class Browser {
41
+ constructor() {
42
+ this.browser = null;
43
+ this.context = null;
44
+ this.page = null;
45
+ }
46
+
47
+ async init() {
48
+ //let port = 9222;
49
+ this.browser = await chromium.launch({
50
+ headless: false,
51
+ timeout: 0,
52
+ //args: ["--remote-debugging-port=" + port],
53
+ });
54
+ // const cdpBrowser = await chromium.connectOverCDP({
55
+ // endpointURL: `http://127.0.0.1:${port}/`,
56
+ // });
57
+ // //let context = await browser.newContext();
58
+ // const context = cdpBrowser.contexts()[0];
59
+ // let page = await context.newPage();
60
+ // page.goto("https://www.cnn.com");
61
+ this.context = await this.browser.newContext();
62
+ this.page = await this.context.newPage();
63
+ //console.log("browser", this.browser);
64
+ }
65
+
66
+ async close() {
67
+ if (this.browser !== null) {
68
+ await this.browser.close();
69
+ this.browser = null;
70
+ this.context = null;
71
+ this.page = null;
72
+ }
73
+ }
74
+ }
75
+ const browserManager = new BrowserManager();
76
+
77
+ export default browserManager;
78
+
79
+ // let browser = await browserManager.createBrowser();
80
+ // browser.page.goto("https://www.cnn.com");
81
+ // let browser2 = await browserManager.createBrowser();
82
+ // await browser2.page.goto("https://www.google.com");
83
+ // // sleep for 2 seconds
84
+ // await new Promise((r) => setTimeout(r, 1000));
85
+ // await browserManager.closeAll();
@@ -0,0 +1,9 @@
1
+ class Environment {
2
+ constructor() {
3
+ this.baseUrl = null;
4
+ }
5
+ setBaseUrl(url) {
6
+ this.baseUrl = url;
7
+ }
8
+ }
9
+ export default Environment;
@@ -0,0 +1,59 @@
1
+ import fs from "node:fs";
2
+ import Environment from "./environment.js";
3
+ import browserManager from "./browser_manager.js";
4
+ import TestContext from "./test_context.js";
5
+ import { StableBrowser } from "./stable_browser.js";
6
+
7
+ let environment = null;
8
+
9
+ // init browser create context and page, if context and page are not null
10
+ const getContext = async function (environment = null) {
11
+ if (environment === null) {
12
+ environment = initEnvoronment();
13
+ }
14
+ let browser = await browserManager.getBrowser();
15
+ let context = new TestContext();
16
+ context.browser = browser.browser;
17
+ context.playContext = browser.context;
18
+ context.page = browser.page;
19
+ context.environment = environment;
20
+ context.stable = new StableBrowser(context.browser, context.page);
21
+ await _initCookies(context);
22
+ return context;
23
+ };
24
+ const _initCookies = async function (context) {
25
+ if (context.environment.cookies) {
26
+ const cookies = [];
27
+ for (let i = 0; i < context.environment.cookies.length; i++) {
28
+ const cookie = context.environment.cookies[i];
29
+ if (cookie.expires && cookie.expires == "undefined") {
30
+ delete cookie.expires;
31
+ }
32
+ cookies.push(cookie);
33
+ }
34
+ await context.playContext.addCookies(cookies);
35
+ }
36
+ };
37
+
38
+ const closeBrowser = async function (browser) {
39
+ await browserManager.closeBrowser(browser);
40
+ };
41
+
42
+ const initEnvoronment = function () {
43
+ if (environment === null) {
44
+ environment = new Environment();
45
+ try {
46
+ const data = fs.readFileSync("env.json", "utf8");
47
+ //console.log("data", data);
48
+ const envObject = JSON.parse(data);
49
+ //console.log("envObject", envObject);
50
+ Object.assign(environment, envObject);
51
+ console.log("env", environment);
52
+ } catch (err) {
53
+ console.error("Error reading env.json", err);
54
+ }
55
+ }
56
+ return environment;
57
+ };
58
+
59
+ export { getContext, closeBrowser };
@@ -0,0 +1,151 @@
1
+ class StableBrowser {
2
+ constructor(browser, page) {
3
+ this.browser = browser;
4
+ this.page = page;
5
+ }
6
+
7
+ async goto(url) {
8
+ await this.page.goto(url, {
9
+ timeout: 60000,
10
+ });
11
+ }
12
+ async _locate(selector) {
13
+ if (selector.startsWith("{")) {
14
+ try {
15
+ const locatorObject = JSON.parse(selector);
16
+ let type = locatorObject.type;
17
+ if (!type) {
18
+ type = "css";
19
+ }
20
+ switch (type) {
21
+ case "css":
22
+ return await this.page.locator(locatorObject.locator);
23
+ case "role":
24
+ return await this.page.getByRole(
25
+ locatorObject.role,
26
+ locatorObject.options
27
+ );
28
+ case "text":
29
+ return await this.page.getByText(locatorObject.text);
30
+ default:
31
+ throw new Error(`Unknown locator type ${type}`);
32
+ }
33
+ } catch (e) {
34
+ console.log("invalid locator object, will try to parse as text");
35
+ }
36
+ }
37
+
38
+ if (selector.startsWith("TEXT=")) {
39
+ return await this.page.getByText(selector.substring("TEXT=".length));
40
+ } else {
41
+ return await this.page.locator(selector);
42
+ }
43
+ }
44
+
45
+ async click(selector) {
46
+ (await this._locate(selector)).click();
47
+ }
48
+ async fill(selector, value) {
49
+ let element = await this._locate(selector);
50
+ await element.fill(value);
51
+ await element.dispatchEvent("change");
52
+ }
53
+ async clickInTableRow(textInRow, actionLocator) {
54
+ const row = await page.evaluate(() => {
55
+ function isVisible(elem) {
56
+ if (!(elem instanceof Element)) {
57
+ return false;
58
+ }
59
+ const style = getComputedStyle(elem);
60
+ if (style.display === "none") return false;
61
+ if (style.visibility !== "visible") return false;
62
+ if (style.opacity < 0.1) return false;
63
+ if (
64
+ elem.offsetWidth +
65
+ elem.offsetHeight +
66
+ elem.getBoundingClientRect().height +
67
+ elem.getBoundingClientRect().width ===
68
+ 0
69
+ ) {
70
+ return false;
71
+ }
72
+ const elemCenter = {
73
+ x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
74
+ y: elem.getBoundingClientRect().top + elem.offsetHeight / 2,
75
+ };
76
+ if (elemCenter.x < 0) return false;
77
+ if (
78
+ elemCenter.x >
79
+ (document.documentElement.clientWidth || window.innerWidth)
80
+ )
81
+ return false;
82
+ if (elemCenter.y < 0) return false;
83
+ if (
84
+ elemCenter.y >
85
+ (document.documentElement.clientHeight || window.innerHeight)
86
+ ) {
87
+ return false;
88
+ }
89
+ return true;
90
+ }
91
+ function isBackgrounElement(element) {
92
+ let rec = element.getBoundingClientRect();
93
+ let xCenter = rec.left + rec.width / 2;
94
+ let yCenter = rec.top + rec.height / 2;
95
+ let elementAtPoint = document.elementFromPoint(xCenter, yCenter);
96
+ if (!elementAtPoint) {
97
+ return false;
98
+ }
99
+ if (elementAtPoint.contains(element)) {
100
+ return false;
101
+ }
102
+ // check if the element is the same element or same as parent
103
+ let toCheck = elementAtPoint;
104
+ while (toCheck) {
105
+ if (toCheck === element) {
106
+ return false;
107
+ }
108
+ toCheck = toCheck.parentElement;
109
+ }
110
+
111
+ return true;
112
+ }
113
+
114
+ const rows = table.querySelectorAll('tr, role="row"');
115
+ let foundRow = null;
116
+ for (let i = 0; i < rows.length; i++) {
117
+ const row = rows[i];
118
+ const rowData = [];
119
+ const cells = row.querySelectorAll(
120
+ "td, th, [role='cell'], [role='columnheader']"
121
+ );
122
+ cells.forEach((cell) => {
123
+ if (!isVisible(cell) || isBackgrounElement(cell)) {
124
+ return;
125
+ }
126
+ const text = getTextFromElement(cell);
127
+ rowData.push(text);
128
+ });
129
+ if (rowData.includes(textInRow)) {
130
+ foundRow = row;
131
+ break;
132
+ }
133
+ }
134
+ return foundRow;
135
+ });
136
+ await foundRow.locator(actionLocator).click();
137
+ }
138
+ async waitForPageLoad() {
139
+ try {
140
+ await Promise.all([
141
+ this.page.waitForLoadState("networkidle"),
142
+ this.page.waitForLoadState("load"),
143
+ this.page.waitForLoadState("domcontentloaded"),
144
+ ]);
145
+ } catch (e) {
146
+ console.log("waitForPageLoad error, ignored");
147
+ }
148
+ await new Promise((resolve) => setTimeout(resolve, 2000));
149
+ }
150
+ }
151
+ export { StableBrowser };
@@ -0,0 +1,9 @@
1
+ class TestContext {
2
+ constructor() {
3
+ this.browser = null;
4
+ this.playContext = null;
5
+ this.page = null;
6
+ this.environment = null;
7
+ }
8
+ }
9
+ export default TestContext;
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "automation_model",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "bin/index.js",
6
+ "type": "module",
7
+ "directories": {
8
+ "lib": "lib"
9
+ },
10
+ "scripts": {
11
+ "pack": "mkdir build && mkdir build/bin && cp ./src/auto_page.js ./build/bin/auto_page.js && cp ./src/environment.js ./build/bin/environment.js && cp ./src/browser_manager.js ./build/bin/browser_manager.js && cp ./src/test_context.js ./build/bin/test_context.js && cp ./src/init_browser.js ./build/bin/init_browser.js && cp ./src/stable_browser.js ./build/bin/stable_browser.js && cp ./package.json ./build/package.json",
12
+ "clean": "rm -rf ./build",
13
+ "build": "npm run clean && npm run pack"
14
+ },
15
+ "author": "",
16
+ "license": "ISC",
17
+ "dependencies": {
18
+ "playwright": "^1.33.0"
19
+ }
20
+ }