froth-webdriverio-framework 7.0.9 → 7.0.11

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.
@@ -0,0 +1,125 @@
1
+ const crypto = require('crypto');
2
+
3
+ //const SECRET_KEY = "froth-testops@rd";
4
+
5
+ async function encryptData(data, secretKey) {
6
+ try {
7
+ if (!data) return null
8
+
9
+ // Generate 12-byte nonce (GCM standard)
10
+ const nonce = crypto.getRandomValues(new Uint8Array(12))
11
+
12
+ // Import key (must be exactly 32 bytes)
13
+ const key = await crypto.subtle.importKey(
14
+ "raw",
15
+ new TextEncoder().encode(secretKey),
16
+ { name: "AES-GCM" },
17
+ false,
18
+ ["encrypt"]
19
+ )
20
+
21
+ // Encrypt
22
+ const encryptedBuffer = await crypto.subtle.encrypt(
23
+ {
24
+ name: "AES-GCM",
25
+ iv: nonce,
26
+ tagLength: 128, // 16 bytes
27
+ },
28
+ key,
29
+ new TextEncoder().encode(data)
30
+ )
31
+
32
+ // WebCrypto output = ciphertext + tag
33
+ const encryptedBytes = new Uint8Array(encryptedBuffer)
34
+
35
+ const ciphertext = encryptedBytes.slice(0, encryptedBytes.length - 16)
36
+ const tag = encryptedBytes.slice(encryptedBytes.length - 16)
37
+
38
+ // nonce + tag + ciphertext (same as backend)
39
+ const payload = new Uint8Array(
40
+ nonce.length + tag.length + ciphertext.length
41
+ )
42
+ payload.set(nonce)
43
+ payload.set(tag, nonce.length)
44
+ payload.set(ciphertext, nonce.length + tag.length)
45
+
46
+ // Base64 encode
47
+ return btoa(String.fromCharCode(...payload))
48
+ } catch (err) {
49
+ console.error("Encryption failed:", err)
50
+ return null
51
+ }
52
+ }
53
+
54
+
55
+
56
+
57
+ async function decrpytData(encryptedData) {
58
+ try {
59
+ if (!encryptedData) return null
60
+
61
+ // Base64 → Uint8Array
62
+ const encryptedBytes = Uint8Array.from(atob(encryptedData), c =>
63
+ c.charCodeAt(0)
64
+ )
65
+
66
+ // Extract nonce, tag, ciphertext
67
+ const nonce = encryptedBytes.slice(0, 12) // 12 bytes
68
+ const tag = encryptedBytes.slice(12, 28) // 16 bytes
69
+ const ciphertext = encryptedBytes.slice(28)
70
+
71
+ // WebCrypto expects: ciphertext + tag
72
+ const encryptedPayload = new Uint8Array(ciphertext.length + tag.length)
73
+ encryptedPayload.set(ciphertext)
74
+ encryptedPayload.set(tag, ciphertext.length)
75
+
76
+ // Import key
77
+ const key = await crypto.subtle.importKey(
78
+ "raw",
79
+ new TextEncoder().encode(config.encryptKeyValue),
80
+ { name: "AES-GCM" },
81
+ false,
82
+ ["decrypt"]
83
+ )
84
+
85
+ // Decrypt
86
+ const decryptedBuffer = await crypto.subtle.decrypt(
87
+ {
88
+ name: "AES-GCM",
89
+ iv: nonce,
90
+ tagLength: 128, // bits (16 bytes)
91
+ },
92
+ key,
93
+ encryptedPayload
94
+ )
95
+
96
+ return new TextDecoder().decode(decryptedBuffer)
97
+ } catch (error) {
98
+ console.error("Error decrypting:", error)
99
+ return null
100
+ }
101
+
102
+ }
103
+
104
+ module.exports = {
105
+ encryptData,
106
+ decrpytData
107
+ };
108
+
109
+ await encryptData(
110
+ data,
111
+ secret_key
112
+ )
113
+
114
+ const decrypted_data = await decrpytData(response)
115
+ const data = JSON.parse(decrypted_data)
116
+ console.log("decrpted data" + data)
117
+ return data
118
+
119
+ // Encrypt a password
120
+ //const encryptedPassword = encryptData("admin@1234", SECRET_KEY);
121
+ //console.log("Encrypted Password:", encryptedPassword);
122
+
123
+
124
+
125
+
@@ -91,32 +91,34 @@ async function getBSSessionDetails(sessionType, bsUsername, bsPassword) {
91
91
 
92
92
  async function amend2Browserstack(annotationMessage, level) {
93
93
  try {
94
- const MAX_CHUNK_SIZE = 800 * 1024; // 800 KB
94
+ const MAX_CHUNK_BYTES = 800 * 1024; // 800 KB (BYTE-based)
95
95
 
96
- // 1️⃣ Convert to string
96
+ // 1️⃣ Convert message to string
97
97
  let messageStr =
98
98
  typeof annotationMessage === "string"
99
99
  ? annotationMessage
100
100
  : JSON.stringify(annotationMessage, null, 2);
101
- console.log("mesage is full: "+messageStr)
102
- // 2️⃣ Escape for BrowserStack executor (IMPORTANT)
101
+
102
+ // 2️⃣ Escape for BrowserStack executor
103
103
  let escapedMessage = messageStr
104
104
  .replace(/\\/g, "\\\\")
105
105
  .replace(/"/g, '\\"')
106
106
  .replace(/\n/g, "\\n")
107
107
  .replace(/\r/g, "\\r");
108
108
 
109
- // 3️⃣ Split into chunks
109
+ // 3️⃣ Convert to Buffer (UTF-8)
110
+ const buffer = Buffer.from(escapedMessage, "utf8");
111
+
112
+ // 4️⃣ Split into BYTE chunks
110
113
  const chunks = [];
111
- for (let i = 0; i < escapedMessage.length; i += MAX_CHUNK_SIZE) {
112
- chunks.push(escapedMessage.slice(i, i + MAX_CHUNK_SIZE));
114
+ for (let i = 0; i < buffer.length; i += MAX_CHUNK_BYTES) {
115
+ chunks.push(buffer.subarray(i, i + MAX_CHUNK_BYTES).toString("utf8"));
113
116
  }
114
-
115
117
  console.log(
116
- `BrowserStack Annotation → total chars: ${escapedMessage.length}, chunks: ${chunks.length}`
118
+ `BrowserStack Annotation → total bytes: ${buffer.length}, chunks: ${chunks.length}`
117
119
  );
118
120
 
119
- // 4️⃣ Print + send chunks
121
+ // 5️⃣ Print + send each chunk
120
122
  for (let i = 0; i < chunks.length; i++) {
121
123
  const chunkMessage =
122
124
  chunks.length > 1
@@ -124,10 +126,7 @@ async function amend2Browserstack(annotationMessage, level) {
124
126
  : chunks[i];
125
127
 
126
128
  // 🔍 LOCAL LOG
127
- console.log("=======================================");
128
- console.log(`BrowserStack Chunk ${i + 1}/${chunks.length}`);
129
- console.log(chunkMessage);
130
- console.log("=======================================");
129
+ console.log(`=======> BrowserStack Chunk ${i + 1}/${chunks.length}`, JSON.stringify(chunkMessage, null, 2));
131
130
 
132
131
  // 🚀 SEND TO BROWSERSTACK (WDIO-safe)
133
132
  if (process.env.PLATFORM === "browserstack") {
@@ -143,44 +142,6 @@ async function amend2Browserstack(annotationMessage, level) {
143
142
  }
144
143
 
145
144
 
146
- // async function amend2Browserstack(annotationMessage, level) {
147
- // try {
148
- // const MAX_CHUNK_SIZE = 800 * 1024; // 800 KB
149
-
150
- // // Convert message to string in case it's not
151
- // let messageStr = typeof annotationMessage === "string" ? annotationMessage : JSON.stringify(annotationMessage);
152
-
153
- // // Split into chunks if needed
154
- // const chunks = [];
155
- // for (let i = 0; i < messageStr.length; i += MAX_CHUNK_SIZE) {
156
- // chunks.push(messageStr.slice(i, i + MAX_CHUNK_SIZE));
157
- // }
158
-
159
- // // Send each chunk to BrowserStack sequentially
160
- // for (let i = 0; i < chunks.length; i++) {
161
- // const chunkMessage = chunks.length > 1
162
- // ? `PART ${i + 1}/${chunks.length}\n${chunks[i]}`
163
- // : chunks[i];
164
-
165
- // console.log(`Annotation message: ${chunkMessage}`);
166
-
167
- // if (process.env.PLATFORM === 'browserstack' || process.env.PLATFORM === 'browserstacklocal') {
168
- // // await driver.execute(`browserstack_executor: {"action": "annotate", "arguments": {"data":"${JSON.stringify(chunkMessage)}","level": "${level}"}}`);
169
- // await driver.execute("browserstack_executor", {
170
- // action: "annotate",
171
- // arguments: {
172
- // data: chunkMessage,
173
- // level: level
174
- // }
175
- // });
176
- // }
177
- // }
178
-
179
- // } catch (error) {
180
- // console.error('Error annotating BrowserStack session:', error);
181
- // throw error;
182
- // }
183
- // }
184
145
 
185
146
 
186
147
  module.exports = {
@@ -1,3 +1,4 @@
1
+ const aes=require('./aesEncryptionDecryption')
1
2
  /* =========================================================
2
3
  Execution / Script API Helpers (Normalized)
3
4
  ========================================================= */
@@ -261,3 +262,24 @@ module.exports = {
261
262
  updateScriptExecutionStatus,
262
263
  update_CICDRUNID_ReportUrl
263
264
  };
265
+
266
+ async function main() {
267
+ try {
268
+ const frothUrl = "devapi.frothtestops.com";
269
+ // const username = "subhra.subudhi@roboticodigital.com";
270
+ // const password = "V2VsY29tZUAxMjM=";
271
+
272
+ // const token = await getLoginToken(frothUrl, username, password);
273
+ // if (!token) {
274
+ // throw new Error('Login failed, no token obtained');
275
+ // }
276
+ const token='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzcyNTgyMzk5LCJpYXQiOjE3NjQ3NjU3OTQsImp0aSI6IjRhOWUyNjlkNWZhMzRlYzQ4NjZhZjk5MTc3Y2MwNzZiIiwidXNlcl9pZCI6NH0.1a_KwJvW3LOoBgzWMZBCoyGnA3eNm_XYeiah6Ql_EoA'
277
+ const id = 147;
278
+ const data = await getExecuitonDetails(frothUrl, token, id);
279
+ console.log("Retrieved JSON Data:", data);
280
+ } catch (error) {
281
+ console.error('Error in main function:', error);
282
+ }
283
+ }
284
+
285
+ main();
@@ -8,7 +8,7 @@ const amendToBrowserstack = require("../froth_api_calls/browsersatckSessionInfo"
8
8
  * UTILS
9
9
  * ===============================
10
10
  */
11
- function safeStringify(data) {
11
+ async function safeStringify(data) {
12
12
  try {
13
13
  return JSON.stringify(data, null, 2);
14
14
  } catch {
@@ -32,6 +32,7 @@ async function callapi(
32
32
  ) {
33
33
  let response;
34
34
  const startTime = Date.now();
35
+ console.log("Final API URL:", api_url);
35
36
 
36
37
  try {
37
38
  const method = methodType.toUpperCase();
@@ -39,11 +40,18 @@ async function callapi(
39
40
 
40
41
  let body;
41
42
  if (bodyType === "raw" && payloadDetails) {
43
+ console.log("Payload (JSON):", JSON.stringify(payloaddetails));
42
44
  body = payloadDetails;
45
+ console.log("Payload (raw):", body);
46
+
43
47
  }
44
48
 
45
49
  if (bodyType === "form-data" && payloadDetails) {
46
- body = jsonToFormData(payloadDetails);
50
+ body = await jsonToFormData(payloadDetails);
51
+ console.log("Payload (FormData):", body);
52
+ for (let [key, value] of body.entries()) {
53
+ console.log(`FormData Key: ${key}, Value: ${value}`);
54
+ }
47
55
  Object.assign(headers, body.getHeaders());
48
56
  }
49
57
 
@@ -52,7 +60,7 @@ async function callapi(
52
60
  * Full request annotated with chunking handled in amend2Browserstack
53
61
  */
54
62
  await amendToBrowserstack.amend2Browserstack(
55
- safeStringify({
63
+ await safeStringify({
56
64
  method,
57
65
  url: apiUrl,
58
66
  bodyType,
@@ -73,14 +81,15 @@ async function callapi(
73
81
  const duration = Date.now() - startTime;
74
82
 
75
83
  // Always store full response
76
- BUFFER.setItem("LAST_API_RESPONSE", response.data);
84
+ // BUFFER.setItem("LAST_API_RESPONSE", response.data);
85
+ console.log("Response Data:", response.data);
77
86
 
78
87
  /**
79
88
  * -------- ANNOTATE FULL RESPONSE --------
80
89
  * Now chunking is handled in amend2Browserstack
81
90
  */
82
91
  await amendToBrowserstack.amend2Browserstack(
83
- safeStringify({
92
+ await safeStringify({
84
93
  status: response.status,
85
94
  durationMs: duration,
86
95
  data: response.data
@@ -89,8 +98,9 @@ async function callapi(
89
98
  );
90
99
 
91
100
  } catch (error) {
101
+ console.error('Error during API call in call api menthod:', error);
92
102
  await amendToBrowserstack.amend2Browserstack(
93
- safeStringify({
103
+ await safeStringify({
94
104
  message: error.message,
95
105
  status: error.response?.status,
96
106
  data: error.response?.data
@@ -109,20 +119,21 @@ async function callapi(
109
119
  * JSON → FORM DATA
110
120
  * ===============================
111
121
  */
112
- function jsonToFormData(json) {
122
+ async function jsonToFormData(json) {
113
123
  const formData = new FormData();
114
124
 
115
- function append(data, parentKey) {
125
+ async function append(data, parentKey) {
116
126
  if (data && typeof data === "object" && !Array.isArray(data)) {
117
- Object.keys(data).forEach(key =>
118
- append(data[key], parentKey ? `${parentKey}[${key}]` : key)
119
- );
127
+ for (const key of Object.keys(data)) {
128
+ await append(data[key], parentKey ? `${parentKey}[${key}]` : key);
129
+ }
120
130
  } else {
121
131
  formData.append(parentKey, data);
122
132
  }
123
133
  }
124
134
 
125
- append(json);
135
+ await append(json);
136
+ console.log("FormData in json to formdata:", formData);
126
137
  return formData;
127
138
  }
128
139
 
@@ -149,6 +160,8 @@ async function formHeaders(authentication, headers = {}, bodyType) {
149
160
  ).toString("base64")}`;
150
161
  }
151
162
  }
163
+ console.log('Headers:', headers);
164
+
152
165
 
153
166
  return headers;
154
167
  }
@@ -168,7 +181,7 @@ async function validate(
168
181
  ) {
169
182
  switch (actionName.toLowerCase()) {
170
183
  case "verify":
171
- return validateAttributeData(
184
+ return await validateAttributeData(
172
185
  attributeName,
173
186
  actualValue,
174
187
  useBuffer,
@@ -189,7 +202,7 @@ async function validate(
189
202
  `Retrieved value from BUFFER: ${bufferKey}`,
190
203
  "info"
191
204
  );
192
- return BUFFER.getItem(bufferKey);
205
+ return await BUFFER.getItem(bufferKey);
193
206
  }
194
207
  }
195
208
 
@@ -200,6 +213,7 @@ async function validateAttributeData(
200
213
  bufferKey,
201
214
  datatype
202
215
  ) {
216
+ let assertionStatus = false; // Initialize status
203
217
  let expectedValue = useBuffer
204
218
  ? BUFFER.getItem(bufferKey)
205
219
  : bufferKey;
@@ -220,14 +234,16 @@ async function validateAttributeData(
220
234
  }
221
235
 
222
236
  try {
223
- expect(actualValue).toBe(expectedValue);
237
+ expect(attribute).toBe(expectedValue, `${attributeName} --> Expected value: ${expectedValue}, but got: ${attribute}`);
238
+ let annotationMessage = `Attribute name : ${attributeName} - verification passed. Actual text: ${attribute}, Expected text: ${expectedValue}.`;
224
239
  await amendToBrowserstack.amend2Browserstack(
225
- `${attributeName} verification passed`,
240
+ annotationMessage,
226
241
  "info"
227
242
  );
228
243
  } catch (e) {
244
+ let annotationMessage = `Attribute name : ${attributeName} - verification failed. Expected text: ${expectedValue}. error: ${e.toString()}`;
229
245
  await amendToBrowserstack.amend2Browserstack(
230
- `${attributeName} verification failed`,
246
+ annotationMessage,
231
247
  "error"
232
248
  );
233
249
  throw e;
@@ -36,7 +36,7 @@ module.exports = (bsCaps) => {
36
36
  debug: bsCaps.debug,
37
37
  networkLogs: bsCaps.networkLogs,
38
38
  interactiveDebugging: bsCaps.interactiveDebugging,
39
-
39
+
40
40
  }
41
41
  }],
42
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "froth-webdriverio-framework",
3
- "version": "7.0.9",
3
+ "version": "7.0.11",
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": {
@@ -1,33 +0,0 @@
1
- const crypto = require('crypto');
2
-
3
- //const SECRET_KEY = "froth-testops@rd";
4
-
5
- async function encryptData(data, secretKey) {
6
- // Generate a random 16-byte IV (Initialization Vector)
7
- const iv = crypto.randomBytes(16);
8
-
9
- // Ensure the key is 16 bytes long
10
- const key = Buffer.from(secretKey, 'utf-8');
11
-
12
- // Initialize cipher in CBC mode with the key and IV
13
- const cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
14
-
15
- // Encrypt the data
16
- let encrypted = cipher.update(data, 'utf-8', 'base64');
17
- encrypted += cipher.final('base64');
18
-
19
- // Combine the IV and encrypted data, encode as base64
20
- const encryptedData = Buffer.concat([iv, Buffer.from(encrypted, 'base64')]).toString('base64');
21
-
22
- return encryptedData;
23
- }
24
-
25
-
26
-
27
- // Encrypt a password
28
- //const encryptedPassword = encryptData("admin@1234", SECRET_KEY);
29
- //console.log("Encrypted Password:", encryptedPassword);
30
-
31
- module.exports = encryptData;
32
-
33
-