@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.
Files changed (68) hide show
  1. package/README.md +18 -2
  2. package/index.js +121 -0
  3. package/package.json +30 -4
  4. package/src/accessibility/combined-a11y-report.js +208 -0
  5. package/src/accessibility/tpp-a11y.js +81 -0
  6. package/src/actions.js +3201 -0
  7. package/src/api/api-auth.js +18 -0
  8. package/src/api/api-service.js +289 -0
  9. package/src/app-config.json +7 -0
  10. package/src/autoheal-actions.js +309 -0
  11. package/src/console-log/console-log-manager.js +39 -0
  12. package/src/console-log/console-log-utils.js +201 -0
  13. package/src/database/mysql/mysql-service.js +23 -0
  14. package/src/database/neo4j/neo4j-service.js +32 -0
  15. package/src/database/oracle/oracle-service.js +48 -0
  16. package/src/database/pg/pg-service.js +29 -0
  17. package/src/downloads/downloads-manager.js +86 -0
  18. package/src/downloads/downloads-utils.js +113 -0
  19. package/src/globalsetup.js +68 -0
  20. package/src/globalteardown.js +57 -0
  21. package/src/hooks/each-hook.js +45 -0
  22. package/src/hooks/hook-utils.js +21 -0
  23. package/src/library/authenticator/authenticator-utils.js +43 -0
  24. package/src/library/csv/csv-utils.js +297 -0
  25. package/src/library/date/date-utils.js +168 -0
  26. package/src/library/emailTesting/TokenConfig.js +46 -0
  27. package/src/library/emailTesting/emailTesting-utils.js +527 -0
  28. package/src/library/excel/excel-utils.js +922 -0
  29. package/src/library/file/file-action-utils.js +129 -0
  30. package/src/library/file/file-utils.js +127 -0
  31. package/src/library/json/json-utils.js +104 -0
  32. package/src/library/math/math-utils.js +283 -0
  33. package/src/library/softAssert/softAssert-utils.js +154 -0
  34. package/src/library/table/table-utils.js +92 -0
  35. package/src/library/text/text-utils.js +45 -0
  36. package/src/library/tpp-library.js +81 -0
  37. package/src/library/web/slider-utils.js +66 -0
  38. package/src/mobile/appium/appium-manager.js +158 -0
  39. package/src/mobile/device-cloud/browserstack-service.js +44 -0
  40. package/src/mobile/device-cloud/commands/browserstack-commands.js +20 -0
  41. package/src/mobile/device-cloud/commands/device-cloud-commands.js +17 -0
  42. package/src/mobile/device-cloud/device-cloud-service.js +29 -0
  43. package/src/mobile/device-cloud/pcloudy-service.js +65 -0
  44. package/src/mobile/mobile-actions.js +1568 -0
  45. package/src/mobile/recorder-utils/css-selector-generator.js +2 -0
  46. package/src/mobile/recorder-utils/finder.js +752 -0
  47. package/src/mobile/recorder-utils/mobile-recorder.js +266 -0
  48. package/src/mobile/web-driver-utils.js +110 -0
  49. package/src/models/tpp-element.js +58 -0
  50. package/src/models/tpp-mobile-element.js +50 -0
  51. package/src/network-log/network-log-manager.js +96 -0
  52. package/src/network-log/network-log-utils.js +361 -0
  53. package/src/types/elements.types.js +24 -0
  54. package/src/utils/ai-utils.js +48 -0
  55. package/src/utils/assert-utils.js +50 -0
  56. package/src/utils/autoheal-utils.js +9 -0
  57. package/src/utils/common-utils.js +120 -0
  58. package/src/utils/cookie-utils.js +70 -0
  59. package/src/utils/json-utils.js +10 -0
  60. package/src/utils/log-utils.js +10 -0
  61. package/src/utils/logger.js +76 -0
  62. package/src/utils/screenshot-utils.js +42 -0
  63. package/src/utils/token-utils.js +18 -0
  64. package/src/utils/vectordb-utils.js +125 -0
  65. package/src/visual-test/tpp-visual-test.js +122 -0
  66. package/src/web/web-executor-agent.js +149 -0
  67. package/src/web/web-executor-data-fetch.js +353 -0
  68. package/test-excel-utils.js +570 -0
