froth-webdriverio-framework 6.0.59 → 6.0.61

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,56 +1,45 @@
1
1
 
2
- //const commonHooks = require('../commonhook');
3
- const setAllDetails = require('../setallDatailinBuffer');
4
-
5
- (async () => {
6
- //setAllDetails.setEnvVariables();
7
- const getExeDetails = await setAllDetails.setExecutionDetails();
8
- // console.log("app url in prerequisite;" + getExeDetails.app_url)
9
- const appurl = process.env.BROWSERSTACK_APP_PATH || getExeDetails.app_url
10
- console.log("app utl is" + appurl)
11
- // getExeDetails.app_url=process.env.BROWSERSTACK_APP_PATH
12
- //return appurl
13
- })();
14
-
15
- module.exports = (bsCaps) => ({
16
- // const appPath = process.env.BROWSERSTACK_APP_PATH;
17
-
18
- //...commonHooks,
19
- user: bsCaps.userName,
20
- key: Buffer.from(bsCaps.accessKey, 'base64').toString('utf-8'),
21
-
22
- services: [
23
- [
24
- 'browserstack',
25
- {
26
- buildIdentifier: process.env.BROWSERSTACK_BUILD_NAME || 'local-build',
27
- browserstackLocal: false,
28
- opts: {
29
- forcelocal: false,
30
- localIdentifier: `wdio-${process.pid}`,
2
+ const commonHooks = require('../commonhook');
3
+ module.exports = (bsCaps) => {
4
+ const PLATFORM = process.env.PLATFORM || 'browserstack';
5
+ const isBSLocal = PLATFORM === 'browserstacklocal';
6
+
7
+ return {
8
+ ...commonHooks,
9
+ user: bsCaps.userName,
10
+ key: Buffer.from(bsCaps.accessKey, 'base64').toString('utf-8'),
11
+
12
+ services: [
13
+ [
14
+ 'browserstack',
15
+ {
16
+ buildIdentifier: process.env.BROWSERSTACK_BUILD_NAME || 'local-build',
17
+ browserstackLocal: isBSLocal,
18
+ opts: {
19
+ forcelocal: isBSLocal,
20
+ localIdentifier: `wdio-${process.pid}`,
21
+ },
22
+ // app: process.env.BROWSERSTACK_APP_PATH,
31
23
  },
32
- app: process.env.BROWSERSTACK_APP_PATH,
33
- },
24
+ ],
34
25
  ],
35
- ],
36
-
37
-
38
- capabilities: [{
39
- platformName: bsCaps.platformName || 'Android',
40
- //'appium:app': appPath,
41
- 'bstack:options': {
42
- projectName: 'BrowserStack Samples',
43
- buildName: 'browserstack build',
44
- sessionName: 'Mobile Test',
45
- deviceName: bsCaps.deviceName || 'Samsung Galaxy S22 Ultra',
46
- osVersion: bsCaps.platformVersion || '12.0',
47
- debug: bsCaps.debug,
48
- networkLogs: bsCaps.networkLogs,
49
- interactiveDebugging: bsCaps.interactiveDebugging,
50
-
51
- }
52
- }],
53
26
 
54
- updateJob: false
55
27
 
56
- });
28
+ capabilities: [{
29
+ platformName: bsCaps.platformName || 'Android',
30
+ 'bstack:options': {
31
+ // projectName: 'BrowserStack Samples',
32
+ buildName: 'Mobile_Build-',
33
+ sessionName: 'Mobile Test',
34
+ deviceName: bsCaps.deviceName || 'Samsung Galaxy S22 Ultra',
35
+ osVersion: bsCaps.platformVersion || '12.0',
36
+ debug: bsCaps.debug,
37
+ networkLogs: bsCaps.networkLogs,
38
+ interactiveDebugging: bsCaps.interactiveDebugging,
39
+
40
+ }
41
+ }],
42
+
43
+ updateJob: false
44
+ }
45
+ };
@@ -1,25 +1,41 @@
1
- module.exports = (bsCaps) => ({
2
- user: bsCaps.userName,
3
- key: Buffer.from(bsCaps.accessKey, 'base64').toString('utf-8'),
1
+ const commonHooks = require('../commonhook');
2
+ module.exports = (bsCaps) => {
3
+ const PLATFORM = process.env.PLATFORM || 'browserstack';
4
4
 
5
+ const isBSLocal = PLATFORM === 'browserstacklocal';
6
+
7
+ return {
8
+ ...commonHooks,
9
+ user: bsCaps.userName,
10
+ key: Buffer.from(bsCaps.accessKey, 'base64').toString('utf-8'),
5
11
 
6
- services: [
7
- [
8
- 'browserstack',
9
- {
10
- browserstackLocal: false,
11
- opts: { forcelocal: false }
12
- }
13
- ]
14
- ],
15
12
 
13
+ services: [
14
+ [
15
+ 'browserstack',
16
+ {
17
+ buildIdentifier: process.env.BROWSERSTACK_BUILD_NAME || 'local-build',
18
+ browserstackLocal: isBSLocal,
19
+ opts: {
20
+ forcelocal: isBSLocal,
21
+ localIdentifier: `wdio-${process.pid}`,
22
+ }
23
+ }
24
+ ]
25
+ ],
16
26
 
17
- capabilities: [{
18
- browserName: process.env.BROWSER || 'chrome',
19
- 'bstack:options': {
20
- os: 'Windows',
21
- osVersion: '11',
22
- buildName: 'BS Web Build'
23
- }
24
- }]
25
- });
27
+
28
+ capabilities: [{
29
+ browserName: bsCaps.browserName || 'chrome',
30
+ browserVersion: bsCaps.browserVersion,
31
+ 'bstack:options': {
32
+ os: bsCaps.os,
33
+ osVersion: bsCaps.osVersion,
34
+ buildName: 'Web_Build-',
35
+ debug: bsCaps.debug,
36
+ networkLogs: bsCaps.networkLogs,
37
+ interactiveDebugging: bsCaps.interactiveDebugging,
38
+ }
39
+ }]
40
+ }
41
+ };
@@ -0,0 +1,38 @@
1
+
2
+ const setAllDetails = require('./setallDatailinBuffer');
3
+ let getExeDetails;
4
+ module.exports = {
5
+ onPrepare: async () => {
6
+ console.log('==== ON PREPARE HOOK ====');
7
+ await setAllDetails.setEnvVariables();
8
+ await setAllDetails.setExecutionDetails();
9
+ await setAllDetails.setSuiteDetails();
10
+ await setAllDetails.setTestDataDetails();
11
+
12
+ console.log('✅ App & media set in on prepare');
13
+ },
14
+
15
+ beforeSession: async function (config, capabilities, specs) {
16
+ try {
17
+ if (process.env.BS_SESSION_TYPE === 'app-automate') {
18
+ console.log("inside before session")
19
+ if (capabilities['bstack:options']) {
20
+ console.log("inside before session if block")
21
+
22
+ capabilities['bstack:options'].app = process.env.BROWSERSTACK_APP_PATH;
23
+ }
24
+ capabilities['appium:app'] = process.env.BROWSERSTACK_APP_PATH;
25
+ console.log('✅ App & media set in before session');
26
+
27
+ }
28
+ console.log('final cinfig dteials :' + JSON.stringify(capabilities))
29
+
30
+ console.log("config details " + JSON.stringify(config))
31
+
32
+
33
+ } catch (error) {
34
+ console.error('🚨 Error in beforeSession:', error);
35
+ console.error('🚨 Error in beforeSession:', error.message);
36
+ }
37
+ }
38
+ };
@@ -1,46 +1,235 @@
1
1
 
2
2
  const setAllDetails = require('./setallDatailinBuffer');
3
- let getExeDetails;
4
- module.exports = {
3
+ const exeDetails = require('../froth_api_calls/getexecutionDetails');
4
+ const { getBSSessionDetails } = require('../froth_api_calls/browsersatckSessionInfo');
5
+ let globalErrorHandled = false;
6
+ let suiteStartTime;
7
+ let totalTestDuration = 0;
8
+ const url = require('url');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ const resultdetails = {
13
+ comments: [],
14
+ excution_status: null,
15
+ excution_time: null
16
+ };
17
+
18
+ /* ----------------- GLOBAL ERROR HANDLERS ----------------- */
19
+ let globalErrorRegistered = false;
20
+ function registerGlobalErrorHandlers() {
21
+ if (globalErrorRegistered) return;
22
+ globalErrorRegistered = true;
23
+
24
+ process.on('uncaughtException', async (err) => {
25
+ console.error('🔥 Uncaught Exception:', err);
26
+ resultdetails.excution_status = 'FAILED';
27
+ resultdetails.comments.push(`Uncaught Exception: ${err.message}`);
28
+ await safeUpdateExecution();
29
+ process.exit(1);
30
+ });
31
+
32
+ process.on('unhandledRejection', async (reason) => {
33
+ console.error('🔥 Unhandled Rejection:', reason);
34
+ resultdetails.excution_status = 'FAILED';
35
+ resultdetails.comments.push(`Unhandled Rejection: ${reason?.message || reason}`);
36
+ await safeUpdateExecution();
37
+ process.exit(1);
38
+ });
39
+ }
40
+
41
+ async function safeUpdateExecution() {
42
+ try {
43
+ await exeDetails.updateExecuitonDetails(
44
+ BUFFER.getItem('ORGANISATION_DOMAIN_URL'),
45
+ BUFFER.getItem('FROTH_LOGIN_TOKEN'),
46
+ BUFFER.getItem('FROTH_EXECUTION_ID'),
47
+ resultdetails
48
+ );
49
+ } catch (e) {
50
+ console.error('❌ Failed to update execution details:', e.message);
51
+ }
52
+ }
53
+
54
+ /* ----------------- HELPER FUNCTIONS ----------------- */
55
+ function msToTime(ms) {
56
+ const sec = Math.floor(ms / 1000);
57
+ return new Date(sec * 1000).toISOString().substr(11, 8);
58
+ }
59
+
60
+ async function failExecution(reason) {
61
+ resultdetails.excution_status = 'FAILED';
62
+ resultdetails.comments.push(reason);
63
+ await safeUpdateExecution();
64
+ process.exit(1);
65
+ }
66
+ /* ------------------ COMMON CONFIG ------------------ */
67
+
68
+ const commonHooks = {
69
+
70
+ /* ========== ON PREPARE ========== */
5
71
  onPrepare: async () => {
72
+ registerGlobalErrorHandlers();
73
+
6
74
  console.log('==== ON PREPARE HOOK ====');
7
75
  await setAllDetails.setEnvVariables();
8
- getExeDetails = await setAllDetails.setExecutionDetails();
9
-
76
+ await setAllDetails.setExecutionDetails();
10
77
  await setAllDetails.setSuiteDetails();
11
78
  await setAllDetails.setTestDataDetails();
12
79
 
13
- console.log('✅ App & media updated before execution');
80
+ console.log('✅ All Env Varibale set');
14
81
  },
15
82
 
83
+ /* ========== BEFORE SESSION ========== */
84
+
16
85
  beforeSession: async function (config, capabilities, specs) {
86
+ console.log('==== BEFORE SESSION ====');
17
87
  try {
18
- if (config.services) {
19
- const bsService = config.services.find(
20
- s => Array.isArray(s) && s[0] === 'browserstack'
21
- );
22
-
23
- // if (bsService) {
24
- // bsService[1].app = process.env.BROWSERSTACK_APP_PATH
25
- // // bsService[1].browserstackLocal = isLocal;
26
-
27
- // if (isLocal) {
28
- // bsService[1].opts = bsService[1].opts || {};
29
- // bsService[1].opts.forcelocal = true;
30
- // bsService[1].opts.localIdentifier = `wdio-${process.pid}`;
31
- // }
32
-
33
- // console.log(`✅ BrowserStack Local: ${bsService[1].browserstackLocal}`);
34
- console.log(`✅ App Path: ${bsService[1].app}`);
35
- console.log("config details " + JSON.stringify(config))
36
- console.log("Capability details " + JSON.stringify(capabilities))
37
-
38
- // }
88
+ /** 1️⃣ Validate test syntax */
89
+ let syntaxFailed = false;
90
+
91
+ for (const fileUrl of specs) {
92
+ const filePath = url.fileURLToPath(fileUrl);
93
+ try {
94
+ new Function(fs.readFileSync(filePath, 'utf8'));
95
+ } catch (err) {
96
+ const msg = `❌ Syntax error in ${path.basename(filePath)}: ${err.message}`;
97
+ console.error(msg);
98
+ resultdetails.comments.push(msg);
99
+ syntaxFailed = true;
100
+ }
101
+ }
102
+
103
+ if (syntaxFailed) {
104
+ await failExecution('Syntax validation failed');
105
+ }
106
+ /** 2️⃣ BrowserStack capability normalization */
107
+
108
+ if (process.env.PLATFORM === 'browserstack' || process.env.PLATFORM === 'browserstacklocal') {
109
+ const bsOpts = capabilities['bstack:options'] || {};
110
+ if (process.env.BS_SESSION_TYPE === 'app-automate') {
111
+ const appPath = process.env.BROWSERSTACK_APP_PATH;
112
+ if (!appPath) {
113
+ await failExecution('BROWSERSTACK_APP_PATH is missing');
114
+ }
115
+
116
+ bsOpts.app = appPath;
117
+ capabilities['appium:app'] = appPath;
118
+ console.log('✅ App & media set in before session');
119
+
120
+ }
121
+ /** Media upload */
122
+ if (process.env.MEDIA_FILES) {
123
+ try {
124
+ bsOpts['browserstack.uploadMedia'] = JSON.parse(process.env.MEDIA_FILES);
125
+ } catch {
126
+ console.warn('⚠️ MEDIA_FILES is not valid JSON');
127
+ }
128
+ }
129
+ capabilities['bstack:options'] = bsOpts;
130
+
39
131
  }
132
+ console.log('final cinfig dteials :' + JSON.stringify(capabilities))
133
+
134
+ console.log("config details " + JSON.stringify(config))
135
+
40
136
 
41
137
  } catch (error) {
42
138
  console.error('🚨 Error in beforeSession:', error);
43
139
  console.error('🚨 Error in beforeSession:', error.message);
44
140
  }
45
- }
141
+ },
142
+ /* ========== BEFORE SUITE ========== */
143
+ beforeSuite: async (suite) => {
144
+ console.log(`==== BEFORE SUITE: ${suite.title} ====`);
145
+ suiteStartTime = Date.now();
146
+
147
+ if (process.env.PLATFORM === 'browserstack' || process.env.PLATFORM === 'browserstacklocal') {
148
+ await getBSSessionDetails(
149
+ process.env.BS_SESSION_TYPE,
150
+ process.env.BROWSERSTACK_USERNAME,
151
+ process.env.BROWSERSTACK_ACCESS_KEY
152
+ );
153
+ }
154
+
155
+ await exeDetails.update_CICDRUNID_ReportUrl(
156
+ BUFFER.getItem('ORGANISATION_DOMAIN_URL'),
157
+ BUFFER.getItem('FROTH_LOGIN_TOKEN'),
158
+ BUFFER.getItem('FROTH_EXECUTION_ID')
159
+ );
160
+ },
161
+ /* ========== BEFORE TEST ========== */
162
+ beforeTest: async (test) => {
163
+ console.log(`▶️ START TEST: ${test.title}`);
164
+ },
165
+
166
+ /* ========== AFTER TEST ========== */
167
+ afterTest: async (test, _, { error, duration, passed }) => {
168
+ totalTestDuration += duration;
169
+
170
+ const fileName = path.basename(test.file);
171
+ const status = passed ? 'PASSED' : 'FAILED';
172
+
173
+ if (!passed) {
174
+ resultdetails.comments.push(`${test.title} - ${error?.message || 'Failed'}`);
175
+ }
176
+
177
+ const suiteDetails = JSON.parse(BUFFER.getItem('FROTHE_SUITE_DETAILS'));
178
+ const script = suiteDetails.find(s => s.scriptName === fileName.replace('.js', ''));
179
+
180
+ await exeDetails.updateScriptExecutionStatus(
181
+ BUFFER.getItem('ORGANISATION_DOMAIN_URL'),
182
+ BUFFER.getItem('FROTH_LOGIN_TOKEN'),
183
+ script.scriptId,
184
+ script.platform.toLowerCase(),
185
+ status
186
+ );
187
+ },
188
+ /* ==== AFTER SESSION ==== */
189
+ afterSession: async (config, capabilities, specs, exitCode) => {
190
+ console.log('==== AFTER SESSION ====');
191
+
192
+ const totalTime = Date.now() - suiteStartTime;
193
+ resultdetails.excution_status = exitCode === 0 ? 'PASSED' : 'FAILED';
194
+ resultdetails.excution_time = msToTime(Math.max(totalTime, totalTestDuration));
195
+
196
+ // Capture WebDriver session failures
197
+ if (exitCode !== 0) {
198
+ resultdetails.comments.push(`❌ WebDriver session failed or timed out (exit code ${exitCode})`);
199
+ }
200
+
201
+ await safeUpdateExecution();
202
+ BUFFER.clear();
203
+ },
204
+
205
+ /* ========== ON ERROR ========== */
206
+
207
+ onError: async function (error) {
208
+ console.error('==== ON ERROR HOOK ====');
209
+ console.error('Error occurred:', error.message);
210
+
211
+ // Normalize all framework-level failures
212
+ resultdetails.excution_status = 'FAILED';
213
+ resultdetails.comments.push(`WDIO Error: ${error.message}`);
214
+
215
+ // Special handling for BrowserStack timeout
216
+ if (error.message?.includes('Automate testing time expired')) {
217
+ resultdetails.comments.push(
218
+ 'BrowserStack session timed out (Automate testing time expired)'
219
+ );
220
+ }
221
+
222
+ await safeUpdateExecution();
223
+ },
224
+ /* ========== ON COMPLETE ========== */
225
+ onComplete: async (exitCode, _, __, results) => {
226
+ console.log('==== ON COMPLETE ====');
227
+ console.log(`Total: ${results.total}, Passed: ${results.passed}, Failed: ${results.failed}`);
228
+ return exitCode;
229
+ },
230
+
231
+
232
+
46
233
  };
234
+
235
+ module.exports = commonHooks;
@@ -2,12 +2,12 @@ const getLoginToken = require("../froth_api_calls/loginapi");
2
2
  const exeDetails = require("../froth_api_calls/getexecutionDetails")
3
3
  const getSuiteDetails = require("../froth_api_calls/getsuiteDetails");
4
4
  const getDataById = require("../froth_api_calls/readTestdata");
5
- BUFFER.setItem("FROTH_TOTAL_DURATION", 0);
6
- BUFFER.setItem("FROTH_EXECUTION_ID", process.env.EXECUTION_ID || 1);
7
- BUFFER.setItem("ORGANISATION_DOMAIN_URL", process.env.ORGANISATION_DOMAIN_URL || "https://devapi.frothtestops.com");
8
- BUFFER.setItem("FROTH_LOGIN_TOKEN", process.env.API_TOKEN)
9
- console.log("api token in set evn variable :" + BUFFER.getItem("FROTH_LOGIN_TOKEN"))
10
- console.log("CICD_RUN_ID in set evn variable :" + process.env.CICD_RUN_ID)
5
+ // BUFFER.setItem("FROTH_TOTAL_DURATION", 0);
6
+ // BUFFER.setItem("FROTH_EXECUTION_ID", process.env.EXECUTION_ID || 1);
7
+ // BUFFER.setItem("ORGANISATION_DOMAIN_URL", process.env.ORGANISATION_DOMAIN_URL || "https://devapi.frothtestops.com");
8
+ // BUFFER.setItem("FROTH_LOGIN_TOKEN", process.env.API_TOKEN)
9
+ // console.log("api token in set evn variable :" + BUFFER.getItem("FROTH_LOGIN_TOKEN"))
10
+ // console.log("CICD_RUN_ID in set evn variable :" + process.env.CICD_RUN_ID)
11
11
  async function generateBuildNumber() {
12
12
  try {
13
13
  const now = await new Date();
@@ -48,16 +48,11 @@ console.log('====> BS SESSION TYPE :', process.env.BS_SESSION_TYPE);
48
48
  // --------------------
49
49
  // Load env-specific config
50
50
  // --------------------
51
- if (PLATFORM === 'browserstack') {
51
+ if (PLATFORM === 'browserstack' || PLATFORM === 'browserstacklocal') {
52
52
  envConfig =
53
53
  OS === 'web'
54
54
  ? require('./browserstack/web.config')
55
55
  : require('./browserstack/mobile.config');
56
- } else if (PLATFORM === 'browserstacklocal') {
57
- envConfig =
58
- OS === 'web'
59
- ? require('./browserstack/weblocal.config')
60
- : require('./browserstack/mobilelocal.config');
61
56
  } else {
62
57
  envConfig =
63
58
  OS === 'web'
@@ -68,28 +63,3 @@ if (PLATFORM === 'browserstack') {
68
63
 
69
64
  exports.config = deepmerge(baseConfig, envConfig(bsCaps));
70
65
 
71
- // Merge base + env config
72
- //const finalConfig = deepmerge(baseConfig, envConfig(bsCaps));
73
-
74
- // --------------------
75
- // Before session hook to dynamically update app
76
- // --------------------
77
- // finalConfig.beforeSession = async function (config, capabilities, specs) {
78
- // if (OS === 'mobile') {
79
- // console.log('====> Updating app before session');
80
- // await setAllDetails.setEnvVariables();
81
- // getExeDetails = await setAllDetails.setExecutionDetails();
82
- // await setAllDetails.setSuiteDetails();
83
- // await setAllDetails.setTestDataDetails();
84
-
85
- // // const appPath = process.env.BROWSERSTACK_APP_PATH || bsCaps.app;
86
- // // // Find the browserstack service object
87
- // // const bsService = config.services.find(s => Array.isArray(s) && s[0] === 'browserstack');
88
- // // if (bsService && bsService[1]) {
89
- // // bsService[1].app = process.env.BROWSERSTACK_APP_PATH || bsCaps.app;
90
- // // console.log('====> App path set to:', bsService[1].app);
91
- // // }
92
- // };
93
- // }
94
-
95
- //exports.config = finalConfig;
package/local.log CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
 
3
- Sat Dec 13 2025 18:08:44:22 GMT+0800 (+08) -- [WARNING] Skipping initialisation of configuration console because: port already in use by another Binary
4
- Sat Dec 13 2025 18:08:45:882 GMT+0800 (+08) -- [SUCCESS] You can now access your local server(s) in our remote browser
3
+ Sat Dec 13 2025 23:24:22:84 GMT+0800 (+08) -- [WARNING] Skipping initialisation of configuration console because: port already in use by another Binary
4
+ Sat Dec 13 2025 23:24:24:305 GMT+0800 (+08) -- [SUCCESS] You can now access your local server(s) in our remote browser
5
5
 
6
- Sat Dec 13 2025 18:08:46:471 GMT+0800 (+08) -- Press Ctrl-C to exit
6
+ Sat Dec 13 2025 23:24:25:180 GMT+0800 (+08) -- Press Ctrl-C to exit
7
7
 
8
8