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 = null;
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
- // extractEmailLinks
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
- const status = passed ? 'PASSED' : 'FAILED';
221
- const msg = `${test.title} - ${passed ? 'Passed' : error?.message || 'Failed'}`;
222
- await pushComment(msg);
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.83",
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": {