@@ -0,0 +1,527 @@
1
+ const { Logger, LOG_PREFIX } = require("../../utils/logger");
2
+ const axios = require('axios');
3
+ const TokenConfig = require('./TokenConfig');
4
+ const config = require('../../app-config.json');
5
+
6
+ const WEBAPP_API_BASE = config.webAppUrl;
7
+
8
+ class EmailTestingUtils{
9
+
10
+ constructor(caller, blacklistedLogs, takeScreenShot, page) {
11
+ this.caller = caller;
12
+ this.blacklistedLogs = blacklistedLogs;
13
+ this.takeScreenShot = takeScreenShot;
14
+ this.page = page;
15
+ }
16
+
17
+ setCaller(caller) {
18
+ this.caller = caller;
19
+ }
20
+
21
+ setBlacklistedLogs(blacklistedLogs) {
22
+ this.blacklistedLogs = blacklistedLogs;
23
+ }
24
+
25
+ setPage(page) {
26
+ this.page = page;
27
+ }
28
+
29
+ async open_html_in_browser(html){
30
+ await this.page.goto('about:blank');
31
+ await this.page.setContent(html, {
32
+ waitUntil: 'networkidle'
33
+ });
34
+ await this.page.evaluate((title) => {
35
+ document.title = title;
36
+ }, "Email Viewer");
37
+ }
38
+
39
+ async initializeConfig() {
40
+ if (!this.config) {
41
+ this.config = await TokenConfig.getConfig();
42
+ }
43
+ return this.config;
44
+ }
45
+
46
+ async getAuthHeaders() {
47
+ const config = await this.initializeConfig();
48
+ return {
49
+ 'Content-Type': 'application/json',
50
+ 'Authorization': `${config.token_type} ${config.access_token}`
51
+ };
52
+ }
53
+
54
+ async getOfflineStatus() {
55
+ const config = await this.initializeConfig();
56
+ return config.offline;
57
+ }
58
+
59
+ async create_testing_mail_id(prefix = '', mail_id_type = 'Automation') {
60
+ const logLabel = `Create Testing Mail ID`;
61
+ const logger = new Logger(this.caller, this.blacklistedLogs);
62
+ logger.startLog(logLabel);
63
+
64
+ try {
65
+ const offline = await this.getOfflineStatus();
66
+ if (offline) {
67
+ this.handle_offline_mode();
68
+ return;
69
+ }
70
+
71
+ const response = await axios.post(
72
+ `${WEBAPP_API_BASE}/testing_mail_ids`,
73
+ {
74
+ prefix,
75
+ mail_id_type,
76
+ },
77
+ {
78
+ headers: await this.getAuthHeaders()
79
+ }
80
+ );
81
+
82
+ if (response.status > 201) {
83
+ const errorMessage = `Failed to create testing mail id, status code: ${response.status}`;
84
+ throw {
85
+ status: response.status,
86
+ message: errorMessage,
87
+ response_data: response.data
88
+ };
89
+ }
90
+
91
+ const createdMailId = response.data.mail_id;
92
+ logger.endLog(logLabel);
93
+ return createdMailId;
94
+ } catch (error) {
95
+ let errorMessage = error.response
96
+ ? `Error creating testing mail id: ${error.response.data.error || error.response.data.message}`
97
+ : `Unexpected error: ${error.message}`;
98
+
99
+ if(errorMessage.includes('MailTestSetting is disabled')) {
100
+ errorMessage = 'EmailTesting is disabled! Enable Email testing from DevAssure web portal.';
101
+ }
102
+
103
+ logger.failureLog(logLabel);
104
+
105
+ throw {
106
+ status: error.response ? error.response.status : 500,
107
+ message: errorMessage,
108
+ details: error.response ? error.response.data : {}
109
+ };
110
+ }
111
+ }
112
+
113
+
114
+ async create_testing_mail_id_with_prefix(prefix){
115
+ let created_mail_id = await this.create_testing_mail_id(prefix);
116
+ return created_mail_id;
117
+ }
118
+
119
+ async fetchEmails(url) {
120
+ try {
121
+ const response = await axios.get(url, {
122
+ headers: await this.getAuthHeaders(),
123
+ });
124
+ return response.data.emails;
125
+ } catch (error) {
126
+ const status = error.response?.status || 500;
127
+ const message = error.response?.data?.error || error.message || "Unknown error occurred";
128
+ throw { status, message };
129
+ }
130
+ }
131
+
132
+ async get_emails_for_recipient(mail_id, limit = 1, logLabel) {
133
+ const logger = new Logger(this.caller, this.blacklistedLogs);
134
+ logger.startLog(logLabel);
135
+
136
+ try {
137
+ const offline = await this.getOfflineStatus();
138
+ if (offline) {
139
+ this.handle_offline_mode();
140
+ return;
141
+ }
142
+ let url = `${WEBAPP_API_BASE}/testing_mail_ids/emails/recipient/${mail_id}`;
143
+ if (limit > 0) {
144
+ url += `?limit=${limit}`;
145
+ }
146
+
147
+ const emails = await this.fetchEmails(url);
148
+ if (emails.length === 0) {
149
+ const message = `No emails found for the email ID: ${mail_id}`;
150
+ throw { status: 404, message };
151
+ }
152
+ logger.endLog(logLabel);
153
+ return emails;
154
+ } catch (error) {
155
+ const status = error.status || 500;
156
+ const message = error.message || "Error fetching emails for recipient";
157
+ logger.failureLog(logLabel);
158
+ throw { status, message };
159
+ }
160
+ }
161
+
162
+ async get_last_email_for_recipient (mail_id) {
163
+ const logLabel = `Get last email for recipient`;
164
+ let email = await this.get_emails_for_recipient (mail_id,1,logLabel);
165
+ return email;
166
+ }
167
+
168
+ async get_last_n_emails_for_recipient (limit, mail_id) {
169
+ const logLabel = `Get last ${limit} emails for recipient`;
170
+ let emails = await this.get_emails_for_recipient (mail_id,limit, logLabel);
171
+ return emails;
172
+ }
173
+
174
+ async get_last_n_emails_with_verification (limit, mail_id, from, subject) {
175
+ const logLabel = `Get last ${limit} emails with matching subject and from address`;
176
+ const logger = new Logger(this.caller, this.blacklistedLogs);
177
+ logger.startLog(logLabel);
178
+
179
+ try {
180
+ const offline = await this.getOfflineStatus();
181
+ if (offline) {
182
+ this.handle_offline_mode();
183
+ return;
184
+ }
185
+
186
+ let url = `${WEBAPP_API_BASE}/testing_mail_ids/emails/recipient/${mail_id}`;
187
+
188
+ const emails = await this.verifySubForEmails(url, from, subject,limit);
189
+
190
+ if (emails.length === 0) {
191
+ const errorMessage = `No matching emails found for mail_id: ${mail_id}`;
192
+ throw {
193
+ status: 404,
194
+ message: errorMessage,
195
+ mail_id,
196
+ };
197
+ }
198
+
199
+ logger.log(logLabel,`Successfully validated email subject and from address.`);
200
+ logger.endLog(logLabel);
201
+ return emails;
202
+ } catch (error) {
203
+ logger.failureLog(logLabel);
204
+ throw {
205
+ status: error.status || 500,
206
+ message: error.message || 'Unexpected error while verifying email.',
207
+ details: error.details || {},
208
+ };
209
+ }
210
+ }
211
+
212
+ async verifySubForEmails(url, from_address, subject, limit) {
213
+ try {
214
+ const fromRegex = new RegExp(from_address, 'i');
215
+ const subRegex = new RegExp(subject, 'i');
216
+ const emails = await this.fetchEmails(url);
217
+ const matchingEmails = [];
218
+
219
+ for (const email of emails) {
220
+ if (fromRegex.test(email.from_address) && subRegex.test(email.subject)) {
221
+ matchingEmails.push(email);
222
+
223
+ if (matchingEmails.length >= limit) {
224
+ break;
225
+ }
226
+ }
227
+ }
228
+
229
+ return matchingEmails;
230
+ } catch (error) {
231
+ return [];
232
+ }
233
+ }
234
+
235
+ async wait_for_email(mail_id, timeout, limit = 1) {
236
+ const logLabel = `Wait for Email`;
237
+ const logger = new Logger(this.caller, this.blacklistedLogs);
238
+ logger.startLog(logLabel);
239
+
240
+ try {
241
+ const offline = await this.getOfflineStatus();
242
+ if (offline) {
243
+ this.handle_offline_mode();
244
+ return;
245
+ }
246
+
247
+ let url = `${WEBAPP_API_BASE}/testing_mail_ids/emails/recipient/${mail_id}`;
248
+ if (limit > 0) {
249
+ url += `?limit=${limit}`;
250
+ }
251
+
252
+ const emails = await this.pollForEmails(url, timeout, logLabel);
253
+
254
+ if (emails.length > 0) {
255
+ logger.log(logLabel,`Successfully found email(s) for ${mail_id}`);
256
+ logger.endLog(logLabel);
257
+ return emails;
258
+ }
259
+
260
+ const message = `No emails found for recipient ${mail_id} within the timeout of ${timeout / 1000} seconds.`;
261
+ throw {
262
+ status: 404,
263
+ message,
264
+ };
265
+ } catch (error) {
266
+ logger.failureLog(logLabel);
267
+ throw {
268
+ status: error.status || 500,
269
+ message: error.message || `Unexpected error while waiting for email.`,
270
+ };
271
+ }
272
+ }
273
+
274
+ async wait_for_email_with_verification(mail_id, fromRegex, subRegex, timeout, limit = 0) {
275
+ const logLabel = `Wait for Email with subject and from address`;
276
+ const logger = new Logger(this.caller, this.blacklistedLogs);
277
+ logger.startLog(logLabel);
278
+
279
+ try {
280
+ const offline = await this.getOfflineStatus();
281
+ if (offline) {
282
+ this.handle_offline_mode();
283
+ return;
284
+ }
285
+
286
+ let url = `${WEBAPP_API_BASE}/testing_mail_ids/emails/recipient/${mail_id}`;
287
+ if (limit > 0) {
288
+ url += `?limit=${limit}`;
289
+ }
290
+
291
+ const emails = await this.pollForEmailsWithFromAddressAndSubject(url, timeout, logLabel,fromRegex,subRegex);
292
+
293
+ if (emails.length === 0) {
294
+ const errorMessage = `No matching emails found for mail_id: ${mail_id} within ${timeout / 1000} seconds.`;
295
+ throw {
296
+ status: 404,
297
+ message: errorMessage,
298
+ mail_id,
299
+ timeout,
300
+ };
301
+ }
302
+
303
+ logger.log(logLabel,`Successfully validated email subject and from address.`);
304
+ logger.endLog(logLabel);
305
+ return emails;
306
+ } catch (error) {
307
+ logger.failureLog(logLabel);
308
+ throw {
309
+ status: error.status || 500,
310
+ message: error.message || 'Unexpected error while verifying email.',
311
+ details: error.details || {},
312
+ };
313
+ }
314
+ }
315
+
316
+ async pollForEmails(url, timeout, logLabel) {
317
+ const logger = new Logger(this.caller, this.blacklistedLogs);
318
+ const totalSeconds = Math.ceil(timeout / 1000);
319
+ const delay = 1000;
320
+
321
+ for (let attempt = 0; attempt < totalSeconds; attempt++) {
322
+ try {
323
+ const emails = await this.fetchEmails(url);
324
+
325
+ if (emails.length > 0) {
326
+ logger.log(logLabel,`Email(s) found after ${attempt + 1} second(s).`);
327
+ return emails;
328
+ }
329
+
330
+ if (attempt < totalSeconds - 1) {
331
+ await new Promise((resolve) => setTimeout(resolve, delay));
332
+ }
333
+ } catch (error) {
334
+ if (attempt === totalSeconds - 1) {
335
+ logger.failureLog(logLabel);
336
+ throw new Error(
337
+ `Failed to fetch emails after ${totalSeconds} attempts: ${error.message}`
338
+ );
339
+ }
340
+ }
341
+ }
342
+ logger.log(logLabel,`No emails found after ${totalSeconds} second(s).`);
343
+ return [];
344
+ }
345
+
346
+ async pollForEmailsWithFromAddressAndSubject(url, timeout, logLabel, from_address, subject) {
347
+ const logger = new Logger(this.caller, this.blacklistedLogs);
348
+ const delay = 1000;
349
+ const startTime = Date.now();
350
+
351
+ const fromRegex = new RegExp(from_address, 'i');
352
+ const subRegex = new RegExp(subject, 'i');
353
+
354
+ while (true) {
355
+ try {
356
+ const emails = await this.fetchEmails(url);
357
+
358
+ if (emails.length > 0) {
359
+ const matchingEmail = emails.find(email =>
360
+ fromRegex.test(email.from_address) && subRegex.test(email.subject)
361
+ );
362
+
363
+ if (matchingEmail) {
364
+ logger.log(logLabel, `Matching email found after ${(Date.now() - startTime) / 1000} second(s).`);
365
+ return matchingEmail;
366
+ }
367
+ }
368
+
369
+ if (Date.now() - startTime >= timeout) {
370
+ break;
371
+ }
372
+
373
+ await new Promise((resolve) => setTimeout(resolve, delay));
374
+ } catch (error) {
375
+ logger.failureLog(logLabel);
376
+ throw new Error(`Failed to fetch emails: ${error.message}`);
377
+ }
378
+ }
379
+
380
+ logger.log(logLabel, `No matching email found after ${(Date.now() - startTime) / 1000} second(s).`);
381
+ return [];
382
+ }
383
+
384
+ async get_subject(emailTest){
385
+ const logLabel = `Get Subject From email`;
386
+ const logger = new Logger(this.caller, this.blacklistedLogs);
387
+ logger.startLog(logLabel);
388
+ const email = this.extractEmail(emailTest);
389
+ if (!email) {
390
+ logger.failureLog(logLabel);
391
+ throw { message: 'Invalid email object' };
392
+ }
393
+ logger.endLog(logLabel);
394
+ return email.subject;
395
+ }
396
+
397
+ async get_content(emailTest){
398
+ const logLabel = `Get Content From email`;
399
+ const logger = new Logger(this.caller, this.blacklistedLogs);
400
+ logger.startLog(logLabel);
401
+ const email = this.extractEmail(emailTest);
402
+ if (!email) {
403
+ logger.failureLog(logLabel);
404
+ throw { message: 'Invalid email object' };
405
+ }
406
+ logger.endLog(logLabel);
407
+ return email.content;
408
+ }
409
+
410
+ async get_from_address(emailTest){
411
+ const logLabel = `Get from address From email`;
412
+ const logger = new Logger(this.caller, this.blacklistedLogs);
413
+ logger.startLog(logLabel);
414
+ const email = this.extractEmail(emailTest);
415
+ if (!email) {
416
+ logger.failureLog(logLabel);
417
+ throw { message: 'Invalid email object' };
418
+ }
419
+ logger.endLog(logLabel);
420
+ return email.from_address;
421
+ }
422
+
423
+ async delete_all_emails(mail_id) {
424
+ const logLabel = `Delete All Emails`;
425
+ const logger = new Logger(this.caller, this.blacklistedLogs);
426
+ logger.startLog(logLabel);
427
+
428
+ try {
429
+ const offline = await this.getOfflineStatus();
430
+ if (offline) {
431
+ this.handle_offline_mode();
432
+ return;
433
+ }
434
+
435
+ const url = `${WEBAPP_API_BASE}/testing_mail_ids/emails/recipient/${mail_id}`;
436
+
437
+ const response = await axios.delete(url, {
438
+ headers: await this.getAuthHeaders(),
439
+ });
440
+
441
+ if (response.status > 201) {
442
+ const errorMessage = `Failed to delete emails for recipient ${mail_id}. Response code: ${response.status}`;
443
+ throw {
444
+ status: response.status,
445
+ message: errorMessage,
446
+ mail_id,
447
+ response_data: response.data,
448
+ };
449
+ }
450
+
451
+ logger.endLog(logLabel);
452
+ return response.data;
453
+ } catch (error) {
454
+ const errorMessage = error.response
455
+ ? `Error deleting emails: ${error.response.data.error}`
456
+ : `Unexpected error: ${error.message}`;
457
+
458
+ logger.failureLog(logLabel);
459
+
460
+ throw {
461
+ status: error.response ? error.response.status : 500,
462
+ message: errorMessage,
463
+ mail_id,
464
+ details: error.response ? error.response.data : {},
465
+ };
466
+ }
467
+ }
468
+
469
+
470
+ async open_email_in_browser(emailTest, type = 'html') {
471
+ const logLabel = `Open Email in Browser`;
472
+ const logger = new Logger(this.caller, this.blacklistedLogs);
473
+ logger.startLog(logLabel);
474
+
475
+ try {
476
+ const offline = await this.getOfflineStatus();
477
+ if (offline) {
478
+ this.handle_offline_mode();
479
+ return;
480
+ }
481
+
482
+ const email = this.extractEmail(emailTest);
483
+ if (!email) {
484
+ throw { message: 'Invalid email object' };
485
+ }
486
+ const message_id = email.message_id;
487
+ const response = await axios.get(
488
+ `${WEBAPP_API_BASE}/testing_mail_ids/email_content`,
489
+ {
490
+ params: { message_id, type },
491
+ headers: await this.getAuthHeaders()
492
+ }
493
+ );
494
+
495
+ if (response.status > 201 || !response.data.content) {
496
+ throw { message: 'Failed to fetch email content' };
497
+ }
498
+
499
+ const emailContent = response.data.content;
500
+
501
+ await this.open_html_in_browser(emailContent);
502
+ logger.endLog(logLabel);
503
+
504
+ } catch (error) {
505
+ logger.failureLog(logLabel);
506
+ throw { message: `Error opening email in browser: ${error.message}` };
507
+ }
508
+ }
509
+
510
+
511
+ extractEmail(emailTest) {
512
+ if (Array.isArray(emailTest)) {
513
+ if (!emailTest?.length) {
514
+ throw { message: 'Email array is empty!' };
515
+ }
516
+ return emailTest.at(-1);
517
+ }
518
+ return emailTest;
519
+ }
520
+
521
+ handle_offline_mode(){
522
+ throw {message: `Email testing actions should not be proceeded with offline`}
523
+ }
524
+
525
+ }
526
+
527
+ exports.EmailTestingUtils = EmailTestingUtils;