froth-webdriverio-framework 6.0.68 → 6.0.70
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.
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
const setAllDetails = require('./setallDatailinBuffer');
|
|
2
3
|
const exeDetails = require('../froth_api_calls/getexecutionDetails');
|
|
3
4
|
const { getBSSessionDetails } = require('../froth_api_calls/browsersatckSessionInfo');
|
|
@@ -7,7 +8,7 @@ let totalTestDuration = 0;
|
|
|
7
8
|
const url = require('url');
|
|
8
9
|
const fs = require('fs');
|
|
9
10
|
const path = require('path');
|
|
10
|
-
|
|
11
|
+
let executionUpdated = false;
|
|
11
12
|
const resultdetails = {
|
|
12
13
|
comments: [],
|
|
13
14
|
excution_status: null,
|
|
@@ -39,12 +40,19 @@ function registerGlobalErrorHandlers() {
|
|
|
39
40
|
|
|
40
41
|
async function safeUpdateExecution() {
|
|
41
42
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
if (executionUpdated) return;
|
|
44
|
+
executionUpdated = true;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
await exeDetails.updateExecuitonDetails(
|
|
48
|
+
BUFFER.getItem('ORGANISATION_DOMAIN_URL'),
|
|
49
|
+
BUFFER.getItem('FROTH_LOGIN_TOKEN'),
|
|
50
|
+
BUFFER.getItem('FROTH_EXECUTION_ID'),
|
|
51
|
+
resultdetails
|
|
52
|
+
);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.error('❌ Failed to update execution details:', e.message);
|
|
55
|
+
}
|
|
48
56
|
} catch (e) {
|
|
49
57
|
console.error('❌ Failed to update execution details:', e.message);
|
|
50
58
|
}
|
|
@@ -52,8 +60,19 @@ async function safeUpdateExecution() {
|
|
|
52
60
|
|
|
53
61
|
/* ----------------- HELPER FUNCTIONS ----------------- */
|
|
54
62
|
function msToTime(ms) {
|
|
55
|
-
|
|
56
|
-
|
|
63
|
+
if (!ms || isNaN(ms)) return '00:00:00';
|
|
64
|
+
|
|
65
|
+
let seconds = Math.floor(ms / 1000);
|
|
66
|
+
let hours = Math.floor(seconds / 3600);
|
|
67
|
+
seconds %= 3600;
|
|
68
|
+
let minutes = Math.floor(seconds / 60);
|
|
69
|
+
seconds %= 60;
|
|
70
|
+
|
|
71
|
+
return [
|
|
72
|
+
hours.toString().padStart(2, '0'),
|
|
73
|
+
minutes.toString().padStart(2, '0'),
|
|
74
|
+
seconds.toString().padStart(2, '0')
|
|
75
|
+
].join(':');
|
|
57
76
|
}
|
|
58
77
|
|
|
59
78
|
async function failExecution(reason) {
|
|
@@ -138,288 +157,122 @@ const commonHooks = {
|
|
|
138
157
|
console.error('🚨 Error in beforeSession:', error.message);
|
|
139
158
|
}
|
|
140
159
|
},
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
console.log('==== AFTER HOOK ====');
|
|
261
|
-
console.log('====> All tests are completed.' + result);
|
|
262
|
-
BUFFER.setItem("RESULT_DATA", result);
|
|
263
|
-
console.log("====> Result data :" + BUFFER.getItem("RESULT_DATA"))
|
|
264
|
-
resultdetails.excution_status = BUFFER.getItem("RESULT_DATA") == 0 ? 'PASSED' : 'FAILED'
|
|
265
|
-
console.log("====> Total Duration taken for the suite:" + BUFFER.getItem("FROTH_TOTAL_DURATION"));
|
|
266
|
-
console.log("====> Execution Status from results" + resultdetails.excution_status);
|
|
267
|
-
// Capture WebDriver session errors
|
|
268
|
-
|
|
269
|
-
if (result !== 0) {
|
|
270
|
-
if (resultdetails.comments.length === 0) {
|
|
271
|
-
resultdetails.comments.push("❌ WebDriver session failed or timed out.");
|
|
272
|
-
}
|
|
273
|
-
resultdetails.comments.push(`Execution failed with exit code: ${result}`);
|
|
274
|
-
|
|
275
|
-
process.on('uncaughtException', (err) => {
|
|
276
|
-
console.error("Uncaught Exception:", err);
|
|
277
|
-
resultdetails.comments.push(`Execution failed : ${err}`);
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
},
|
|
283
|
-
|
|
284
|
-
onError: async function (error) {
|
|
285
|
-
console.error('==== ON ERROR HOOK ====');
|
|
286
|
-
console.error('====> Error occurred:', error.message);
|
|
287
|
-
if (error.message.includes('Automate testing time expired')) {
|
|
288
|
-
console.log('❌ Global error: Session timed out on BrowserStack.');
|
|
289
|
-
resultdetails.excution_status = 'FAILED';
|
|
290
|
-
resultdetails.comments.push(`Global error: Session timed out on BrowserStack.Please check ths session: ${result}`);
|
|
291
|
-
|
|
292
|
-
await exeDetails.updateExecuitonDetails(BUFFER.getItem("ORGANISATION_DOMAIN_URL"), BUFFER.getItem("FROTH_LOGIN_TOKEN"), BUFFER.getItem("FROTH_EXECUTION_ID"), resultdetails)
|
|
293
|
-
process.exit(1); // Stop execution if session timed out
|
|
294
|
-
}
|
|
295
|
-
},
|
|
296
|
-
afterSession: async function (config, capabilities, specs) {
|
|
297
|
-
console.log('==== AFTER SESSION HOOK ====');
|
|
298
|
-
console.log('====> This is the aftersession hook');
|
|
299
|
-
// console.log("Capabilities:", capabilities);
|
|
300
|
-
console.log("Specs:", specs);
|
|
301
|
-
//console.log("Config:", config);
|
|
302
|
-
|
|
303
|
-
process.on('uncaughtException', (err) => {
|
|
304
|
-
console.error("Uncaught Exception:", err);
|
|
305
|
-
resultdetails.comments.push(`Execution failed with exit code: ${err}`);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
// Capture unhandled promise rejections
|
|
309
|
-
process.on('unhandledRejection', (reason, promise) => {
|
|
310
|
-
console.error("Unhandled Promise Rejection:", reason);
|
|
311
|
-
resultdetails.comments.push(`Execution failed with exit code: ${reason}`);
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
endtime = new Date().getTime();
|
|
315
|
-
let totalDuration = endtime - starttime;
|
|
316
|
-
console.log("====> Total Duration taken for :" + BUFFER.getItem("FROTH_TOTAL_DURATION"));
|
|
317
|
-
console.log("====> Total Duration in after session based on start time and end time:" + totalDuration);
|
|
318
|
-
console.log("====> Total Duration in after session based on summing up the test execution times:" + totalTestDuration);
|
|
319
|
-
|
|
320
|
-
resultdetails.excution_status = BUFFER.getItem("RESULT_DATA") == 0 ? 'PASSED' : 'FAILED'
|
|
321
|
-
const frothDuration = BUFFER.getItem("FROTH_TOTAL_DURATION");
|
|
322
|
-
|
|
323
|
-
if (await isInvalidDuration(frothDuration)) {
|
|
324
|
-
// console.log("inside froth duration");
|
|
325
|
-
if (await isInvalidDuration(totalTestDuration)) {
|
|
326
|
-
console.log("inside froth totalTestDuration");
|
|
327
|
-
resultdetails.excution_time = await millisecondsToTime(totalDuration);
|
|
328
|
-
} else {
|
|
329
|
-
console.log("inside froth totalTestDuration comparision");
|
|
330
|
-
if (totalDuration > totalTestDuration)
|
|
331
|
-
resultdetails.excution_time = await millisecondsToTime(totalDuration);
|
|
332
|
-
else
|
|
333
|
-
resultdetails.excution_time = await millisecondsToTime(totalTestDuration);
|
|
334
|
-
}
|
|
335
|
-
} else {
|
|
336
|
-
console.log("inside froth duration else");
|
|
337
|
-
resultdetails.excution_time = await secondsToTime(frothDuration);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
console.log("====> Total Duration calculation:" + resultdetails.excution_time);
|
|
341
|
-
|
|
342
|
-
await exeDetails.updateExecuitonDetails(BUFFER.getItem("ORGANISATION_DOMAIN_URL"), BUFFER.getItem("FROTH_LOGIN_TOKEN"), BUFFER.getItem("FROTH_EXECUTION_ID"), resultdetails)
|
|
343
|
-
|
|
344
|
-
// Perform any cleanup or post-test actions here
|
|
345
|
-
BUFFER.clear();
|
|
346
|
-
},
|
|
347
|
-
|
|
348
|
-
onComplete: async function (exitCode, config, capabilities, results) {
|
|
349
|
-
console.log('==== ON COMPLETE HOOK ====');
|
|
350
|
-
console.log('====> Results:', results);
|
|
351
|
-
console.log('==== Test Results Summary ======');
|
|
352
|
-
console.log('Total Tests:', results.total);
|
|
353
|
-
console.log('Passed:', results.passed);
|
|
354
|
-
console.log('Failed:', results.failed);
|
|
355
|
-
console.log('Exit Code:', exitCode);
|
|
356
|
-
|
|
357
|
-
console.log('==== ALL TESTS ARE COMPLETED ====');
|
|
358
|
-
return exitCode;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
};
|
|
362
|
-
async function isInvalidDuration(val) {
|
|
363
|
-
console.log("val in isValidDuration:" + val);
|
|
364
|
-
// Check if the value is null, 0, or undefined
|
|
365
|
-
let isValid;
|
|
366
|
-
if (typeof val === 'string') {
|
|
367
|
-
val = val.trim().toLowerCase();
|
|
368
|
-
isValid = val === "null" || val === "0" || val === "undefined";
|
|
369
|
-
|
|
370
|
-
} else
|
|
371
|
-
isValid = val === null || val === 0 || val === undefined;
|
|
372
|
-
|
|
373
|
-
console.log("isValid in isValidDuration:" + isValid);
|
|
374
|
-
|
|
375
|
-
return isValid;
|
|
376
|
-
}
|
|
377
|
-
async function secondsToTime(secs) {
|
|
378
|
-
console.log("secs in secondsToTime :" + secs);
|
|
379
|
-
let hours = Math.floor(secs / 3600);
|
|
380
|
-
let minutes = Math.floor((secs % 3600) / 60);
|
|
381
|
-
let seconds = secs % 60;
|
|
382
|
-
|
|
383
|
-
// Adding leading zeros if the value is less than 10
|
|
384
|
-
if (hours < 10) hours = '0' + hours;
|
|
385
|
-
if (minutes < 10) minutes = '0' + minutes;
|
|
386
|
-
if (seconds < 10) seconds = '0' + seconds;
|
|
387
|
-
console.log("Time:" + hours + ':' + minutes + ':' + seconds);
|
|
388
|
-
return hours + ':' + minutes + ':' + seconds;
|
|
389
|
-
}
|
|
390
|
-
async function millisecondsToTime(ms) {
|
|
391
|
-
console.log("ms in millisecondsToTime: " + ms);
|
|
392
|
-
|
|
393
|
-
// Ensure input is a number
|
|
394
|
-
ms = Number(ms);
|
|
395
|
-
if (isNaN(ms)) {
|
|
396
|
-
return '00:00:00';
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
let totalSeconds = Math.floor(ms / 1000);
|
|
400
|
-
let hours = Math.floor(totalSeconds / 3600);
|
|
401
|
-
let minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
402
|
-
let seconds = totalSeconds % 60;
|
|
403
|
-
|
|
404
|
-
// Pad with leading zeros
|
|
405
|
-
hours = hours < 10 ? '0' + hours : hours;
|
|
406
|
-
minutes = minutes < 10 ? '0' + minutes : minutes;
|
|
407
|
-
seconds = seconds < 10 ? '0' + seconds : seconds;
|
|
408
|
-
|
|
409
|
-
const timeStr = `${hours}:${minutes}:${seconds}`;
|
|
410
|
-
console.log("Formatted time:", timeStr);
|
|
411
|
-
return timeStr;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
async function convertTimetoHHMMSS(time) {
|
|
415
|
-
const seconds = Math.floor((time / 1000) % 60);
|
|
416
|
-
const minutes = Math.floor((time / (1000 * 60)) % 60);
|
|
417
|
-
const hours = Math.floor((time / (1000 * 60 * 60)) % 24);
|
|
418
|
-
const formattedTime = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
419
|
-
|
|
420
|
-
console.log("Time:" + hours + ':' + minutes + ':' + seconds);
|
|
421
|
-
|
|
422
|
-
return formattedTime;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
module.exports = commonHooks;
|
|
160
|
+
/* ========== BEFORE SUITE ========== */
|
|
161
|
+
beforeSuite: async (suite) => {
|
|
162
|
+
console.log(`==== BEFORE SUITE: ${suite.title} ====`);
|
|
163
|
+
suiteStartTime = Date.now();
|
|
164
|
+
|
|
165
|
+
if (process.env.PLATFORM === 'browserstack' || process.env.PLATFORM === 'browserstacklocal') {
|
|
166
|
+
await getBSSessionDetails(
|
|
167
|
+
process.env.BS_SESSION_TYPE,
|
|
168
|
+
process.env.BROWSERSTACK_USERNAME,
|
|
169
|
+
process.env.BROWSERSTACK_ACCESS_KEY
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
await exeDetails.update_CICDRUNID_ReportUrl(
|
|
174
|
+
BUFFER.getItem('ORGANISATION_DOMAIN_URL'),
|
|
175
|
+
BUFFER.getItem('FROTH_LOGIN_TOKEN'),
|
|
176
|
+
BUFFER.getItem('FROTH_EXECUTION_ID')
|
|
177
|
+
);
|
|
178
|
+
},
|
|
179
|
+
/* ========== BEFORE TEST ========== */
|
|
180
|
+
beforeTest: async (test) => {
|
|
181
|
+
console.log(`▶️ START TEST: ${test.title}`);
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
/* ========== AFTER TEST ========== */
|
|
185
|
+
afterTest: async (test, _, { error, duration, passed }) => {
|
|
186
|
+
console.log(`==== AFTER TEST HOOK ===='${test.title}'`);
|
|
187
|
+
totalTestDuration += duration;
|
|
188
|
+
|
|
189
|
+
const fileName = path.basename(test.file);
|
|
190
|
+
const status = passed ? 'PASSED' : 'FAILED';
|
|
191
|
+
|
|
192
|
+
if (!passed) {
|
|
193
|
+
resultdetails.comments.push(`${test.title} - ${error?.message || 'Failed'}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const suiteDetails = JSON.parse(BUFFER.getItem('FROTHE_SUITE_DETAILS'));
|
|
197
|
+
const script = suiteDetails.find(s => s.scriptName === fileName.replace('.js', ''));
|
|
198
|
+
console.log("Script Details:", script);
|
|
199
|
+
|
|
200
|
+
await exeDetails.updateScriptExecutionStatus(
|
|
201
|
+
BUFFER.getItem('ORGANISATION_DOMAIN_URL'),
|
|
202
|
+
BUFFER.getItem('FROTH_LOGIN_TOKEN'),
|
|
203
|
+
script.scriptId,
|
|
204
|
+
script.platform.toLowerCase(),
|
|
205
|
+
status
|
|
206
|
+
);
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Hook that gets executed after the suite has ended (in Mocha/Jasmine only).
|
|
211
|
+
* @param {object} suite suite details
|
|
212
|
+
*/
|
|
213
|
+
afterSuite: async function (suite) {
|
|
214
|
+
console.log('==== AFTER SUITE HOOK ====');
|
|
215
|
+
console.log(`====> Test suite has completed '${suite.title}'`);
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
/* ==== AFTER SESSION ==== */
|
|
219
|
+
afterSession: async (config, capabilities, specs,exitCode) => {
|
|
220
|
+
console.log('==== AFTER SESSION ====');
|
|
221
|
+
const endTime = Date.now();
|
|
222
|
+
if (!suiteStartTime) suiteStartTime = endTime;
|
|
223
|
+
|
|
224
|
+
const totalTime = Math.max(endTime - suiteStartTime, totalTestDuration);
|
|
225
|
+
// resultdetails.excution_status = exitCode === 0 ? 'PASSED' : 'FAILED';
|
|
226
|
+
resultdetails.excution_time = msToTime(totalTime);
|
|
227
|
+
|
|
228
|
+
console.log('⏱ Final execution time:', resultdetails.excution_time);
|
|
229
|
+
|
|
230
|
+
// console.log('📤 Updating DB with final execution details');
|
|
231
|
+
// console.log('Status:', resultdetails.excution_status);
|
|
232
|
+
// console.log('Duration:', resultdetails.excution_time);
|
|
233
|
+
|
|
234
|
+
// await safeUpdateExecution();
|
|
235
|
+
// BUFFER.clear();
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
/* ========== ON ERROR ========== */
|
|
239
|
+
|
|
240
|
+
onError: async function (error) {
|
|
241
|
+
console.error('==== ON ERROR HOOK ====');
|
|
242
|
+
console.error('Error occurred:', error.message);
|
|
243
|
+
|
|
244
|
+
// Normalize all framework-level failures
|
|
245
|
+
resultdetails.excution_status = 'FAILED';
|
|
246
|
+
resultdetails.comments.push(`WDIO Error: ${error.message}`);
|
|
247
|
+
|
|
248
|
+
// Special handling for BrowserStack timeout
|
|
249
|
+
if (error.message?.includes('Automate testing time expired')) {
|
|
250
|
+
resultdetails.comments.push(
|
|
251
|
+
'BrowserStack session timed out (Automate testing time expired)'
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
await safeUpdateExecution();
|
|
256
|
+
},
|
|
257
|
+
/* ========== ON COMPLETE ========== */
|
|
258
|
+
onComplete: async (exitCode, _, __, results) => {
|
|
259
|
+
cconsole.log('==== ON COMPLETE ====');
|
|
260
|
+
console.log(`Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`);
|
|
261
|
+
|
|
262
|
+
resultdetails.excution_status = exitCode === 0 ? 'PASSED' : 'FAILED';
|
|
263
|
+
|
|
264
|
+
if (exitCode !== 0 && resultdetails.comments.length === 0) {
|
|
265
|
+
resultdetails.comments.push(`Execution failed with exit code ${exitCode}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
await safeUpdateExecution();
|
|
269
|
+
BUFFER.clear();
|
|
270
|
+
|
|
271
|
+
return exitCode;
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
module.exports = commonHooks;
|