froth-webdriverio-framework 6.0.83 → 6.0.85
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.
|
@@ -134,7 +134,7 @@ async function updateExecuitonDetails(frothUrl, token, id, resultdetails) {
|
|
|
134
134
|
formData.append('excution_time', resultdetails.excution_time);
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
if (Array.isArray(resultdetails.comments) && resultdetails.comments.length) {
|
|
137
|
+
if (Array.isArray(resultdetails.comments) && resultdetails.comments.length!=0) {
|
|
138
138
|
formData.append('comments', resultdetails.comments.join('<br>'));
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -41,7 +41,7 @@ let scrollIntoView = null;
|
|
|
41
41
|
let api = null;
|
|
42
42
|
|
|
43
43
|
let selectDropDownValue = null;
|
|
44
|
-
let selectDropDownText
|
|
44
|
+
let selectDropDownText = null;
|
|
45
45
|
|
|
46
46
|
let acceptAlert = null;
|
|
47
47
|
let dismissAlert = null;
|
|
@@ -106,16 +106,16 @@ api = require(basepath + '/apicall').callapi;
|
|
|
106
106
|
validate = require(basepath + '/apicall').validate;
|
|
107
107
|
|
|
108
108
|
selectDropDownValue = require(basepath + '/dropDown').select4mDropDownValue;
|
|
109
|
-
selectDropDownText= require(basepath + '/dropDown').select4mDropDownText;
|
|
109
|
+
selectDropDownText = require(basepath + '/dropDown').select4mDropDownText;
|
|
110
110
|
|
|
111
111
|
acceptAlert = require(basepath + '/alert.js').acceptalert;
|
|
112
112
|
dismissAlert = require(basepath + '/alert.js').dismissalert;
|
|
113
113
|
|
|
114
114
|
generateJWT = require(basepath + '/jwt').generateJWTToken;
|
|
115
|
-
captureLoadNavigation= require(basepath + '/captureNavigationTime').captureLoadNavigationTime;
|
|
115
|
+
captureLoadNavigation = require(basepath + '/captureNavigationTime').captureLoadNavigationTime;
|
|
116
116
|
|
|
117
|
-
amendBrowserStackLog= require(basepath + '/../froth_api_calls/browsersatckSessionInfo').amend2Browserstack;
|
|
118
|
-
logJsonDataToTable= require(basepath + '/logData').logJsonData2Table;
|
|
117
|
+
amendBrowserStackLog = require(basepath + '/../froth_api_calls/browsersatckSessionInfo').amend2Browserstack;
|
|
118
|
+
logJsonDataToTable = require(basepath + '/logData').logJsonData2Table;
|
|
119
119
|
|
|
120
120
|
//extractEmailLinks = require(basepath + '/emailParsing');
|
|
121
121
|
//export the variabels
|
|
@@ -163,5 +163,5 @@ module.exports = {
|
|
|
163
163
|
captureLoadNavigation,
|
|
164
164
|
amendBrowserStackLog,
|
|
165
165
|
logJsonDataToTable,
|
|
166
|
-
|
|
166
|
+
extractEmailLinks
|
|
167
167
|
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
2
|
+
|
|
3
|
+
const Imap = require('imap');
|
|
4
|
+
const { simpleParser } = require('mailparser');
|
|
5
|
+
const cheerio = require('cheerio');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Connects to an IMAP inbox, parses emails, and extracts all unique links.
|
|
9
|
+
* @param {Object} config - IMAP config { user, password, host, port, tls }
|
|
10
|
+
* @param {Object} [filter] - Optional filter { subject, from }
|
|
11
|
+
* @returns {Promise<Array<{link: string, text: string}>>}
|
|
12
|
+
*/
|
|
13
|
+
async function getEmailLinks(username,app_password, subjectdetails,fromemail) {
|
|
14
|
+
const config = {
|
|
15
|
+
user: username,
|
|
16
|
+
password: app_password,
|
|
17
|
+
host: 'imap.gmail.com',
|
|
18
|
+
port: 993,
|
|
19
|
+
tls: true
|
|
20
|
+
};
|
|
21
|
+
const filter = {
|
|
22
|
+
subject: subjectdetails,
|
|
23
|
+
from: fromemail
|
|
24
|
+
};
|
|
25
|
+
const imap = new Imap(config);
|
|
26
|
+
|
|
27
|
+
function openInbox(cb) {
|
|
28
|
+
imap.openBox('INBOX', true, cb);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
let results = new Map();
|
|
33
|
+
let allLinks = [];
|
|
34
|
+
let parseDone;
|
|
35
|
+
const parsePromise = new Promise(res => { parseDone = res; });
|
|
36
|
+
|
|
37
|
+
imap.once('ready', function () {
|
|
38
|
+
openInbox(function (err, box) {
|
|
39
|
+
if (err) return cleanup(err);
|
|
40
|
+
|
|
41
|
+
// Build search criteria
|
|
42
|
+
let searchCriteria = ['ALL'];
|
|
43
|
+
if (filter.subject) searchCriteria.push(['HEADER', 'SUBJECT', filter.subject]);
|
|
44
|
+
if (filter.from) searchCriteria.push(['FROM', filter.from]);
|
|
45
|
+
|
|
46
|
+
imap.search(searchCriteria, function (err, uids) {
|
|
47
|
+
if (err) return cleanup(err);
|
|
48
|
+
if (!uids.length) return cleanup(null, []);
|
|
49
|
+
|
|
50
|
+
// Sort UIDs descending to get the latest email first
|
|
51
|
+
uids = uids.sort((a, b) => b - a);
|
|
52
|
+
// Only fetch the latest email
|
|
53
|
+
const latestUid = uids[0];
|
|
54
|
+
const fetch = imap.fetch([latestUid], { bodies: '' });
|
|
55
|
+
fetch.on('message', function (msg) {
|
|
56
|
+
let buffer = '';
|
|
57
|
+
msg.on('body', function (stream) {
|
|
58
|
+
stream.on('data', function (chunk) {
|
|
59
|
+
buffer += chunk.toString('utf8');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
msg.once('end', async function () {
|
|
63
|
+
try {
|
|
64
|
+
const parsed = await simpleParser(buffer);
|
|
65
|
+
let links = [];
|
|
66
|
+
|
|
67
|
+
// Extract from HTML with element context
|
|
68
|
+
if (parsed.html) {
|
|
69
|
+
const $ = cheerio.load(parsed.html);
|
|
70
|
+
$('a[href], button[href], [role="button"][href], img[src], area[href]').each((_, el) => {
|
|
71
|
+
let link = null;
|
|
72
|
+
let text = '';
|
|
73
|
+
let elementType = el.tagName;
|
|
74
|
+
if (elementType === 'a' || elementType === 'area') {
|
|
75
|
+
link = $(el).attr('href');
|
|
76
|
+
text = $(el).text().trim() || link;
|
|
77
|
+
} else if (elementType === 'img') {
|
|
78
|
+
link = $(el).attr('src');
|
|
79
|
+
text = $(el).attr('alt') || link;
|
|
80
|
+
} else if (elementType === 'button' || $(el).attr('role') === 'button') {
|
|
81
|
+
link = $(el).attr('href');
|
|
82
|
+
text = $(el).text().trim() || link;
|
|
83
|
+
}
|
|
84
|
+
if (link) {
|
|
85
|
+
links.push({ link, text, element: elementType });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Extract from plaintext
|
|
91
|
+
if (parsed.text) {
|
|
92
|
+
const urlRegex = /(https?:\/\/[^\s]+)/g;
|
|
93
|
+
let match;
|
|
94
|
+
while ((match = urlRegex.exec(parsed.text))) {
|
|
95
|
+
links.push({ link: match[1], text: match[1], element: 'text' });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Deduplicate by link and element context
|
|
100
|
+
for (const l of links) {
|
|
101
|
+
const key = l.link + '|' + l.element + '|' + l.text;
|
|
102
|
+
if (!results.has(key)) {
|
|
103
|
+
results.set(key, { link: l.link, text: l.text, element: l.element });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
allLinks = Array.from(results.values());
|
|
107
|
+
parseDone();
|
|
108
|
+
} catch (e) {
|
|
109
|
+
// Log and continue
|
|
110
|
+
console.error('Parse error:', e);
|
|
111
|
+
parseDone();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
fetch.once('error', cleanup);
|
|
116
|
+
fetch.once('end', async () => {
|
|
117
|
+
await parsePromise;
|
|
118
|
+
cleanup(null, allLinks);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
imap.once('error', cleanup);
|
|
125
|
+
|
|
126
|
+
function cleanup(err, data) {
|
|
127
|
+
imap.end();
|
|
128
|
+
if (err) reject(err);
|
|
129
|
+
else resolve(data);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
imap.connect();
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function findLinks(links,searchText) {
|
|
137
|
+
const findLinkByText = (links, searchText) => {
|
|
138
|
+
return links.find(l => l.text && l.text.toLowerCase().includes(searchText.toLowerCase()));
|
|
139
|
+
};
|
|
140
|
+
// Example usage:
|
|
141
|
+
const found = findLinkByText(links, searchText);
|
|
142
|
+
return found ? found.link : null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
// Example main function for direct execution
|
|
147
|
+
// if (require.main === module) {
|
|
148
|
+
// (async () => {
|
|
149
|
+
|
|
150
|
+
// const links = await extractEmailLinks('gfntesting44@gmail.com','wtrd qfee dicr hpba', "GFN Testing, review your Google Account settings","no-reply@google.com");
|
|
151
|
+
// console.log('Extracted links in main:', links);
|
|
152
|
+
// const foundLink = await findLinks(links,"Privacy Policy");
|
|
153
|
+
// console.log('Found Link: ', foundLink);
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
// })();
|
|
157
|
+
|
|
158
|
+
// }
|
|
159
|
+
|
|
160
|
+
module.exports = { getEmailLinks ,findLinks}
|
|
161
|
+
|
|
@@ -14,8 +14,6 @@ const resultdetails = {
|
|
|
14
14
|
excution_status: null,
|
|
15
15
|
excution_time: null
|
|
16
16
|
};
|
|
17
|
-
// At top of commonHooks.js
|
|
18
|
-
global.TEST_COMMENTS = [];
|
|
19
17
|
|
|
20
18
|
/* ----------------- GLOBAL ERROR HANDLERS ----------------- */
|
|
21
19
|
let globalErrorRegistered = false;
|
|
@@ -217,9 +215,22 @@ const commonHooks = {
|
|
|
217
215
|
totalTestDuration += duration;
|
|
218
216
|
|
|
219
217
|
const fileName = path.basename(test.file);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
218
|
+
let scriptresult = "NOT RUN";
|
|
219
|
+
// Default assumption: test passed (unless soft assertion failed)
|
|
220
|
+
let finalPassed = passed;
|
|
221
|
+
|
|
222
|
+
if (passed) {
|
|
223
|
+
scriptresult = "PASSED"
|
|
224
|
+
resultdetails.comments.push(`${test.title} - passed`);
|
|
225
|
+
console.log(`====> resultdetails comments: ${resultdetails.comments}`);
|
|
226
|
+
}
|
|
227
|
+
else if (!finalPassed || error) {
|
|
228
|
+
scriptresult = "FAILED"
|
|
229
|
+
console.log(`====> Failed or error while executing the test: ${error ? error.message : "Test failed"}`);
|
|
230
|
+
if (!resultdetails.comments.some(comment => typeof comment === 'string' && comment.includes(test.title)))
|
|
231
|
+
resultdetails.comments.push(`${test.title} - failed: ${error ? error.message : "Test failed"}`);
|
|
232
|
+
|
|
233
|
+
}
|
|
223
234
|
|
|
224
235
|
const suiteDetails = JSON.parse(BUFFER.getItem('FROTHE_SUITE_DETAILS'));
|
|
225
236
|
const script = suiteDetails.find(s => s.scriptName === fileName.replace('.js', ''));
|
|
@@ -247,7 +258,8 @@ const commonHooks = {
|
|
|
247
258
|
afterSession: async (config, capabilities, specs, exitCode) => {
|
|
248
259
|
console.log('==== AFTER SESSION ====');
|
|
249
260
|
// Do not calculate time here; we will use WDIO's total duration in onComplete
|
|
250
|
-
console.log('⏱ Leaving execution time calculation for onComplete hook');
|
|
261
|
+
console.log('⏱ Leaving execution time calculation for onComplete hook'+resultdetails.comments);
|
|
262
|
+
|
|
251
263
|
|
|
252
264
|
},
|
|
253
265
|
|
|
@@ -281,13 +293,13 @@ const commonHooks = {
|
|
|
281
293
|
resultdetails.excution_time = await msToTime(totalTime);
|
|
282
294
|
resultdetails.excution_status = exitCode === 0 ? 'PASSED' : 'FAILED';
|
|
283
295
|
|
|
284
|
-
const allComments = global.TEST_COMMENTS || [];
|
|
285
|
-
if (allComments.length === 0 && exitCode === 0) allComments.push('All tests passed ✅');
|
|
286
|
-
if (exitCode !== 0 && allComments.length === 0) allComments.push(`Execution failed with exit code ${exitCode}`);
|
|
296
|
+
// const allComments = global.TEST_COMMENTS || [];
|
|
297
|
+
// if (allComments.length === 0 && exitCode === 0) allComments.push('All tests passed ✅');
|
|
298
|
+
// if (exitCode !== 0 && allComments.length === 0) allComments.push(`Execution failed with exit code ${exitCode}`);
|
|
287
299
|
|
|
288
|
-
resultdetails.comments = allComments;
|
|
300
|
+
// resultdetails.comments = allComments;
|
|
289
301
|
|
|
290
|
-
console.log('Comments being sent:', resultdetails.comments);
|
|
302
|
+
console.log('Comments being sent:', resultdetails.comments.length==0?'':JSON.stringify(resultdetails.comments));
|
|
291
303
|
console.log('⏱ Final execution time (ms):', totalTime);
|
|
292
304
|
console.log('⏱ Final execution time (hh:mm:ss):', resultdetails.excution_time);
|
|
293
305
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "froth-webdriverio-framework",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.85",
|
|
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": {
|