froth-webdriverio-framework 6.0.71 → 6.0.73
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.
|
@@ -3,243 +3,248 @@
|
|
|
3
3
|
========================================================= */
|
|
4
4
|
|
|
5
5
|
const DEFAULT_HEADERS = (token) => ({
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
'Authorization': `Bearer ${token}`,
|
|
7
|
+
'Content-Type': 'application/json'
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
/* ===================== HELPERS ===================== */
|
|
11
11
|
|
|
12
12
|
function isValidId(id) {
|
|
13
|
-
|
|
13
|
+
return id !== null && id !== undefined && id !== 0;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
async function handleResponse(response, context) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
if (response.ok) {
|
|
18
|
+
return response.json();
|
|
19
|
+
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
if (response.status === 401) {
|
|
22
|
+
console.error(`🔒 Unauthorized (401) in ${context}`);
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const errorText = await response.text();
|
|
27
|
+
console.error(`❌ ${context} failed [${response.status}]: ${errorText}`);
|
|
28
|
+
return null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/* ===================== GET EXECUTION ===================== */
|
|
32
32
|
|
|
33
33
|
async function getExecuitonDetails(frothUrl, token, id) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
if (!isValidId(id)) {
|
|
35
|
+
console.error('❌ Invalid execution ID');
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
const url = `${frothUrl}/api/test-execution-retrieve/${id}/`;
|
|
40
|
+
console.log('GET:', url);
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
try {
|
|
43
|
+
const response = await fetch(url, {
|
|
44
|
+
method: 'GET',
|
|
45
|
+
headers: DEFAULT_HEADERS(token)
|
|
46
|
+
});
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
const data = await handleResponse(response, 'getExecuitonDetails');
|
|
49
|
+
if (!data) return null;
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
const jsondata = {
|
|
52
|
+
automation_suite_id: data?.automation_suite_details?.id ?? null,
|
|
53
|
+
test_cycle_id: data?.test_cycle_details?.id ?? null,
|
|
54
|
+
app_url: data?.app_details?.app_url ?? null,
|
|
55
|
+
browser_stack_local: data?.capability_details?.browser_stack_local ?? null,
|
|
56
|
+
mediaurls: data?.media_details?.map(m => m.media_url) ?? []
|
|
57
|
+
};
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
console.log('✅ Execution details loaded');
|
|
60
|
+
return jsondata;
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error('❌ getExecuitonDetails error:', error.message);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/* ===================== SCRIPT MAPPING ===================== */
|
|
69
69
|
|
|
70
70
|
async function getExecuitonScriptDetails(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
frothUrl,
|
|
72
|
+
token,
|
|
73
|
+
execution_id,
|
|
74
|
+
script_id,
|
|
75
|
+
script_platform
|
|
76
76
|
) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
if (!isValidId(script_id)) {
|
|
78
|
+
console.error('❌ Invalid script ID');
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
const url =
|
|
83
|
+
`${frothUrl}/api/execution-script-mapping/` +
|
|
84
|
+
`?execution_id=${execution_id}` +
|
|
85
|
+
`&automation_script_id=${script_id}` +
|
|
86
|
+
`&platform=${script_platform}`;
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
console.log('GET:', url);
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(url, {
|
|
92
|
+
method: 'GET',
|
|
93
|
+
headers: DEFAULT_HEADERS(token)
|
|
94
|
+
});
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
const data = await handleResponse(response, 'getExecuitonScriptDetails');
|
|
97
|
+
if (!data || !data.length) return null;
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
return data[0].id;
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error('❌ getExecuitonScriptDetails error:', error.message);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/* ===================== UPDATE EXECUTION ===================== */
|
|
108
108
|
|
|
109
109
|
async function updateExecuitonDetails(frothUrl, token, id, resultdetails) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (BUFFER.getItem('FROTH_UPDATE_EXECUTION') === 'TRUE') {
|
|
116
|
-
console.log('ℹ️ Execution already updated — skipping');
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const url = `${frothUrl}/api/test-execution-update/${id}/`;
|
|
121
|
-
const formData = new FormData();
|
|
122
|
-
|
|
123
|
-
console.log('PUT:', url);
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
formData.append('updated_through_bot', true);
|
|
127
|
-
|
|
128
|
-
if (resultdetails.excution_status) {
|
|
129
|
-
formData.append('excution_status', resultdetails.excution_status);
|
|
110
|
+
if (!isValidId(id)) {
|
|
111
|
+
console.error('❌ Invalid execution ID for update');
|
|
112
|
+
return;
|
|
130
113
|
}
|
|
131
114
|
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
) {
|
|
136
|
-
formData.append('excution_time', resultdetails.excution_time);
|
|
115
|
+
if (BUFFER.getItem('FROTH_UPDATE_EXECUTION') === 'TRUE') {
|
|
116
|
+
console.log('ℹ️ Execution already updated — skipping');
|
|
117
|
+
return;
|
|
137
118
|
}
|
|
138
119
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const response = await fetch(url, {
|
|
144
|
-
method: 'PUT',
|
|
145
|
-
headers: { 'Authorization': `Bearer ${token}` },
|
|
146
|
-
body: formData
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const data = await handleResponse(response, 'updateExecuitonDetails');
|
|
150
|
-
if (!data) return;
|
|
120
|
+
const url = `${frothUrl}/api/test-execution-update/${id}/`;
|
|
121
|
+
const formData = new FormData();
|
|
151
122
|
|
|
152
|
-
|
|
153
|
-
console.log('✅ Execution details updated');
|
|
123
|
+
console.log('PUT:', url);
|
|
154
124
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
125
|
+
try {
|
|
126
|
+
formData.append('updated_through_bot', true);
|
|
127
|
+
|
|
128
|
+
if (resultdetails.excution_status) {
|
|
129
|
+
formData.append('excution_status', resultdetails.excution_status);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
resultdetails.excution_time &&
|
|
134
|
+
resultdetails.excution_time !== 'NaN:NaN:NaN'
|
|
135
|
+
) {
|
|
136
|
+
formData.append('excution_time', resultdetails.excution_time);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (Array.isArray(resultdetails.comments) && resultdetails.comments.length) {
|
|
140
|
+
formData.append('comments', resultdetails.comments.join('<br>'));
|
|
141
|
+
}
|
|
142
|
+
// ✅ Log actual FormData keys
|
|
143
|
+
console.log('📤 FormData keys sent:');
|
|
144
|
+
for (const [key, value] of formData.entries()) {
|
|
145
|
+
console.log(` ${key}: ${value}`);
|
|
146
|
+
}
|
|
147
|
+
const response = await fetch(url, {
|
|
148
|
+
method: 'PUT',
|
|
149
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
150
|
+
body: formData
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
const data = await handleResponse(response, 'updateExecuitonDetails');
|
|
155
|
+
if (!data) return;
|
|
156
|
+
|
|
157
|
+
BUFFER.setItem('FROTH_UPDATE_EXECUTION', 'TRUE');
|
|
158
|
+
console.log('✅ Execution details updated');
|
|
159
|
+
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error('❌ updateExecuitonDetails error:', error.message);
|
|
162
|
+
}
|
|
158
163
|
}
|
|
159
164
|
|
|
160
165
|
/* ===================== UPDATE CICD / REPORT ===================== */
|
|
161
166
|
|
|
162
167
|
async function update_CICDRUNID_ReportUrl(frothUrl, token, id) {
|
|
163
|
-
|
|
168
|
+
if (!isValidId(id)) return;
|
|
164
169
|
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
const url = `${frothUrl}/api/test-execution-update/${id}/`;
|
|
171
|
+
const formData = new FormData();
|
|
167
172
|
|
|
168
|
-
|
|
173
|
+
console.log('PUT:', url);
|
|
169
174
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
175
|
+
try {
|
|
176
|
+
formData.append('updated_through_bot', true);
|
|
177
|
+
formData.append('run_id', process.env.CICD_RUN_ID);
|
|
173
178
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
const reportUrl = BUFFER.getItem('REPORT_URL');
|
|
180
|
+
if (reportUrl) {
|
|
181
|
+
formData.append('report_url', reportUrl);
|
|
182
|
+
}
|
|
178
183
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
+
const response = await fetch(url, {
|
|
185
|
+
method: 'PUT',
|
|
186
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
187
|
+
body: formData
|
|
188
|
+
});
|
|
184
189
|
|
|
185
|
-
|
|
190
|
+
await handleResponse(response, 'update_CICDRUNID_ReportUrl');
|
|
186
191
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error('❌ update_CICDRUNID_ReportUrl error:', error.message);
|
|
194
|
+
}
|
|
190
195
|
}
|
|
191
196
|
|
|
192
197
|
/* ===================== UPDATE SCRIPT STATUS ===================== */
|
|
193
198
|
|
|
194
199
|
async function updateScriptExecutionStatus(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
frothUrl,
|
|
201
|
+
token,
|
|
202
|
+
scriptid,
|
|
203
|
+
script_platform,
|
|
204
|
+
status
|
|
200
205
|
) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
try {
|
|
207
|
-
const mappingId = await getExecuitonScriptDetails(
|
|
208
|
-
frothUrl,
|
|
209
|
-
token,
|
|
210
|
-
BUFFER.getItem('FROTH_EXECUTION_ID'),
|
|
211
|
-
scriptid,
|
|
212
|
-
script_platform
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
if (!mappingId) return;
|
|
216
|
-
|
|
217
|
-
const url = `${frothUrl}/api/script-status-percentage/${mappingId}/`;
|
|
218
|
-
const formData = new FormData();
|
|
206
|
+
if (!isValidId(scriptid)) {
|
|
207
|
+
console.error('❌ Invalid script ID');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
219
210
|
|
|
220
|
-
|
|
211
|
+
try {
|
|
212
|
+
const mappingId = await getExecuitonScriptDetails(
|
|
213
|
+
frothUrl,
|
|
214
|
+
token,
|
|
215
|
+
BUFFER.getItem('FROTH_EXECUTION_ID'),
|
|
216
|
+
scriptid,
|
|
217
|
+
script_platform
|
|
218
|
+
);
|
|
221
219
|
|
|
222
|
-
|
|
223
|
-
formData.append('updated_through_bot', true);
|
|
220
|
+
if (!mappingId) return;
|
|
224
221
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
headers: { 'Authorization': `Bearer ${token}` },
|
|
228
|
-
body: formData
|
|
229
|
-
});
|
|
222
|
+
const url = `${frothUrl}/api/script-status-percentage/${mappingId}/`;
|
|
223
|
+
const formData = new FormData();
|
|
230
224
|
|
|
231
|
-
|
|
225
|
+
console.log('PUT:', url);
|
|
232
226
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
227
|
+
formData.append('script_status', status);
|
|
228
|
+
formData.append('updated_through_bot', true);
|
|
229
|
+
|
|
230
|
+
const response = await fetch(url, {
|
|
231
|
+
method: 'PUT',
|
|
232
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
233
|
+
body: formData
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await handleResponse(response, 'updateScriptExecutionStatus');
|
|
237
|
+
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.error('❌ updateScriptExecutionStatus error:', error.message);
|
|
240
|
+
}
|
|
236
241
|
}
|
|
237
242
|
|
|
238
243
|
/* ===================== EXPORTS ===================== */
|
|
239
244
|
|
|
240
245
|
module.exports = {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
246
|
+
getExecuitonDetails,
|
|
247
|
+
updateExecuitonDetails,
|
|
248
|
+
updateScriptExecutionStatus,
|
|
249
|
+
update_CICDRUNID_ReportUrl
|
|
245
250
|
};
|
|
@@ -216,13 +216,13 @@ const commonHooks = {
|
|
|
216
216
|
},
|
|
217
217
|
|
|
218
218
|
/* ==== AFTER SESSION ==== */
|
|
219
|
-
afterSession: async (config, capabilities, specs,exitCode) => {
|
|
219
|
+
afterSession: async (config, capabilities, specs, exitCode) => {
|
|
220
220
|
console.log('==== AFTER SESSION ====');
|
|
221
221
|
const endTime = Date.now();
|
|
222
222
|
if (!suiteStartTime) suiteStartTime = endTime;
|
|
223
223
|
|
|
224
224
|
const totalTime = Math.max(endTime - suiteStartTime, totalTestDuration);
|
|
225
|
-
|
|
225
|
+
// resultdetails.excution_status = exitCode === 0 ? 'PASSED' : 'FAILED';
|
|
226
226
|
resultdetails.excution_time = msToTime(totalTime);
|
|
227
227
|
|
|
228
228
|
console.log('⏱ Final execution time:', resultdetails.excution_time);
|
|
@@ -264,7 +264,30 @@ const commonHooks = {
|
|
|
264
264
|
if (exitCode !== 0 && resultdetails.comments.length === 0) {
|
|
265
265
|
resultdetails.comments.push(`Execution failed with exit code ${exitCode}`);
|
|
266
266
|
}
|
|
267
|
+
// ✅ Set final status
|
|
268
|
+
resultdetails.excution_status = exitCode === 0 ? 'PASSED' : 'FAILED';
|
|
269
|
+
|
|
270
|
+
// ✅ If execution failed but no comments, add default comment
|
|
271
|
+
if (exitCode !== 0 && resultdetails.comments.length === 0) {
|
|
272
|
+
resultdetails.comments.push(`Execution failed with exit code ${exitCode}`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ✅ Make sure excution_time is set (if not, fallback)
|
|
276
|
+
if (!resultdetails.excution_time || resultdetails.excution_time === 'NaN:NaN:NaN') {
|
|
277
|
+
const fallbackTime = totalTestDuration || 0;
|
|
278
|
+
resultdetails.excution_time = msToTime(fallbackTime);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
console.log('📤 Updating DB with final execution details');
|
|
282
|
+
console.log('Status:', resultdetails.excution_status);
|
|
283
|
+
console.log('Duration:', resultdetails.excution_time);
|
|
267
284
|
|
|
285
|
+
// await exeDetails.updateExecuitonDetails(
|
|
286
|
+
// BUFFER.getItem('ORGANISATION_DOMAIN_URL'),
|
|
287
|
+
// BUFFER.getItem('FROTH_LOGIN_TOKEN'),
|
|
288
|
+
// BUFFER.getItem('FROTH_EXECUTION_ID'),
|
|
289
|
+
// resultdetails
|
|
290
|
+
// );
|
|
268
291
|
await safeUpdateExecution();
|
|
269
292
|
BUFFER.clear();
|
|
270
293
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "froth-webdriverio-framework",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.73",
|
|
4
4
|
"readme": "WendriverIO Integration with [BrowserStack](https://www.browserstack.com)",
|
|
5
5
|
"description": "Selenium examples for WebdriverIO and BrowserStack App Automate",
|
|
6
6
|
"scripts": {
|