@devassure/tpp-engine 0.0.0-stage → 1.8.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.
- package/README.md +18 -2
- package/index.js +121 -0
- package/package.json +30 -4
- package/src/accessibility/combined-a11y-report.js +208 -0
- package/src/accessibility/tpp-a11y.js +81 -0
- package/src/actions.js +3201 -0
- package/src/api/api-auth.js +18 -0
- package/src/api/api-service.js +289 -0
- package/src/app-config.json +7 -0
- package/src/autoheal-actions.js +309 -0
- package/src/console-log/console-log-manager.js +39 -0
- package/src/console-log/console-log-utils.js +201 -0
- package/src/database/mysql/mysql-service.js +23 -0
- package/src/database/neo4j/neo4j-service.js +32 -0
- package/src/database/oracle/oracle-service.js +48 -0
- package/src/database/pg/pg-service.js +29 -0
- package/src/downloads/downloads-manager.js +86 -0
- package/src/downloads/downloads-utils.js +113 -0
- package/src/globalsetup.js +68 -0
- package/src/globalteardown.js +57 -0
- package/src/hooks/each-hook.js +45 -0
- package/src/hooks/hook-utils.js +21 -0
- package/src/library/authenticator/authenticator-utils.js +43 -0
- package/src/library/csv/csv-utils.js +297 -0
- package/src/library/date/date-utils.js +168 -0
- package/src/library/emailTesting/TokenConfig.js +46 -0
- package/src/library/emailTesting/emailTesting-utils.js +527 -0
- package/src/library/excel/excel-utils.js +922 -0
- package/src/library/file/file-action-utils.js +129 -0
- package/src/library/file/file-utils.js +127 -0
- package/src/library/json/json-utils.js +104 -0
- package/src/library/math/math-utils.js +283 -0
- package/src/library/softAssert/softAssert-utils.js +154 -0
- package/src/library/table/table-utils.js +92 -0
- package/src/library/text/text-utils.js +45 -0
- package/src/library/tpp-library.js +81 -0
- package/src/library/web/slider-utils.js +66 -0
- package/src/mobile/appium/appium-manager.js +158 -0
- package/src/mobile/device-cloud/browserstack-service.js +44 -0
- package/src/mobile/device-cloud/commands/browserstack-commands.js +20 -0
- package/src/mobile/device-cloud/commands/device-cloud-commands.js +17 -0
- package/src/mobile/device-cloud/device-cloud-service.js +29 -0
- package/src/mobile/device-cloud/pcloudy-service.js +65 -0
- package/src/mobile/mobile-actions.js +1568 -0
- package/src/mobile/recorder-utils/css-selector-generator.js +2 -0
- package/src/mobile/recorder-utils/finder.js +752 -0
- package/src/mobile/recorder-utils/mobile-recorder.js +266 -0
- package/src/mobile/web-driver-utils.js +110 -0
- package/src/models/tpp-element.js +58 -0
- package/src/models/tpp-mobile-element.js +50 -0
- package/src/network-log/network-log-manager.js +96 -0
- package/src/network-log/network-log-utils.js +361 -0
- package/src/types/elements.types.js +24 -0
- package/src/utils/ai-utils.js +48 -0
- package/src/utils/assert-utils.js +50 -0
- package/src/utils/autoheal-utils.js +9 -0
- package/src/utils/common-utils.js +120 -0
- package/src/utils/cookie-utils.js +70 -0
- package/src/utils/json-utils.js +10 -0
- package/src/utils/log-utils.js +10 -0
- package/src/utils/logger.js +76 -0
- package/src/utils/screenshot-utils.js +42 -0
- package/src/utils/token-utils.js +18 -0
- package/src/utils/vectordb-utils.js +125 -0
- package/src/visual-test/tpp-visual-test.js +122 -0
- package/src/web/web-executor-agent.js +149 -0
- package/src/web/web-executor-data-fetch.js +353 -0
- package/test-excel-utils.js +570 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
const { compare } = require("../utils/assert-utils");
|
|
2
|
+
const { Logger } = require("../utils/logger");
|
|
3
|
+
|
|
4
|
+
class ConsoleLogUtils {
|
|
5
|
+
|
|
6
|
+
constructor(caller, blacklistedLogs, consoleLogManager) {
|
|
7
|
+
this.caller = caller;
|
|
8
|
+
this.blacklistedLogs = blacklistedLogs;
|
|
9
|
+
this.consoleLogManager = consoleLogManager;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
setCaller(caller) {
|
|
13
|
+
this.caller = caller;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
setBlacklistedLogs(blacklistedLogs) {
|
|
17
|
+
this.blacklistedLogs = blacklistedLogs;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
checkConsoleLogEnabled(logLabel) {
|
|
21
|
+
if(!this.consoleLogManager?.enabled) {
|
|
22
|
+
if(logLabel) {
|
|
23
|
+
(new Logger(this.caller, this.blacklistedLogs)).failureLog(logLabel);
|
|
24
|
+
}
|
|
25
|
+
throw { message: 'Console logs tracing is not enabled! Enable it under Project preferences.' };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get_console_logs_matching_text(searchText) {
|
|
30
|
+
const logLabel = `Get Console Logs matching text - ${searchText}`;
|
|
31
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
32
|
+
logger.startLog(logLabel);
|
|
33
|
+
this.checkConsoleLogEnabled(logLabel);
|
|
34
|
+
let logs = this.queryLogs({
|
|
35
|
+
searchText: searchText,
|
|
36
|
+
});
|
|
37
|
+
logger.endLog(logLabel);
|
|
38
|
+
return logs || [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get_last_console_log_matching(logType, url) {
|
|
42
|
+
const logLabel = `Get Last Console Log matching log type - ${logType} and sourceUrl - ${url}`;
|
|
43
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
44
|
+
logger.startLog(logLabel);
|
|
45
|
+
this.checkConsoleLogEnabled(logLabel);
|
|
46
|
+
let logs = this.queryLogs({
|
|
47
|
+
limit: 1,
|
|
48
|
+
sourceUrl: url,
|
|
49
|
+
logTypes: [method],
|
|
50
|
+
});
|
|
51
|
+
if(!logs?.length) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
logger.endLog(logLabel);
|
|
55
|
+
return logs[0];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get_last_n_console_logs_matching(n, logType, url) {
|
|
59
|
+
const logLabel = `Get Last ${n} Console Logs matching logType - ${logType} and sourceUrl - ${url}`;
|
|
60
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
61
|
+
logger.startLog(logLabel);
|
|
62
|
+
this.checkConsoleLogEnabled(logLabel);
|
|
63
|
+
let logs = this.queryLogs({
|
|
64
|
+
limit: n,
|
|
65
|
+
sourceUrl: url,
|
|
66
|
+
logTypes: [logType],
|
|
67
|
+
});
|
|
68
|
+
logger.endLog(logLabel);
|
|
69
|
+
return logs || [];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get_all_console_logs() {
|
|
73
|
+
const logLabel = `Get All Console Logs`;
|
|
74
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
75
|
+
logger.startLog(logLabel);
|
|
76
|
+
this.checkConsoleLogEnabled(logLabel);
|
|
77
|
+
let logs = this.queryLogs({});
|
|
78
|
+
logger.endLog(logLabel);
|
|
79
|
+
return logs;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get_last_n_console_logs(n) {
|
|
83
|
+
const logLabel = `Get Last ${n} Console Logs`;
|
|
84
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
85
|
+
logger.startLog(logLabel);
|
|
86
|
+
this.checkConsoleLogEnabled(logLabel);
|
|
87
|
+
let logs = this.queryLogs({limit: n});
|
|
88
|
+
logger.endLog(logLabel);
|
|
89
|
+
return logs;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
query_console_logs(query) {
|
|
93
|
+
const logLabel = `Query Console Logs`;
|
|
94
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
95
|
+
logger.startLog(logLabel);
|
|
96
|
+
this.checkConsoleLogEnabled(logLabel);
|
|
97
|
+
let logs = this.queryLogs(query);
|
|
98
|
+
logger.endLog(logLabel);
|
|
99
|
+
return logs;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
//Private Fn
|
|
103
|
+
queryLogs(query) {
|
|
104
|
+
let logs = this.consoleLogManager?.consoleLogs;
|
|
105
|
+
if(query?.sourceUrl) {
|
|
106
|
+
if(query.urlComparator) {
|
|
107
|
+
logs = logs.filter(log => compare(log.sourceUrl, query.urlComparator, query.sourceUrl))
|
|
108
|
+
} else {
|
|
109
|
+
let regex;
|
|
110
|
+
try {
|
|
111
|
+
regex = new RegExp(query.sourceUrl);
|
|
112
|
+
} catch(_ex) {};
|
|
113
|
+
const check = regex
|
|
114
|
+
? (log) => regex.test(log.sourceUrl) || log.sourceUrl?.includes(query.sourceUrl)
|
|
115
|
+
: (log) => log.sourceUrl?.includes(query.sourceUrl)
|
|
116
|
+
logs = logs.filter(check);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if(query?.logTypes?.length) {
|
|
120
|
+
logs = logs.filter(log => query.logTypes.some(logType => log.type === logType));
|
|
121
|
+
}
|
|
122
|
+
if(query?.searchText) {
|
|
123
|
+
logs = logs.filter(log => compare(log.text?.toLowerCase(), query.textComparator || 'contains', query.searchText.toLowerCase()));
|
|
124
|
+
}
|
|
125
|
+
if(query?.limit && query.limit > 0) {
|
|
126
|
+
logs = logs.slice(-1 * query.limit);
|
|
127
|
+
}
|
|
128
|
+
return logs
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
print_all_console_logs() {
|
|
132
|
+
const logs = this.consoleLogManager?.consoleLogs;
|
|
133
|
+
this.checkConsoleLogEnabled();
|
|
134
|
+
const title = `###### All console logs: (${logs?.length || 0}) ######`;
|
|
135
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
136
|
+
logger.log(undefined, title);
|
|
137
|
+
this.print_console_logs(logs);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
print_console_logs(consoleLog, index) {
|
|
141
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
142
|
+
if(Array.isArray(consoleLog)) {
|
|
143
|
+
consoleLog?.forEach((log, i) => this.print_console_logs(log, i));
|
|
144
|
+
return;
|
|
145
|
+
} else if(!consoleLog || typeof consoleLog !== "object") {
|
|
146
|
+
logger.log(undefined, 'Invalid console log!!');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const title = index == null
|
|
150
|
+
? "---------------------------------CONSOLE LOG---------------------------------"
|
|
151
|
+
: `-- ${index + 1} -------------------------------------------------------------------------`
|
|
152
|
+
logger.log(undefined, title);
|
|
153
|
+
let content = JSON.stringify(consoleLog, undefined, 4);
|
|
154
|
+
content.split('\n').forEach(line => logger.log(undefined, line));
|
|
155
|
+
logger.log(undefined, "_______________________________________________________________________________");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
console_log_or_last_in_array(consoleLog, logLabel) {
|
|
159
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
160
|
+
if(!consoleLog) {
|
|
161
|
+
logger.failureLog(logLabel);
|
|
162
|
+
throw { message: 'Invalid console log object!' };
|
|
163
|
+
}
|
|
164
|
+
if(Array.isArray(consoleLog)) {
|
|
165
|
+
if(!consoleLog?.length) {
|
|
166
|
+
logger.failureLog(logLabel);
|
|
167
|
+
throw { message: 'Console logs is empty!' };
|
|
168
|
+
}
|
|
169
|
+
let log = consoleLog.at(-1);
|
|
170
|
+
if(!log) {
|
|
171
|
+
logger.failureLog(logLabel);
|
|
172
|
+
throw { message: 'Invalid console logs!' };
|
|
173
|
+
}
|
|
174
|
+
return log;
|
|
175
|
+
}
|
|
176
|
+
return consoleLog;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
get_console_log_source_url(consoleLog) {
|
|
180
|
+
const logLabel = `Get Console Log Source Url`;
|
|
181
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
182
|
+
logger.startLog(logLabel);
|
|
183
|
+
this.checkConsoleLogEnabled(logLabel);
|
|
184
|
+
let log = this.console_log_or_last_in_array(consoleLog, logLabel)
|
|
185
|
+
logger.endLog(logLabel);
|
|
186
|
+
return log.sourceUrl;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
get_console_log_text(consoleLog) {
|
|
190
|
+
const logLabel = `Get Console Log Text`;
|
|
191
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
192
|
+
logger.startLog(logLabel);
|
|
193
|
+
this.checkConsoleLogEnabled(logLabel);
|
|
194
|
+
let log = this.console_log_or_last_in_array(consoleLog, logLabel)
|
|
195
|
+
logger.endLog(logLabel);
|
|
196
|
+
return log.text;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
exports.ConsoleLogUtils = ConsoleLogUtils;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const mysql = require('mysql2/promise');
|
|
2
|
+
|
|
3
|
+
class MySQLService {
|
|
4
|
+
|
|
5
|
+
async executeQuery(dbConfig, query, params, paramValues) {
|
|
6
|
+
const pool = mysql.createPool({
|
|
7
|
+
host: dbConfig.host,
|
|
8
|
+
user: dbConfig.username,
|
|
9
|
+
password: dbConfig.password,
|
|
10
|
+
port: dbConfig.port,
|
|
11
|
+
database: dbConfig.database,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < params.length; i++) {
|
|
15
|
+
query = query.replace("@" + params[i].name, paramValues[i]);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const [rows, columnData] = await pool.query(query);
|
|
19
|
+
return rows;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
exports.MySQLService = MySQLService;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const neo4j = require('neo4j-driver');
|
|
2
|
+
|
|
3
|
+
class Neo4jService {
|
|
4
|
+
async executeQuery(dbConfig, query, params, paramValues) {
|
|
5
|
+
const uri = `bolt://${dbConfig.host}:${dbConfig.port}`;
|
|
6
|
+
|
|
7
|
+
const driver = neo4j.driver(
|
|
8
|
+
uri,
|
|
9
|
+
neo4j.auth.basic(dbConfig.username, dbConfig.password)
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const session = driver.session({
|
|
13
|
+
database: dbConfig.database || 'neo4j'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const queryParams = {};
|
|
17
|
+
for (let i = 0; i < params.length; i++) {
|
|
18
|
+
queryParams[params[i].name] = paramValues[i];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const result = await session.run(query, queryParams);
|
|
23
|
+
const records = result.records.map(record => record.toObject());
|
|
24
|
+
return records;
|
|
25
|
+
} finally {
|
|
26
|
+
await session.close();
|
|
27
|
+
await driver.close();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
exports.Neo4jService = Neo4jService;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const oracledb = require('oracledb');
|
|
2
|
+
|
|
3
|
+
class OracleService {
|
|
4
|
+
|
|
5
|
+
async executeQuery(dbConfig, query, params, paramValues) {
|
|
6
|
+
let connection;
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
// Create connection
|
|
10
|
+
connection = await oracledb.getConnection({
|
|
11
|
+
user: dbConfig.username,
|
|
12
|
+
password: dbConfig.password,
|
|
13
|
+
connectString: `${dbConfig.host}:${dbConfig.port}/${dbConfig.service_name}`
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Build bind parameters object
|
|
17
|
+
const bindParams = {};
|
|
18
|
+
for (let i = 0; i < params.length; i++) {
|
|
19
|
+
bindParams[params[i].name] = paramValues[i];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Execute query with bind parameters
|
|
23
|
+
const result = await connection.execute(query, bindParams, {
|
|
24
|
+
outFormat: oracledb.OUT_FORMAT_OBJECT, // Return rows as objects
|
|
25
|
+
autoCommit: true
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return result.rows;
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
throw {
|
|
32
|
+
message: `${err.message}`
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
// Always close the connection
|
|
37
|
+
if (connection) {
|
|
38
|
+
try {
|
|
39
|
+
await connection.close();
|
|
40
|
+
} catch (err) {
|
|
41
|
+
console.error('Error closing connection:', err);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
exports.OracleService = OracleService;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const { Pool } = require('pg');
|
|
2
|
+
|
|
3
|
+
class PostgreSQLService {
|
|
4
|
+
|
|
5
|
+
async executeQuery(dbConfig, query, params, paramValues) {
|
|
6
|
+
const pool = new Pool({
|
|
7
|
+
host: dbConfig.host,
|
|
8
|
+
user: dbConfig.username,
|
|
9
|
+
password: dbConfig.password,
|
|
10
|
+
port: dbConfig.port,
|
|
11
|
+
database: dbConfig.database,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Replace named parameters with positional placeholders
|
|
15
|
+
for (let i = 0; i < params.length; i++) {
|
|
16
|
+
query = query.replace("@" + params[i].name, paramValues[i]);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const client = await pool.connect();
|
|
20
|
+
try {
|
|
21
|
+
const result = await client.query(query);
|
|
22
|
+
return result.rows;
|
|
23
|
+
} finally {
|
|
24
|
+
client.release();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.PostgreSQLService = PostgreSQLService;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const { Logger } = require('../utils/logger');
|
|
4
|
+
|
|
5
|
+
const DOWNLOADS_FOLDER = 'downloads';
|
|
6
|
+
|
|
7
|
+
class DownloadsManager {
|
|
8
|
+
|
|
9
|
+
constructor(downloadsConfig, page) {
|
|
10
|
+
this.downloads = [];
|
|
11
|
+
this.overwriteFile = !!downloadsConfig?.overwriteFile;
|
|
12
|
+
this.handleDownloads(page);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
setCaller(caller) {
|
|
16
|
+
this.caller = caller;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
handleDownloads(page) {
|
|
20
|
+
if(!page) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getUniqueFilePath(directory, fileName, overwriteFile) {
|
|
25
|
+
if (!fs.existsSync(directory)) {
|
|
26
|
+
fs.mkdirSync(directory);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const ext = path.extname(fileName);
|
|
30
|
+
let uniqueFilePath = path.join(directory, fileName);
|
|
31
|
+
|
|
32
|
+
if(overwriteFile) {
|
|
33
|
+
return uniqueFilePath;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const baseName = path.basename(fileName, ext);
|
|
37
|
+
let counter = 1;
|
|
38
|
+
while (fs.existsSync(uniqueFilePath)) {
|
|
39
|
+
uniqueFilePath = path.join(directory, `${baseName} (${counter})${ext}`);
|
|
40
|
+
counter++;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return uniqueFilePath;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const handleDownload = async (download) => {
|
|
47
|
+
const fileName = download.suggestedFilename();
|
|
48
|
+
const filePath = getUniqueFilePath(DOWNLOADS_FOLDER, fileName, this.overwriteFile);
|
|
49
|
+
const logMessage = `Downloading file ${fileName}`;
|
|
50
|
+
const logger = new Logger(this.caller);
|
|
51
|
+
logger.startLog(logMessage);
|
|
52
|
+
try {
|
|
53
|
+
let doDownload = async () => {
|
|
54
|
+
fs.writeFileSync(filePath, "");
|
|
55
|
+
await download.saveAs(filePath);
|
|
56
|
+
logger.log(undefined, `Downloaded file saved at ${filePath}`);
|
|
57
|
+
logger.endLog(logMessage);
|
|
58
|
+
};
|
|
59
|
+
const promise = doDownload();
|
|
60
|
+
this.downloads.push({
|
|
61
|
+
fileName: fileName,
|
|
62
|
+
filePath: filePath,
|
|
63
|
+
promise: promise,
|
|
64
|
+
timestamp: Date.now(),
|
|
65
|
+
});
|
|
66
|
+
await promise;
|
|
67
|
+
} catch (ex) {
|
|
68
|
+
if(ex?.message?.includes('context or browser has been closed')) {
|
|
69
|
+
logger.log(undefined, 'Browser closed before download is complete!')
|
|
70
|
+
} else {
|
|
71
|
+
logger.log(undefined, `${ex}`);
|
|
72
|
+
}
|
|
73
|
+
logger.failureLog(logMessage);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
page.on('download', handleDownload);
|
|
78
|
+
|
|
79
|
+
page.context().on('page', async (newPage) => {
|
|
80
|
+
newPage.on('download', handleDownload);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
exports.DownloadsManager = DownloadsManager;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const { sleep } = require("../utils/common-utils");
|
|
2
|
+
const { Logger } = require("../utils/logger");
|
|
3
|
+
|
|
4
|
+
class DownloadsUtils {
|
|
5
|
+
|
|
6
|
+
constructor(caller, blacklistedLogs, downloadsManager) {
|
|
7
|
+
this.caller = caller;
|
|
8
|
+
this.blacklistedLogs = blacklistedLogs;
|
|
9
|
+
this.downloadsManager = downloadsManager;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
setCaller(caller) {
|
|
13
|
+
this.caller = caller;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
setBlacklistedLogs(blacklistedLogs) {
|
|
17
|
+
this.blacklistedLogs = blacklistedLogs;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async wait_for_downloads_complete_ms(timeout) {
|
|
21
|
+
await this.wait_for_downloads_complete(timeout);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async wait_for_downloads_complete(timeout) {
|
|
25
|
+
const logLabel = timeout ?
|
|
26
|
+
`Wait for downloads to complete within ${timeout} ms`
|
|
27
|
+
: `Wait for downloads to complete`;
|
|
28
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
29
|
+
logger.startLog(logLabel);
|
|
30
|
+
|
|
31
|
+
let maxTries = timeout ? timeout / 1000 : 30;
|
|
32
|
+
let count = 0;
|
|
33
|
+
let latestDownloads = [];
|
|
34
|
+
|
|
35
|
+
while(!latestDownloads?.length && count < maxTries) {
|
|
36
|
+
//Filters all downloads in the last 5s
|
|
37
|
+
latestDownloads = this.downloadsManager.downloads
|
|
38
|
+
?.filter(download => download?.timestamp && (Date.now() - download.timestamp <= 5 * 1000));
|
|
39
|
+
count += 1;
|
|
40
|
+
console.log(`No new downloads. Retrying... #${count}`);
|
|
41
|
+
await sleep(1000);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if(!latestDownloads?.length) {
|
|
45
|
+
logger.log(logLabel, `No new download has started in the last ${count}s... You can ignore if the download was triggered earlier!`)
|
|
46
|
+
logger.endLog(logLabel);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const promises = latestDownloads
|
|
51
|
+
?.map(download => download?.promise)
|
|
52
|
+
?.filter(promise => !!promise);
|
|
53
|
+
await Promise.all(promises);
|
|
54
|
+
logger.endLog(logLabel);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async get_last_downloaded_file() {
|
|
58
|
+
const logLabel = `Get last downloaded file`;
|
|
59
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
60
|
+
logger.startLog(logLabel);
|
|
61
|
+
if(!this.downloadsManager?.downloads?.length) {
|
|
62
|
+
logger.failureLog(logLabel)
|
|
63
|
+
throw { message: 'No downloads present!' };
|
|
64
|
+
}
|
|
65
|
+
const download = this.downloadsManager.downloads.at(-1);
|
|
66
|
+
await download.promise;
|
|
67
|
+
logger.endLog(logLabel);
|
|
68
|
+
return download.filePath;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async get_last_downloaded_file_name_match(searchTerm) {
|
|
72
|
+
const logLabel = `Get last downloaded file with name matching ${searchTerm}`;
|
|
73
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
74
|
+
logger.startLog(logLabel);
|
|
75
|
+
if(!this.downloadsManager?.downloads?.length) {
|
|
76
|
+
logger.failureLog(logLabel)
|
|
77
|
+
throw { message: 'No downloads present!' };
|
|
78
|
+
}
|
|
79
|
+
let regex;
|
|
80
|
+
try {
|
|
81
|
+
regex = new RegExp(searchTerm);
|
|
82
|
+
} catch(_ex) {};
|
|
83
|
+
const check = regex
|
|
84
|
+
? (download) => regex.test(download.fileName) || download.fileName?.includes(searchTerm)
|
|
85
|
+
: (download) => download.fileName?.includes(searchTerm);
|
|
86
|
+
const download = this.downloadsManager.downloads.reverse().find(check);
|
|
87
|
+
if(!download) {
|
|
88
|
+
logger.failureLog(logLabel)
|
|
89
|
+
throw { message: 'There are no downloads matching given searchTerm!' };
|
|
90
|
+
}
|
|
91
|
+
await download.promise;
|
|
92
|
+
logger.endLog(logLabel);
|
|
93
|
+
return download.filePath;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async get_all_downloaded_files() {
|
|
97
|
+
const logLabel = `Get all downloaded files`;
|
|
98
|
+
const logger = new Logger(this.caller, this.blacklistedLogs);
|
|
99
|
+
logger.startLog(logLabel);
|
|
100
|
+
if(!this.downloadsManager?.downloads?.length) {
|
|
101
|
+
logger.failureLog(logLabel)
|
|
102
|
+
throw { message: 'No downloads present!' };
|
|
103
|
+
}
|
|
104
|
+
const downloads = this.downloadsManager.downloads
|
|
105
|
+
.filter(download => !!download?.promise && !!download.filePath);
|
|
106
|
+
await Promise.all(downloads.map(download => download.promise));
|
|
107
|
+
logger.endLog(logLabel);
|
|
108
|
+
return downloads.map(download => download.filePath);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
exports.DownloadsUtils = DownloadsUtils;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const { chromium } = require('@playwright/test');
|
|
2
|
+
const { openBrowser, importGetHooks } = require('./hooks/hook-utils');
|
|
3
|
+
const { startAppiumServers } = require('./mobile/appium/appium-manager');
|
|
4
|
+
const { FileUtils } = require('./library/file/file-utils');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { getAutohealPath } = require('./utils/autoheal-utils');
|
|
7
|
+
|
|
8
|
+
async function globalSetup(config) {
|
|
9
|
+
const packageInfo = require('.././package.json');
|
|
10
|
+
console.log('Engine version : ', packageInfo?.version);
|
|
11
|
+
|
|
12
|
+
await new FileUtils().writeJSONContent(getAutohealPath(), {});
|
|
13
|
+
|
|
14
|
+
let playwrightConfig;
|
|
15
|
+
if(config?.configFile) {
|
|
16
|
+
playwrightConfig = require(config.configFile);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if(playwrightConfig?.customConfig?.testType === 'web' ) {
|
|
20
|
+
const channels = config.projects.map(project => project.use.channel).filter(c => !!c);
|
|
21
|
+
for (let i = 0; i < channels.length; i++) {
|
|
22
|
+
const channel = channels[i];
|
|
23
|
+
try {
|
|
24
|
+
const browser = await chromium.launch({ channel: channel });
|
|
25
|
+
await browser.close();
|
|
26
|
+
} catch(ex) {
|
|
27
|
+
console.log(`[[TPP]] Error launching ${channel} !!! Make sure browser is installed. :: [ERROR]`);
|
|
28
|
+
throw {message: `Browser ${channel} not installed!`};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if(playwrightConfig?.customConfig?.chromeExtension) {
|
|
32
|
+
console.log(`[[TPP_PRINT_ONLY]] 🌐 Only Chromium Browser will be used as Chrome Extension is enabled!`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//TODO move to separate hook for mobile
|
|
37
|
+
//Start Appium
|
|
38
|
+
|
|
39
|
+
if(playwrightConfig?.customConfig?.testType === 'mobile'
|
|
40
|
+
&& !playwrightConfig.customConfig.mobileConfig?.deviceCloud
|
|
41
|
+
) {
|
|
42
|
+
console.log(`[[TPP_PRINT_ONLY]] 📱 Mobile setup :: [BEGIN]`);
|
|
43
|
+
await startAppiumServers(playwrightConfig.customConfig.mobileConfig.appiumStartScript, playwrightConfig.workers || 1);
|
|
44
|
+
console.log(`[[TPP_PRINT_ONLY]] 📱 Mobile setup :: [END]`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let getHooks = importGetHooks();
|
|
48
|
+
if(!getHooks) return;
|
|
49
|
+
|
|
50
|
+
const actions = await openBrowser();
|
|
51
|
+
const hooks = getHooks(actions);
|
|
52
|
+
if(!hooks?.find(hook => hook?.beforeAll)) return;
|
|
53
|
+
|
|
54
|
+
let exception;
|
|
55
|
+
try {
|
|
56
|
+
actions.setCaller('', 'BeforeAll');
|
|
57
|
+
actions.testStartLog();
|
|
58
|
+
for (let i = 0; i < hooks.length; i++) {
|
|
59
|
+
const hook = hooks[i];
|
|
60
|
+
hook?.beforeAll && await hook.beforeAll();
|
|
61
|
+
}
|
|
62
|
+
} catch(ex) {
|
|
63
|
+
exception = ex;
|
|
64
|
+
}
|
|
65
|
+
await actions.handleResult(exception);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
exports.default = globalSetup;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const { generateCombinedA11yReport } = require('./accessibility/combined-a11y-report');
|
|
2
|
+
const { openBrowser, importGetHooks } = require('./hooks/hook-utils');
|
|
3
|
+
const { FileUtils } = require('./library/file/file-utils');
|
|
4
|
+
const { stopAppiumServers, resetAppiumConfig } = require('./mobile/appium/appium-manager');
|
|
5
|
+
const { getAutohealPath } = require('./utils/autoheal-utils');
|
|
6
|
+
const { resetTokenFile } = require("./utils/token-utils");
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
async function globalTeardown(config) {
|
|
10
|
+
resetTokenFile();
|
|
11
|
+
generateCombinedA11yReport();
|
|
12
|
+
|
|
13
|
+
await new FileUtils().deleteFile(getAutohealPath());
|
|
14
|
+
//TODO move to separate hook for mobile
|
|
15
|
+
//Stop Appium
|
|
16
|
+
let playwrightConfig;
|
|
17
|
+
if(config?.configFile) {
|
|
18
|
+
playwrightConfig = require(config.configFile);
|
|
19
|
+
}
|
|
20
|
+
if(playwrightConfig.customConfig?.testType === 'mobile'
|
|
21
|
+
&& !playwrightConfig.customConfig?.mobileConfig?.deviceCloud
|
|
22
|
+
) {
|
|
23
|
+
console.log(`[[TPP_PRINT_ONLY]] Mobile teardown :: [BEGIN]`);
|
|
24
|
+
await stopAppiumServers();
|
|
25
|
+
resetAppiumConfig();
|
|
26
|
+
console.log(`[[TPP_PRINT_ONLY]] Mobile teardown :: [END]`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let getHooks = importGetHooks();
|
|
30
|
+
if(!getHooks) return;
|
|
31
|
+
|
|
32
|
+
const actions = await openBrowser();
|
|
33
|
+
const hooks = getHooks(actions);
|
|
34
|
+
if(!hooks?.find(hook => hook?.afterAll)) {
|
|
35
|
+
await closBrowser();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let exception;
|
|
40
|
+
try {
|
|
41
|
+
actions.setCaller('', 'AfterAll');
|
|
42
|
+
actions.testStartLog();
|
|
43
|
+
for (let i = 0; i < hooks.length; i++) {
|
|
44
|
+
const hook = hooks[i];
|
|
45
|
+
hook?.afterAll && await hook.afterAll();
|
|
46
|
+
}
|
|
47
|
+
} catch(ex) {
|
|
48
|
+
exception = ex;
|
|
49
|
+
}
|
|
50
|
+
await actions.handleResult(exception);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function closBrowser(action) {
|
|
54
|
+
await action?.page?.context()?.browser()?.close();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
exports.default = globalTeardown;
|