froth-webdriverio-framework 7.0.17 → 7.0.19
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/froth_common_actions_back/Utils.js +167 -0
- package/froth_common_actions_back/alert.js +49 -0
- package/froth_common_actions_back/apicall.js +179 -0
- package/froth_common_actions_back/assert.js +85 -0
- package/froth_common_actions_back/captureNavigationTime.js +53 -0
- package/froth_common_actions_back/click.js +57 -0
- package/froth_common_actions_back/dropDown.js +34 -0
- package/froth_common_actions_back/emailParsing.js +161 -0
- package/froth_common_actions_back/jwt.js +64 -0
- package/froth_common_actions_back/logData.js +73 -0
- package/froth_common_actions_back/random.js +230 -0
- package/froth_common_actions_back/scroll.js +104 -0
- package/froth_common_actions_back/storeToBuffer.js +45 -0
- package/froth_common_actions_back/swicthWindowTab.js +36 -0
- package/froth_common_actions_back/swipe.js +219 -0
- package/froth_configs/commonhook.js +1 -1
- package/froth_configs_back/commonconfig.js +409 -0
- package/froth_configs_back/setallDatailinBuffer.js +100 -0
- package/froth_configs_back/wdio.common.conf.js +53 -0
- package/froth_configs_back/wdio.common.conf_back.js +138 -0
- package/package.json +36 -22
- package/browserstack.err +0 -1
- package/buffer_storage/FROTHE_SUITE_DETAILS +0 -1
- package/buffer_storage/FROTH_EXECUTION_ID +0 -1
- package/buffer_storage/FROTH_LOGIN_TOKEN +0 -1
- package/buffer_storage/FROTH_TOTAL_DURATION +0 -1
- package/buffer_storage/ORGANISATION_DOMAIN_URL +0 -1
- package/froth_configs/commonhook copy.js +0 -38
- package/froth_configs/commonhook_with_old_code.js +0 -425
- package/froth_configs/wdio.common.conf copy.js +0 -57
- package/local.log +0 -8
- package/log/key-metrics.json +0 -4853
- package/log/sdk-cli-debug.log +0 -122
- package/log/sdk-cli.log +0 -16974
- package/log/sdk-debug-utility.log +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Switches to a browser window/tab by its title using WebdriverIO.
|
|
3
|
+
* @param {string} title - The title of the window/tab to switch to.
|
|
4
|
+
*/
|
|
5
|
+
async function switch2WindowByTitle(title) {
|
|
6
|
+
const handles = await browser.getWindowHandles();
|
|
7
|
+
for (const handle of handles) {
|
|
8
|
+
await browser.switchToWindow(handle);
|
|
9
|
+
const currentTitle = await browser.getTitle();
|
|
10
|
+
if (currentTitle === title) {
|
|
11
|
+
return true; // Switched successfully
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
throw new Error(`No window with title "${title}" found.`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Switches to a browser window/tab by its index using WebdriverIO.
|
|
19
|
+
* @param {number} index - The index of the window/tab to switch to (0-based).
|
|
20
|
+
*/
|
|
21
|
+
async function switch2WindowByIndex(index) {
|
|
22
|
+
const handles = await browser.getWindowHandles();
|
|
23
|
+
console.log(`Total open windows: ${handles.length}`);
|
|
24
|
+
console.log(`Switching to window at index: ${index}`);
|
|
25
|
+
console.log(`Available handles: ${handles.join(', ')}`);
|
|
26
|
+
if (index < 0 || index >= handles.length) {
|
|
27
|
+
throw new Error(`Invalid window index: ${index}. There are only ${handles.length} windows open.`);
|
|
28
|
+
}
|
|
29
|
+
await browser.switchToWindow(handles[index]);
|
|
30
|
+
return true; // Switched successfully
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
// Example usage in a test
|
|
35
|
+
// await switchToWindowByTitle('Your Window Title');
|
|
36
|
+
module.exports = {switch2WindowByTitle,switch2WindowByIndex};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
async function swipeleft(selector, xoffset, speedinsec) {
|
|
2
|
+
try {
|
|
3
|
+
console.log('Swiping left');
|
|
4
|
+
|
|
5
|
+
if (xoffset == null) {
|
|
6
|
+
driver.swipeLeft(selector, speedinsec);
|
|
7
|
+
} else {
|
|
8
|
+
driver.swipeLeft(selector, xoffset, speedinsec);
|
|
9
|
+
}
|
|
10
|
+
} catch (error) {
|
|
11
|
+
console.error(error.message);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function swiperight(selector, xoffset, speedinsec) {
|
|
17
|
+
try {
|
|
18
|
+
console.log('Swiping right');
|
|
19
|
+
|
|
20
|
+
if (xoffset == null) {
|
|
21
|
+
driver.swipeRight(selector, speedinsec);
|
|
22
|
+
} else {
|
|
23
|
+
driver.swipeRight(selector, xoffset, speedinsec);
|
|
24
|
+
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error(error.message);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function swipeup(selector, yoffset, speedinsec) {
|
|
32
|
+
try {
|
|
33
|
+
console.log('Swiping up');
|
|
34
|
+
|
|
35
|
+
if (yoffset == null) {
|
|
36
|
+
driver.swipeUp(selector, speedinsec);
|
|
37
|
+
} else {
|
|
38
|
+
driver.swipeUp(selector, yoffset, speedinsec);
|
|
39
|
+
}
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(error.message);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function swipedown(selector, yoffset, speedinsec) {
|
|
46
|
+
try {
|
|
47
|
+
console.log('Swiping down');
|
|
48
|
+
|
|
49
|
+
if (yoffset == null) {
|
|
50
|
+
driver.swipeDown(selector, speedinsec);
|
|
51
|
+
} else {
|
|
52
|
+
driver.swipeDown(selector, yoffset, speedinsec);
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error(error.message);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function swipewithcoordinates(StartX, StartY, EndX, EndY) {
|
|
60
|
+
|
|
61
|
+
await driver.performActions([
|
|
62
|
+
{
|
|
63
|
+
type: "pointer",
|
|
64
|
+
id: "finger1",
|
|
65
|
+
parameters: { pointerType: "touch" },
|
|
66
|
+
actions: [
|
|
67
|
+
{ type: "pointerMove", duration: 0, x: StartX, y: StartY },
|
|
68
|
+
{ type: "pointerDown", button: 0 },
|
|
69
|
+
{ type: "pause", duration: 300 },
|
|
70
|
+
{ type: "pointerMove", duration: 1000, x: EndX, y: EndY },
|
|
71
|
+
{ type: "pointerUp", button: 0 }
|
|
72
|
+
],
|
|
73
|
+
}
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
async function swipetofit() {
|
|
77
|
+
// Get screen size dynamically
|
|
78
|
+
const screenSize = await driver.getWindowRect();
|
|
79
|
+
const screenWidth = screenSize.width;
|
|
80
|
+
const screenHeight = screenSize.height;
|
|
81
|
+
|
|
82
|
+
console.log(`Screen Size: Width=${screenWidth}, Height=${screenHeight}`);
|
|
83
|
+
|
|
84
|
+
// Define approximate positions for corners
|
|
85
|
+
const topRightStartX = screenWidth * 0.88; // Top-right corner
|
|
86
|
+
const topRightStartY = screenHeight * 0.44;
|
|
87
|
+
|
|
88
|
+
const topRightEndX = screenWidth * 0.96; // Expand to the right
|
|
89
|
+
const topRightEndY = screenHeight * 0.39; // Move upwards slightly
|
|
90
|
+
|
|
91
|
+
const bottomLeftStartX = screenWidth * 0.12; // Bottom-left corner
|
|
92
|
+
const bottomLeftStartY = screenHeight * 0.69;
|
|
93
|
+
|
|
94
|
+
const bottomLeftEndX = screenWidth * 0.014; // Expand to the left
|
|
95
|
+
const bottomLeftEndY = screenHeight * 0.73; // Move down slightly
|
|
96
|
+
|
|
97
|
+
console.log(`Resizing top-right from (${topRightStartX}, ${topRightStartY}) to (${topRightEndX}, ${topRightEndY})`);
|
|
98
|
+
console.log(`Resizing bottom-left from (${bottomLeftStartX}, ${bottomLeftStartY}) to (${bottomLeftEndX}, ${bottomLeftEndY})`);
|
|
99
|
+
|
|
100
|
+
// Resize from top-right corner
|
|
101
|
+
await driver.performActions([
|
|
102
|
+
{
|
|
103
|
+
type: "pointer",
|
|
104
|
+
id: "finger1",
|
|
105
|
+
parameters: { pointerType: "touch" },
|
|
106
|
+
actions: [
|
|
107
|
+
{ type: "pointerMove", duration: 0, x: topRightStartX, y: topRightStartY },
|
|
108
|
+
{ type: "pointerDown", button: 0 },
|
|
109
|
+
{ type: "pause", duration: 300 },
|
|
110
|
+
{ type: "pointerMove", duration: 1000, x: topRightEndX, y: topRightEndY },
|
|
111
|
+
{ type: "pointerUp", button: 0 }
|
|
112
|
+
],
|
|
113
|
+
}
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
// Resize from bottom-left corner
|
|
117
|
+
await driver.performActions([
|
|
118
|
+
{
|
|
119
|
+
type: "pointer",
|
|
120
|
+
id: "finger2",
|
|
121
|
+
parameters: { pointerType: "touch" },
|
|
122
|
+
actions: [
|
|
123
|
+
{ type: "pointerMove", duration: 0, x: bottomLeftStartX, y: bottomLeftStartY },
|
|
124
|
+
{ type: "pointerDown", button: 0 },
|
|
125
|
+
{ type: "pause", duration: 300 },
|
|
126
|
+
{ type: "pointerMove", duration: 1000, x: bottomLeftEndX, y: bottomLeftEndY },
|
|
127
|
+
{ type: "pointerUp", button: 0 }
|
|
128
|
+
],
|
|
129
|
+
}
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
console.log("✅ Crop overlay resized from two corners successfully!");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// async function swipetofit(TopRStartXpct, TopRStartYpct, TopREndXpct, TopREndYpct, BottomLStartXpct, BottomLStartYpct, BottomLEndXpct, BottomLEndYpct) {
|
|
136
|
+
|
|
137
|
+
// let topRightStartX; // Top-right corner
|
|
138
|
+
// let topRightStartY;
|
|
139
|
+
|
|
140
|
+
// let topRightEndX; // Expand to the right
|
|
141
|
+
// let topRightEndY; // Move upwards slightly
|
|
142
|
+
|
|
143
|
+
// let bottomLeftStartX; // Bottom-left corner
|
|
144
|
+
// let bottomLeftStartY;
|
|
145
|
+
|
|
146
|
+
// let bottomLeftEndX; // Expand to the left
|
|
147
|
+
// let bottomLeftEndY;
|
|
148
|
+
|
|
149
|
+
// // Get screen size dynamically
|
|
150
|
+
// const screenSize = await driver.getWindowRect();
|
|
151
|
+
// const screenWidth = screenSize.width;
|
|
152
|
+
// const screenHeight = screenSize.height;
|
|
153
|
+
|
|
154
|
+
// console.log(`Screen Size: Width=${screenWidth}, Height=${screenHeight}`);
|
|
155
|
+
// // Define approximate positions for corners
|
|
156
|
+
|
|
157
|
+
// if (TopRStartXpct === null) {// default calucaltion
|
|
158
|
+
// topRightStartX = screenWidth * 0.88; // Top-right corner
|
|
159
|
+
// topRightStartY = screenHeight * 0.44;
|
|
160
|
+
|
|
161
|
+
// topRightEndX = screenWidth * 0.96; // Expand to the right
|
|
162
|
+
// topRightEndY = screenHeight * 0.39; // Move upwards slightly
|
|
163
|
+
|
|
164
|
+
// bottomLeftStartX = screenWidth * 0.12; // Bottom-left corner
|
|
165
|
+
// bottomLeftStartY = screenHeight * 0.69;
|
|
166
|
+
|
|
167
|
+
// bottomLeftEndX = screenWidth * 0.014; // Expand to the left
|
|
168
|
+
// bottomLeftEndY = screenHeight * 0.73;
|
|
169
|
+
// } else {
|
|
170
|
+
// topRightStartX = screenWidth * (TopRStartXpct / 100); // Top-right corner
|
|
171
|
+
// topRightStartY = screenHeight * (TopRStartYpct / 100);
|
|
172
|
+
|
|
173
|
+
// topRightEndX = screenWidth * (TopREndXpct / 100); // Expand to the right
|
|
174
|
+
// topRightEndY = screenHeight * (TopREndYpct / 100); // Move upwards slightly
|
|
175
|
+
|
|
176
|
+
// bottomLeftStartX = screenWidth * (BottomLStartXpct / 100); // Bottom-left corner
|
|
177
|
+
// bottomLeftStartY = screenHeight * (BottomLStartYpct / 100);
|
|
178
|
+
|
|
179
|
+
// bottomLeftEndX = screenWidth * (BottomLEndXpct / 100); // Expand to the left
|
|
180
|
+
// bottomLeftEndY = screenHeight * (BottomLEndYpct / 100); // Move down slightly
|
|
181
|
+
// }
|
|
182
|
+
// console.log(`Resizing top-right from (${topRightStartX}, ${topRightStartY}) to (${topRightEndX}, ${topRightEndY})`);
|
|
183
|
+
// console.log(`Resizing bottom-left from (${bottomLeftStartX}, ${bottomLeftStartY}) to (${bottomLeftEndX}, ${bottomLeftEndY})`);
|
|
184
|
+
|
|
185
|
+
// // Resize from top-right corner
|
|
186
|
+
// await driver.performActions([
|
|
187
|
+
// {
|
|
188
|
+
// type: "pointer",
|
|
189
|
+
// id: "finger1",
|
|
190
|
+
// parameters: { pointerType: "touch" },
|
|
191
|
+
// actions: [
|
|
192
|
+
// { type: "pointerMove", duration: 0, x: topRightStartX, y: topRightStartY },
|
|
193
|
+
// { type: "pointerDown", button: 0 },
|
|
194
|
+
// { type: "pause", duration: 300 },
|
|
195
|
+
// { type: "pointerMove", duration: 1000, x: topRightEndX, y: topRightEndY },
|
|
196
|
+
// { type: "pointerUp", button: 0 }
|
|
197
|
+
// ],
|
|
198
|
+
// }
|
|
199
|
+
// ]);
|
|
200
|
+
|
|
201
|
+
// // Resize from bottom-left corner
|
|
202
|
+
// await driver.performActions([
|
|
203
|
+
// {
|
|
204
|
+
// type: "pointer",
|
|
205
|
+
// id: "finger2",
|
|
206
|
+
// parameters: { pointerType: "touch" },
|
|
207
|
+
// actions: [
|
|
208
|
+
// { type: "pointerMove", duration: 0, x: bottomLeftStartX, y: bottomLeftStartY },
|
|
209
|
+
// { type: "pointerDown", button: 0 },
|
|
210
|
+
// { type: "pause", duration: 300 },
|
|
211
|
+
// { type: "pointerMove", duration: 1000, x: bottomLeftEndX, y: bottomLeftEndY },
|
|
212
|
+
// { type: "pointerUp", button: 0 }
|
|
213
|
+
// ],
|
|
214
|
+
// }
|
|
215
|
+
// ]);
|
|
216
|
+
|
|
217
|
+
// console.log("✅ Crop overlay resized from two corners successfully!");
|
|
218
|
+
// }
|
|
219
|
+
module.exports = { swipeleft, swipedown, swiperight, swipeup, swipetofit, swipewithcoordinates };
|
|
@@ -159,7 +159,7 @@ const commonHooks = {
|
|
|
159
159
|
capabilities['bstack:options'] = bsOpts;
|
|
160
160
|
|
|
161
161
|
}
|
|
162
|
-
|
|
162
|
+
console.log('final cinfig dteials :' + JSON.stringify(capabilities))
|
|
163
163
|
|
|
164
164
|
// console.log("config details " + JSON.stringify(config))
|
|
165
165
|
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const url = require('url');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { LocalStorage } = require('node-localstorage');
|
|
5
|
+
global.BUFFER = new LocalStorage('./storage');
|
|
6
|
+
const setAllDetails = require("./setallDatailinBuffer")
|
|
7
|
+
const exeDetails = require("../froth_api_calls/getexecutionDetails")
|
|
8
|
+
const getBSSessionDetails = require("../froth_api_calls/browsersatckSessionInfo").getBSSessionDetails;
|
|
9
|
+
const { fail } = require("assert");
|
|
10
|
+
const { error } = require('console');
|
|
11
|
+
//const isBrowserStackEnabled = process.env.BROWSERSTACK;
|
|
12
|
+
let starttime;
|
|
13
|
+
let endtime;
|
|
14
|
+
let duration_tests = 0;
|
|
15
|
+
console.log('===== common config===== ');
|
|
16
|
+
const resultdetails = {
|
|
17
|
+
comments: [],
|
|
18
|
+
excution_status: null, // Pass/Fail
|
|
19
|
+
excution_time: null, // Execution time in milliseconds
|
|
20
|
+
};
|
|
21
|
+
// Description: This file contains the common configuration for the webdriverio framework.
|
|
22
|
+
const commonconfig = {
|
|
23
|
+
|
|
24
|
+
onPrepare: async function (capabilities, specs) {
|
|
25
|
+
try {
|
|
26
|
+
|
|
27
|
+
console.log('==== ON PREPARE HOOK ====');
|
|
28
|
+
// This code runs before the test suite starts
|
|
29
|
+
await setAllDetails.setEnvVariables();
|
|
30
|
+
await setAllDetails.setExecutionDetails();
|
|
31
|
+
await setAllDetails.setSuiteDetails();
|
|
32
|
+
await setAllDetails.setTestDataDetails();
|
|
33
|
+
console.log("on prepare:", JSON.stringify(capabilities))
|
|
34
|
+
|
|
35
|
+
// console.log("ALL JSON DATA in env variable :" + JSON.stringify(process.env));
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.log("====> Error in onPrepare:", e);
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
beforeSession: async function (config, capabilities, specs) {
|
|
44
|
+
try {
|
|
45
|
+
let syntaxFailed = false;
|
|
46
|
+
|
|
47
|
+
console.log('==== BEFORE SESSION HOOK ====');
|
|
48
|
+
// Perform any setup or pre-test actions here
|
|
49
|
+
console.log("specdat:", specs);
|
|
50
|
+
console.log("length:", specs.length);
|
|
51
|
+
//checking the syntax error in the test files
|
|
52
|
+
for (const fileUrl of specs) {
|
|
53
|
+
const filePath = url.fileURLToPath(fileUrl); // convert file:// URL to file path
|
|
54
|
+
try {
|
|
55
|
+
const code = fs.readFileSync(filePath, 'utf8');
|
|
56
|
+
new Function(code); // Try to compile
|
|
57
|
+
} catch (err) {
|
|
58
|
+
// Extract line number from stack trace
|
|
59
|
+
const match = err.stack.match(/\((.*):(\d+):(\d+)\)/);
|
|
60
|
+
const lineInfo = match ? ` at line ${match[2]}, column ${match[3]}` : '';
|
|
61
|
+
|
|
62
|
+
const errorMsg = `❌ Syntax error in '${path.basename(filePath)}'${lineInfo}: ${err.message}`;
|
|
63
|
+
console.error("🚨", errorMsg);
|
|
64
|
+
resultdetails.comments.push(errorMsg);
|
|
65
|
+
syntaxFailed = true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (syntaxFailed) {
|
|
69
|
+
resultdetails.excution_status = 'FAILED';
|
|
70
|
+
await exeDetails.updateExecuitonDetails(
|
|
71
|
+
BUFFER.getItem("ORGANISATION_DOMAIN_URL"),
|
|
72
|
+
BUFFER.getItem("FROTH_LOGIN_TOKEN"),
|
|
73
|
+
BUFFER.getItem("FROTH_EXECUTION_ID"),
|
|
74
|
+
resultdetails
|
|
75
|
+
);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
// set the capability like media and app and bs local
|
|
79
|
+
// if (process.env.PLATFORM === 'browserstack') {
|
|
80
|
+
// /// console.log("capabilities:", capabilities);
|
|
81
|
+
// capabilities.browserstackLocal = process.env.BROWSERSTACK_LOCAL;
|
|
82
|
+
// // capabilities.accessKey = Buffer.from(capabilities.accessKey, 'base64').toString('utf-8');
|
|
83
|
+
// if (capabilities.platformName === 'android' || capabilities.platformName === 'ios') {
|
|
84
|
+
// capabilities.app = process.env.BROWSERSTACK_APP_PATH;
|
|
85
|
+
// if (capabilities.app === undefined || capabilities.app === null || capabilities.app === '') {
|
|
86
|
+
// console.error("🚨 Error: BROWSERSTACK_APP_PATH is not defined or empty.");
|
|
87
|
+
// resultdetails.excution_status = 'FAILED';
|
|
88
|
+
// resultdetails.comments.push("BROWSERSTACK_APP_PATH is not defined or empty.");
|
|
89
|
+
// await exeDetails.updateExecuitonDetails(BUFFER.getItem("ORGANISATION_DOMAIN_URL"), BUFFER.getItem("FROTH_LOGIN_TOKEN"), BUFFER.getItem("FROTH_EXECUTION_ID"), resultdetails);
|
|
90
|
+
// process.exit(1); // Stop execution if app path is not set
|
|
91
|
+
// } else {
|
|
92
|
+
// console.log("App Path:", capabilities.app);
|
|
93
|
+
// console.log("Browserstack Local:", capabilities.browserstackLocal);
|
|
94
|
+
// }
|
|
95
|
+
// }
|
|
96
|
+
|
|
97
|
+
// try {
|
|
98
|
+
// let mediaFiles = process.env.MEDIA_FILES ? JSON.parse(process.env.MEDIA_FILES) : [];
|
|
99
|
+
// console.log("Size of Media Files:", Array.isArray(mediaFiles) ? mediaFiles.length : "Invalid data");
|
|
100
|
+
|
|
101
|
+
// if (Array.isArray(mediaFiles) && mediaFiles.length > 0) {
|
|
102
|
+
// console.log("Media Files:", JSON.parse(process.env.MEDIA_FILES));
|
|
103
|
+
// capabilities['browserstack.uploadMedia'] = JSON.parse(process.env.MEDIA_FILES);
|
|
104
|
+
// }
|
|
105
|
+
// } catch (error) {
|
|
106
|
+
// console.error("Error parsing MEDIA_FILES:", error);
|
|
107
|
+
// }
|
|
108
|
+
|
|
109
|
+
// console.log(`Running tests on after app,bslocal,mediafiles: ${JSON.stringify(capabilities)}`);
|
|
110
|
+
// }
|
|
111
|
+
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error('🚨 Error in beforeSession:', error);
|
|
114
|
+
console.error('🚨 Error in beforeSession:', error.message);
|
|
115
|
+
resultdetails.excution_status = 'FAILED';
|
|
116
|
+
resultdetails.comments.push("Session creation failed:", error.message);
|
|
117
|
+
await exeDetails.updateExecuitonDetails(BUFFER.getItem("ORGANISATION_DOMAIN_URL"), BUFFER.getItem("FROTH_LOGIN_TOKEN"), BUFFER.getItem("FROTH_EXECUTION_ID"), resultdetails)
|
|
118
|
+
// throw new Error(`Session creation failed: ${error.message}`);
|
|
119
|
+
process.exit(1); // Stop execution if session creation fails
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
},
|
|
125
|
+
/**
|
|
126
|
+
* Gets executed before the suite starts (in Mocha/Jasmine only).
|
|
127
|
+
* @param {object} suite suite details
|
|
128
|
+
*/
|
|
129
|
+
beforeSuite: async function (suite) {
|
|
130
|
+
try {
|
|
131
|
+
console.log('==== BEFORE SUITE HOOK ====');
|
|
132
|
+
console.log(`====> Test suite has been started ' ${suite.title}' `,);
|
|
133
|
+
|
|
134
|
+
starttime = new Date().getTime();
|
|
135
|
+
|
|
136
|
+
if (process.env.PLATFORM === 'browserstack')
|
|
137
|
+
await getBSSessionDetails(process.env.BS_SESSION_TYPE, process.env.BROWSERSTACK_USERNAME, process.env.BROWSERSTACK_ACCESS_KEY);
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
// const resultdetails = {};
|
|
141
|
+
await exeDetails.update_CICDRUNID_ReportUrl(BUFFER.getItem("ORGANISATION_DOMAIN_URL"), BUFFER.getItem("FROTH_LOGIN_TOKEN"), BUFFER.getItem("FROTH_EXECUTION_ID"))
|
|
142
|
+
BUFFER.setItem("UPDATE_EXECUTION", 'FALSE') //i need to recall
|
|
143
|
+
|
|
144
|
+
} catch (e) {
|
|
145
|
+
console.log("Error in beforeSuite:", e);
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
before: async function (capabilities, specs) {
|
|
150
|
+
if (process.env.BS_SESSION_TYPE === 'automate') {
|
|
151
|
+
console.log('==== BEFORE HOOK ====')
|
|
152
|
+
await browser.maximizeWindow()
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
console.log('==== BEFORE HOOK FOR MOBILE ====');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Function to be executed before a test (in Mocha/Jasmine only)
|
|
162
|
+
* @param {object} test test object
|
|
163
|
+
* @param {object} context scope object the test was executed with
|
|
164
|
+
*/
|
|
165
|
+
beforeTest: async function (test, context) {
|
|
166
|
+
|
|
167
|
+
console.log('==== BEFORE TEST HOOK ====');
|
|
168
|
+
console.log(`====> Test Started '${test.title}'`);
|
|
169
|
+
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Function to be executed after a test (in Mocha/Jasmine only)
|
|
175
|
+
* @param {object} test test object
|
|
176
|
+
* @param {object} context scope object the test was executed with
|
|
177
|
+
* @param {Error} result.error error object in case the test fails, otherwise `undefined`
|
|
178
|
+
* @param {*} result.result return object of test function
|
|
179
|
+
* @param {number} result.duration duration of test
|
|
180
|
+
* @param {boolean} result.passed true if test has passed, otherwise false
|
|
181
|
+
* @param {object} result.retries information about spec related retries, e.g. `{ attempts: 0, limit: 0 }`
|
|
182
|
+
*/
|
|
183
|
+
afterTest: async function (test, context, { error, result, duration, passed, retries }) {
|
|
184
|
+
console.log('==== AFTER TEST HOOK ====');
|
|
185
|
+
console.log(`====> Test name finished '${test.title}'`);
|
|
186
|
+
|
|
187
|
+
const fileName = path.basename(test.file);
|
|
188
|
+
console.log('====> Test File Name:', fileName);
|
|
189
|
+
// BUFFER.setItem("FROTH_TOTAL_DURATION", Number(BUFFER.getItem("FROTH_TOTAL_DURATION")) + duration)
|
|
190
|
+
console.log(`====> Total Duration for this test: ${duration}ms`);
|
|
191
|
+
duration_tests += duration;
|
|
192
|
+
console.log(`====> Total Duration for all tests: ${duration_tests}ms`);
|
|
193
|
+
console.log(`====> Status of test: ${passed}`);
|
|
194
|
+
|
|
195
|
+
let scriptresult = "NOT RUN";
|
|
196
|
+
// Default assumption: test passed (unless soft assertion failed)
|
|
197
|
+
let finalPassed = passed;
|
|
198
|
+
|
|
199
|
+
if (passed) {
|
|
200
|
+
scriptresult = "PASSED"
|
|
201
|
+
resultdetails.comments.push(`${test.title} - passed`);
|
|
202
|
+
console.log(`====> resultdetails comments: ${resultdetails.comments}`);
|
|
203
|
+
}
|
|
204
|
+
else if (!finalPassed || error) {
|
|
205
|
+
scriptresult = "FAILED"
|
|
206
|
+
console.log(`====> Failed or error while executing the test: ${error ? error.message : "Test failed"}`);
|
|
207
|
+
if (!resultdetails.comments.some(comment => typeof comment === 'string' && comment.includes(test.title)))
|
|
208
|
+
resultdetails.comments.push(`${test.title} - failed: ${error ? error.message : "Test failed"}`);
|
|
209
|
+
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let scriptDetails = BUFFER.getItem("FROTHE_SUITE_DETAILS");
|
|
213
|
+
if (typeof scriptDetails === "string") {
|
|
214
|
+
scriptDetails = JSON.parse(scriptDetails);
|
|
215
|
+
}
|
|
216
|
+
const jwtScript = scriptDetails.find(s => s.scriptName === fileName.replace(".js", ""));
|
|
217
|
+
console.log("jwtScript:", jwtScript);
|
|
218
|
+
|
|
219
|
+
await exeDetails.updateScriptExecutionStatus(
|
|
220
|
+
BUFFER.getItem("ORGANISATION_DOMAIN_URL"),
|
|
221
|
+
BUFFER.getItem("FROTH_LOGIN_TOKEN"),
|
|
222
|
+
jwtScript.scriptId,
|
|
223
|
+
jwtScript.platform.toLowerCase(),
|
|
224
|
+
scriptresult)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
},
|
|
228
|
+
/**
|
|
229
|
+
* Hook that gets executed after the suite has ended (in Mocha/Jasmine only).
|
|
230
|
+
* @param {object} suite suite details
|
|
231
|
+
*/
|
|
232
|
+
afterSuite: async function (suite) {
|
|
233
|
+
console.log('==== AFTER SUITE HOOK ====');
|
|
234
|
+
console.log(`====> Test suite has completed '${suite.title}'`);
|
|
235
|
+
},
|
|
236
|
+
/**
|
|
237
|
+
* Gets executed after all tests are done. You still have access to all global variables from
|
|
238
|
+
* the test.
|
|
239
|
+
* @param {number} result 0 - test pass, 1 - test fail
|
|
240
|
+
* @param {Array.<Object>} capabilities list of capabilities details
|
|
241
|
+
* @param {Array.<String>} specs List of spec file paths that ran
|
|
242
|
+
*/
|
|
243
|
+
after: async function (result, config, capabilities, specs) {
|
|
244
|
+
console.log('==== AFTER HOOK ====');
|
|
245
|
+
console.log('====> All tests are completed.' + result);
|
|
246
|
+
BUFFER.setItem("RESULT_DATA", result);
|
|
247
|
+
console.log("====> Result data :" + BUFFER.getItem("RESULT_DATA"))
|
|
248
|
+
resultdetails.excution_status = BUFFER.getItem("RESULT_DATA") == 0 ? 'PASSED' : 'FAILED'
|
|
249
|
+
console.log("====> Total Duration taken for the suite:" + BUFFER.getItem("FROTH_TOTAL_DURATION"));
|
|
250
|
+
console.log("====> Execution Status from results" + resultdetails.excution_status);
|
|
251
|
+
// Capture WebDriver session errors
|
|
252
|
+
|
|
253
|
+
if (result !== 0) {
|
|
254
|
+
if (resultdetails.comments.length === 0) {
|
|
255
|
+
resultdetails.comments.push("❌ WebDriver session failed or timed out.");
|
|
256
|
+
}
|
|
257
|
+
resultdetails.comments.push(`Execution failed with exit code: ${result}`);
|
|
258
|
+
|
|
259
|
+
process.on('uncaughtException', (err) => {
|
|
260
|
+
console.error("Uncaught Exception:", err);
|
|
261
|
+
resultdetails.comments.push(`Execution failed : ${err}`);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
onError: async function (error) {
|
|
269
|
+
console.error('==== ON ERROR HOOK ====');
|
|
270
|
+
console.error('====> Error occurred:', error.message);
|
|
271
|
+
if (error.message.includes('Automate testing time expired')) {
|
|
272
|
+
console.log('❌ Global error: Session timed out on BrowserStack.');
|
|
273
|
+
resultdetails.excution_status = 'FAILED';
|
|
274
|
+
resultdetails.comments.push(`Global error: Session timed out on BrowserStack.Please check ths session: ${result}`);
|
|
275
|
+
|
|
276
|
+
await exeDetails.updateExecuitonDetails(BUFFER.getItem("ORGANISATION_DOMAIN_URL"), BUFFER.getItem("FROTH_LOGIN_TOKEN"), BUFFER.getItem("FROTH_EXECUTION_ID"), resultdetails)
|
|
277
|
+
process.exit(1); // Stop execution if session timed out
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
afterSession: async function (config, capabilities, specs) {
|
|
281
|
+
console.log('==== AFTER SESSION HOOK ====');
|
|
282
|
+
console.log('====> This is the aftersession hook');
|
|
283
|
+
// console.log("Capabilities:", capabilities);
|
|
284
|
+
console.log("Specs:", specs);
|
|
285
|
+
//console.log("Config:", config);
|
|
286
|
+
|
|
287
|
+
process.on('uncaughtException', (err) => {
|
|
288
|
+
console.error("Uncaught Exception:", err);
|
|
289
|
+
resultdetails.comments.push(`Execution failed with exit code: ${err}`);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Capture unhandled promise rejections
|
|
293
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
294
|
+
console.error("Unhandled Promise Rejection:", reason);
|
|
295
|
+
resultdetails.comments.push(`Execution failed with exit code: ${reason}`);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
endtime = new Date().getTime();
|
|
299
|
+
let totalDuration = endtime - starttime;
|
|
300
|
+
console.log("====> Total Duration taken for :" + BUFFER.getItem("FROTH_TOTAL_DURATION"));
|
|
301
|
+
console.log("====> Total Duration in after session based on start time and end time:" + totalDuration);
|
|
302
|
+
console.log("====> Total Duration in after session based on summing up the test execution times:" + duration_tests);
|
|
303
|
+
|
|
304
|
+
resultdetails.excution_status = BUFFER.getItem("RESULT_DATA") == 0 ? 'PASSED' : 'FAILED'
|
|
305
|
+
const frothDuration = BUFFER.getItem("FROTH_TOTAL_DURATION");
|
|
306
|
+
|
|
307
|
+
if (await isInvalidDuration(frothDuration)) {
|
|
308
|
+
// console.log("inside froth duration");
|
|
309
|
+
if (await isInvalidDuration(duration_tests)) {
|
|
310
|
+
console.log("inside froth duration_tests");
|
|
311
|
+
resultdetails.excution_time = await millisecondsToTime(totalDuration);
|
|
312
|
+
} else {
|
|
313
|
+
console.log("inside froth duration_tests comparision");
|
|
314
|
+
if (totalDuration > duration_tests)
|
|
315
|
+
resultdetails.excution_time = await millisecondsToTime(totalDuration);
|
|
316
|
+
else
|
|
317
|
+
resultdetails.excution_time = await millisecondsToTime(duration_tests);
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
console.log("inside froth duration else");
|
|
321
|
+
resultdetails.excution_time = await secondsToTime(frothDuration);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
console.log("====> Total Duration calculation:" + resultdetails.excution_time);
|
|
325
|
+
|
|
326
|
+
await exeDetails.updateExecuitonDetails(BUFFER.getItem("ORGANISATION_DOMAIN_URL"), BUFFER.getItem("FROTH_LOGIN_TOKEN"), BUFFER.getItem("FROTH_EXECUTION_ID"), resultdetails)
|
|
327
|
+
|
|
328
|
+
// Perform any cleanup or post-test actions here
|
|
329
|
+
BUFFER.clear();
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
onComplete: async function (exitCode, config, capabilities, results) {
|
|
333
|
+
console.log('==== ON COMPLETE HOOK ====');
|
|
334
|
+
console.log('====> Results:', results);
|
|
335
|
+
console.log('==== Test Results Summary ======');
|
|
336
|
+
console.log('Total Tests:', results.total);
|
|
337
|
+
console.log('Passed:', results.passed);
|
|
338
|
+
console.log('Failed:', results.failed);
|
|
339
|
+
console.log('Exit Code:', exitCode);
|
|
340
|
+
|
|
341
|
+
console.log('==== ALL TESTS ARE COMPLETED ====');
|
|
342
|
+
return exitCode;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
};
|
|
346
|
+
async function isInvalidDuration(val) {
|
|
347
|
+
console.log("val in isValidDuration:" + val);
|
|
348
|
+
// Check if the value is null, 0, or undefined
|
|
349
|
+
let isValid;
|
|
350
|
+
if (typeof val === 'string') {
|
|
351
|
+
val = val.trim().toLowerCase();
|
|
352
|
+
isValid = val === "null" || val === "0" || val === "undefined";
|
|
353
|
+
|
|
354
|
+
} else
|
|
355
|
+
isValid = val === null || val === 0 || val === undefined;
|
|
356
|
+
|
|
357
|
+
console.log("isValid in isValidDuration:" + isValid);
|
|
358
|
+
|
|
359
|
+
return isValid;
|
|
360
|
+
}
|
|
361
|
+
async function secondsToTime(secs) {
|
|
362
|
+
console.log("secs in secondsToTime :" + secs);
|
|
363
|
+
let hours = Math.floor(secs / 3600);
|
|
364
|
+
let minutes = Math.floor((secs % 3600) / 60);
|
|
365
|
+
let seconds = secs % 60;
|
|
366
|
+
|
|
367
|
+
// Adding leading zeros if the value is less than 10
|
|
368
|
+
if (hours < 10) hours = '0' + hours;
|
|
369
|
+
if (minutes < 10) minutes = '0' + minutes;
|
|
370
|
+
if (seconds < 10) seconds = '0' + seconds;
|
|
371
|
+
console.log("Time:" + hours + ':' + minutes + ':' + seconds);
|
|
372
|
+
return hours + ':' + minutes + ':' + seconds;
|
|
373
|
+
}
|
|
374
|
+
async function millisecondsToTime(ms) {
|
|
375
|
+
console.log("ms in millisecondsToTime: " + ms);
|
|
376
|
+
|
|
377
|
+
// Ensure input is a number
|
|
378
|
+
ms = Number(ms);
|
|
379
|
+
if (isNaN(ms)) {
|
|
380
|
+
return '00:00:00';
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
let totalSeconds = Math.floor(ms / 1000);
|
|
384
|
+
let hours = Math.floor(totalSeconds / 3600);
|
|
385
|
+
let minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
386
|
+
let seconds = totalSeconds % 60;
|
|
387
|
+
|
|
388
|
+
// Pad with leading zeros
|
|
389
|
+
hours = hours < 10 ? '0' + hours : hours;
|
|
390
|
+
minutes = minutes < 10 ? '0' + minutes : minutes;
|
|
391
|
+
seconds = seconds < 10 ? '0' + seconds : seconds;
|
|
392
|
+
|
|
393
|
+
const timeStr = `${hours}:${minutes}:${seconds}`;
|
|
394
|
+
console.log("Formatted time:", timeStr);
|
|
395
|
+
return timeStr;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
async function convertTimetoHHMMSS(time) {
|
|
399
|
+
const seconds = Math.floor((time / 1000) % 60);
|
|
400
|
+
const minutes = Math.floor((time / (1000 * 60)) % 60);
|
|
401
|
+
const hours = Math.floor((time / (1000 * 60 * 60)) % 24);
|
|
402
|
+
const formattedTime = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
403
|
+
|
|
404
|
+
console.log("Time:" + hours + ':' + minutes + ':' + seconds);
|
|
405
|
+
|
|
406
|
+
return formattedTime;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
module.exports = commonconfig;
|