@dev-blinq/cucumber_client 1.0.1265-dev → 1.0.1265-stage

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.
Files changed (38) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +159 -14068
  2. package/bin/assets/preload/recorderv3.js +3 -1
  3. package/bin/assets/scripts/dom_parent.js +26 -0
  4. package/bin/assets/scripts/recorder.js +8 -4
  5. package/bin/assets/scripts/unique_locators.js +847 -547
  6. package/bin/assets/templates/_hooks_template.txt +37 -0
  7. package/bin/assets/templates/page_template.txt +2 -16
  8. package/bin/assets/templates/utils_template.txt +44 -71
  9. package/bin/client/apiTest/apiTest.js +6 -0
  10. package/bin/client/cli_helpers.js +11 -13
  11. package/bin/client/code_cleanup/utils.js +5 -1
  12. package/bin/client/code_gen/code_inversion.js +61 -4
  13. package/bin/client/code_gen/page_reflection.js +838 -899
  14. package/bin/client/code_gen/playwright_codeget.js +52 -13
  15. package/bin/client/cucumber/feature.js +89 -27
  16. package/bin/client/cucumber/project_to_document.js +1 -1
  17. package/bin/client/cucumber/steps_definitions.js +84 -76
  18. package/bin/client/cucumber_selector.js +17 -1
  19. package/bin/client/local_agent.js +5 -4
  20. package/bin/client/project.js +186 -196
  21. package/bin/client/recorderv3/bvt_recorder.js +290 -80
  22. package/bin/client/recorderv3/implemented_steps.js +74 -16
  23. package/bin/client/recorderv3/index.js +47 -25
  24. package/bin/client/recorderv3/network.js +299 -0
  25. package/bin/client/recorderv3/services.js +4 -16
  26. package/bin/client/recorderv3/step_runner.js +331 -67
  27. package/bin/client/recorderv3/step_utils.js +153 -5
  28. package/bin/client/recorderv3/update_feature.js +32 -30
  29. package/bin/client/recording.js +3 -0
  30. package/bin/client/run_cucumber.js +5 -1
  31. package/bin/client/scenario_report.js +0 -5
  32. package/bin/client/test_scenario.js +0 -1
  33. package/bin/client/utils/socket_logger.js +132 -0
  34. package/bin/index.js +1 -0
  35. package/bin/logger.js +3 -2
  36. package/bin/min/consoleApi.min.cjs +2 -3
  37. package/bin/min/injectedScript.min.cjs +16 -16
  38. package/package.json +24 -14
@@ -1,9 +1,9 @@
1
1
  import { AstBuilder, GherkinClassicTokenMatcher, Parser } from "@cucumber/gherkin";
2
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
2
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from "fs";
3
3
  import path from "path";
4
4
  import url from "url";
5
5
  import { findFilesWithExtension, StepsDefinitions } from "../cucumber/steps_definitions.js";
6
- import { Feature } from "../cucumber/feature.js";
6
+ import { Feature, Step } from "../cucumber/feature.js";
7
7
  import { CodePage } from "../code_gen/page_reflection.js";
8
8
  import { getCommandsForImplementedStep, loadStepDefinitions } from "./step_utils.js";
9
9
  import { parseStepTextParameters } from "../cucumber/utils.js";
@@ -13,7 +13,6 @@ const uuidFn = () => (++id).toString(16);
13
13
  const builder = new AstBuilder(uuidFn);
14
14
  const matcher = new GherkinClassicTokenMatcher();
15
15
  const parser = new Parser(builder, matcher);
16
-
17
16
  let i = 0;
18
17
  const getImplId = () => {
19
18
  return `I-${i++}`;
@@ -57,6 +56,53 @@ function memorySizeOf(obj) {
57
56
  return sizeOf(obj);
58
57
  }
59
58
 
59
+ export function parseRouteFiles(projectDir, step) {
60
+ const routeFolder = path.join(projectDir, "data", "routes");
61
+ const templateRouteMap = new Map();
62
+
63
+ if (!existsSync(routeFolder)) {
64
+ step.routeItems = null;
65
+ return;
66
+ }
67
+
68
+ // Go over all the files in the route folder and parse them
69
+ const routeFiles = readdirSync(routeFolder).filter((file) => file.endsWith(".json"));
70
+ for (const file of routeFiles) {
71
+ const filePath = path.join(routeFolder, file);
72
+ const routeData = JSON.parse(readFileSync(filePath, "utf8"));
73
+ if (routeData && routeData.template) {
74
+ const template = routeData.template;
75
+ const routes = routeData.routes;
76
+
77
+ templateRouteMap.set(template, routes);
78
+ }
79
+ }
80
+
81
+ if (!existsSync(routeFolder)) {
82
+ return null;
83
+ } else if (step && step.text) {
84
+ // Convert the step text to cucumber template
85
+ const cucumberStep = new Step();
86
+ cucumberStep.text = step.text;
87
+ const template = cucumberStep.getTemplate();
88
+ if (templateRouteMap.has(template)) {
89
+ const routeItems = templateRouteMap.get(template);
90
+ routeItems.forEach((item) => {
91
+ const filters = item.filters || {};
92
+ const queryParams = filters?.queryParams || {};
93
+ const queryParamsArray = Object.keys(queryParams).map((key) => ({
94
+ key: key,
95
+ value: queryParams[key],
96
+ }));
97
+ filters.queryParams = queryParamsArray || [];
98
+ });
99
+ step.routeItems = routeItems;
100
+ } else {
101
+ step.routeItems = null;
102
+ }
103
+ }
104
+ }
105
+
60
106
  export const getImplementedSteps = async (projectDir) => {
61
107
  const foundErrors = [];
62
108
  try {
@@ -70,6 +116,12 @@ export const getImplementedSteps = async (projectDir) => {
70
116
  const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
71
117
  //console.log({ utilsContent });
72
118
  writeFileSync(utilsFilePath, utilsContent, "utf8");
119
+ const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
120
+ if (existsSync(hooksTemplateFilePath)) {
121
+ const hooksFilePath = path.join(stepDefinitionFolderPath, "_hooks.mjs");
122
+ const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
123
+ writeFileSync(hooksFilePath, hooksContent, "utf8");
124
+ }
73
125
  } catch (error) {
74
126
  foundErrors.push({ error });
75
127
  }
@@ -168,7 +220,10 @@ export const getImplementedSteps = async (projectDir) => {
168
220
  }
169
221
  stepLineSet.add(stepLine);
170
222
  step.templateIndex = implementedSteps.length;
171
- implementedSteps.push({
223
+
224
+ parseRouteFiles(projectDir, step);
225
+
226
+ const implementedStep = {
172
227
  keyword: step.keyword.trim(),
173
228
  keywordAlias: step.keywordAlias?.trim(),
174
229
  text: updateStepText(template.pattern, step.parameters),
@@ -179,7 +234,10 @@ export const getImplementedSteps = async (projectDir) => {
179
234
  templateIndex: step.templateIndex,
180
235
  pattern: template.pattern,
181
236
  paths: template.paths,
182
- });
237
+ routeItems: step.routeItems,
238
+ };
239
+
240
+ implementedSteps.push(implementedStep);
183
241
  }
184
242
  }
185
243
 
@@ -236,17 +294,17 @@ export const getImplementedSteps = async (projectDir) => {
236
294
  for (const tag of scenario.tags) {
237
295
  delete tag.location;
238
296
  }
239
- // for (const scenario of scenarios) {
240
- // for (const step of scenario.steps) {
241
- // if (step.templateIndex === undefined) {
242
- // const cleanStepName = stepsDefinitions._stepNameToTemplate(step.text);
243
- // const index = implementedSteps.findIndex((istep) => {
244
- // return cleanStepName === istep.pattern;
245
- // });
246
- // step.templateIndex = index;
247
- // }
248
- // }
249
- // }
297
+ for (const scenario of scenarios) {
298
+ for (const step of scenario.steps) {
299
+ if (step.templateIndex === undefined) {
300
+ const cleanStepName = stepsDefinitions._stepNameToTemplate(step.text);
301
+ const index = implementedSteps.findIndex((istep) => {
302
+ return cleanStepName === istep.pattern;
303
+ });
304
+ step.templateIndex = index;
305
+ }
306
+ }
307
+ }
250
308
  }
251
309
  if (foundErrors.length > 0) {
252
310
  console.log("foundErrors", foundErrors);
@@ -4,6 +4,7 @@ import { BVTRecorder } from "./bvt_recorder.js";
4
4
  import { compareWithScenario } from "../code_gen/duplication_analysis.js";
5
5
  import { getAppDataDir } from "./app_dir.js";
6
6
  import { readdir } from "fs/promises";
7
+ import socketLogger from "../utils/socket_logger.js";
7
8
 
8
9
  let port = process.env.EDITOR_PORT || 3003;
9
10
  const WS_URL = "http://localhost:" + port;
@@ -16,7 +17,9 @@ class PromisifiedSocketServer {
16
17
  init() {
17
18
  this.socket.on("request", async (data) => {
18
19
  const { event, input, id, roomId, socketId } = data;
19
- // console.log("request", { event, input, id, roomId, socketId });
20
+ if (event !== "recorderWindow.getCurrentChromiumPath") {
21
+ socketLogger.info("Received request", { event, input, id, roomId, socketId });
22
+ }
20
23
  try {
21
24
  const handler = this.routes[event];
22
25
  if (!handler) {
@@ -24,17 +27,12 @@ class PromisifiedSocketServer {
24
27
  return;
25
28
  }
26
29
  const response = await handler(input);
27
- // console.log("response", { id, value: response, roomId, socketId });
30
+ if (event !== "recorderWindow.getCurrentChromiumPath") {
31
+ socketLogger.info(`Sending response`, { event, id, value: response, roomId, socketId });
32
+ }
28
33
  this.socket.emit("response", { id, value: response, roomId, socketId });
29
34
  } catch (error) {
30
- console.log("request", JSON.stringify({ event, input, id, roomId, socketId }));
31
- console.error("response", { id, error, roomId, socketId });
32
- // console.error({
33
- // message: error?.message,
34
- // code: error?.code,
35
- // info: error?.info,
36
- // stack: error?.stack,
37
- // })
35
+ socketLogger.error("Error handling request", { event, input, id, roomId, socketId, error });
38
36
  this.socket.emit("response", {
39
37
  id,
40
38
  error: {
@@ -52,13 +50,16 @@ class PromisifiedSocketServer {
52
50
  }
53
51
 
54
52
  const init = ({ envName, projectDir, roomId, TOKEN }) => {
55
- console.log("connecting to " + WS_URL);
53
+ console.log("Connecting to " + WS_URL);
56
54
  const socket = io(WS_URL);
55
+ socketLogger.init(socket, { context: "BVTRecorder", eventName: "BVTRecorder.log" });
57
56
  socket.on("connect", () => {
58
- // console.log('connected to server')
57
+ socketLogger.info("Connected to BVTRecorder server");
58
+ console.log("Connected to BVTRecorder server");
59
59
  });
60
60
  socket.on("disconnect", () => {
61
- // console.log('disconnected from server')
61
+ socketLogger.info("Disconnected from server");
62
+ console.log("Disconnected from server");
62
63
  });
63
64
  socket.emit("joinRoom", { id: roomId, window: "cucumber_client/bvt_recorder" });
64
65
  const recorder = new BVTRecorder({
@@ -66,18 +67,20 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
66
67
  projectDir,
67
68
  TOKEN,
68
69
  sendEvent: (event, data) => {
69
- console.log("----", event, data, "roomId", roomId);
70
+ socketLogger.info("Sending event", { event, data, roomId });
70
71
  socket.emit(event, data, roomId);
71
72
  },
73
+ logger: socketLogger,
72
74
  });
73
75
  recorder
74
76
  .openBrowser()
75
77
  .then(() => {
76
- // console.log("BVTRecorder.browserOpened");
78
+ socketLogger.info("BVTRecorder.browserOpened");
77
79
  socket.emit("BVTRecorder.browserOpened", null, roomId);
78
80
  })
79
81
  .catch((e) => {
80
- socket.emit("BVTRecorder.browserLaunchFailed", null, roomId);
82
+ socketLogger.error("BVTRecorder.browserLaunchFailed", e);
83
+ socket.emit("BVTRecorder.browserLaunchFailed", e, roomId);
81
84
  });
82
85
  const timeOutForFunction = async (promise, timeout = 5000) => {
83
86
  const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(), timeout));
@@ -87,6 +90,7 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
87
90
  return res;
88
91
  } catch (error) {
89
92
  console.error(error);
93
+ socketLogger.error(error);
90
94
  throw error;
91
95
  }
92
96
  };
@@ -96,10 +100,13 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
96
100
  return recorder
97
101
  .openBrowser(input)
98
102
  .then(() => {
103
+ socketLogger.info("BVTRecorder.browserOpened");
104
+ console.info("BVTRecorder.browserOpened");
99
105
  socket.emit("BVTRecorder.browserOpened", { roomId, window: "cucumber_client/bvt_recorder" });
100
106
  })
101
107
  .catch((e) => {
102
- console.error(e);
108
+ socketLogger.error("Error opening browser", e);
109
+ console.error("BVTRecorder.browserLaunchFailed", e);
103
110
  socket.emit("BVTRecorder.browserLaunchFailed", { roomId, window: "cucumber_client/bvt_recorder" });
104
111
  });
105
112
  },
@@ -110,10 +117,13 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
110
117
  return recorder
111
118
  .reOpenBrowser(input)
112
119
  .then(() => {
113
- // console.log("BVTRecorder.browserOpened");
120
+ socketLogger.info("BVTRecorder.browserOpened");
121
+ console.log("BVTRecorder.browserOpened");
114
122
  socket.emit("BVTRecorder.browserOpened", null, roomId);
115
123
  })
116
- .catch(() => {
124
+ .catch((e) => {
125
+ socketLogger.info("BVTRecorder.browserLaunchFailed");
126
+ console.error("BVTRecorder.browserLaunchFailed", e);
117
127
  socket.emit("BVTRecorder.browserLaunchFailed", null, roomId);
118
128
  });
119
129
  },
@@ -139,9 +149,6 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
139
149
  "recorderWindow.runStep": async (input) => {
140
150
  return recorder.runStep(input);
141
151
  },
142
- "recorderWindow.runScenario": async (input) => {
143
- return recorder.runScenario(input);
144
- },
145
152
  "recorderWindow.saveScenario": async (input) => {
146
153
  return recorder.saveScenario(input);
147
154
  },
@@ -197,6 +204,12 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
197
204
  "recorderWindow.abortExecution": async (input) => {
198
205
  return recorder.abortExecution(input);
199
206
  },
207
+ "recorderWindow.pauseExecution": async (input) => {
208
+ return recorder.pauseExecution(input);
209
+ },
210
+ "recorderWindow.resumeExecution": async (input) => {
211
+ return recorder.resumeExecution(input);
212
+ },
200
213
  "recorderWindow.loadExistingScenario": async (input) => {
201
214
  return recorder.loadExistingScenario(input);
202
215
  },
@@ -209,9 +222,7 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
209
222
  "recorderWindow.getSnapshotFiles": async (input) => {
210
223
  const snapshotFolder = recorder.getSnapshotFolder();
211
224
  if (snapshotFolder) {
212
- // Get the list of filenames in the snapshot folder
213
225
  const files = await readdir(snapshotFolder);
214
- // Filter the files to only include .png files
215
226
  const ymlFiles = files.filter((file) => file.endsWith(".yml") || file.endsWith(".yaml"));
216
227
  return { folder: snapshotFolder, files: ymlFiles };
217
228
  } else return { folder: null, files: [] };
@@ -242,6 +253,18 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
242
253
  "recorderWindow.getStepsAndCommandsForScenario": async (input) => {
243
254
  return await recorder.getStepsAndCommandsForScenario(input);
244
255
  },
256
+ "recorderWindow.getNetworkEvents": async (input) => {
257
+ return await recorder.getNetworkEvents(input);
258
+ },
259
+ "recorderWindow.initExecution": async (input) => {
260
+ return await recorder.initExecution(input);
261
+ },
262
+ "recorderWindow.cleanupExecution": async (input) => {
263
+ return await recorder.cleanupExecution(input);
264
+ },
265
+ "recorderWindow.resetExecution": async (input) => {
266
+ return await recorder.resetExecution(input);
267
+ },
245
268
  });
246
269
  socket.on("targetBrowser.command.event", async (input) => {
247
270
  return recorder.onAction(input);
@@ -268,7 +291,6 @@ try {
268
291
  showUsage(error, usage);
269
292
  }
270
293
  try {
271
- // console.log({ envName, projectDir, featureName, scenarioName, stepIndex, roomId })
272
294
  init({
273
295
  envName,
274
296
  projectDir,
@@ -0,0 +1,299 @@
1
+ /**
2
+ * @typedef {Object} NetworkEvent
3
+ * @property {import('playwright').Request} request
4
+ * @property {import('playwright').Response|null} response
5
+ * @property {string} id
6
+ * @property {number} timestamp
7
+ * @property {string} status - 'completed', 'failed'
8
+ */
9
+
10
+ class NetworkMonitor {
11
+ constructor() {
12
+ this.networkId = 0;
13
+ /** @type {Map<string, NetworkEvent>} */
14
+ this.requestIdMap = new Map();
15
+ this.networkEvents = new Map();
16
+ /** @type {Map<import('playwright').Page, {responseListener: Function, requestFailedListener: Function}>} */
17
+ this.pageListeners = new Map();
18
+ }
19
+
20
+ /**
21
+ * Add network event listeners to a page
22
+ * @param {import('playwright').Page} page
23
+ */
24
+ addNetworkEventListener(page) {
25
+ // Create the listener functions
26
+ const responseListener = async (response) => {
27
+ const request = response.request();
28
+ let eventId = this.requestIdMap.get(request);
29
+
30
+ if (!eventId) {
31
+ this.networkId++;
32
+ eventId = this.networkId.toString();
33
+ this.requestIdMap.set(request, eventId);
34
+ }
35
+
36
+ const networkEvent = {
37
+ id: eventId,
38
+ request,
39
+ response,
40
+ timestamp: Date.now(),
41
+ status: "completed",
42
+ };
43
+
44
+ this.networkEvents.set(eventId, networkEvent);
45
+ };
46
+
47
+ const requestFailedListener = (request) => {
48
+ let eventId = this.requestIdMap.get(request);
49
+
50
+ if (!eventId) {
51
+ this.networkId++;
52
+ eventId = this.networkId.toString();
53
+ this.requestIdMap.set(request, eventId);
54
+ }
55
+
56
+ const networkEvent = {
57
+ id: eventId,
58
+ request,
59
+ response: null,
60
+ timestamp: Date.now(),
61
+ status: "failed",
62
+ };
63
+
64
+ this.networkEvents.set(eventId, networkEvent);
65
+ };
66
+ // Store the listeners for later removal
67
+ this.pageListeners.set(page, {
68
+ responseListener,
69
+ requestFailedListener,
70
+ });
71
+
72
+ // Add the listeners to the page
73
+ page.on("response", responseListener);
74
+ page.on("requestfailed", requestFailedListener);
75
+ }
76
+
77
+ /**
78
+ * Remove network event listeners from a specific page
79
+ * @param {import('playwright').Page} page
80
+ */
81
+ removeNetworkEventListener(page) {
82
+ const listeners = this.pageListeners.get(page);
83
+ if (listeners) {
84
+ page.off("response", listeners.responseListener);
85
+ page.off("requestfailed", listeners.requestFailedListener);
86
+ this.pageListeners.delete(page);
87
+ console.log("Network event listeners removed from page");
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Remove network event listeners from all pages
93
+ */
94
+ removeAllNetworkEventListeners() {
95
+ for (const [page, listeners] of this.pageListeners) {
96
+ page.off("response", listeners.responseListener);
97
+ page.off("requestfailed", listeners.requestFailedListener);
98
+ }
99
+ this.pageListeners.clear();
100
+ console.log("All network event listeners removed");
101
+ }
102
+
103
+ /**
104
+ * Check if a page has active listeners
105
+ * @param {import('playwright').Page} page
106
+ * @returns {boolean}
107
+ */
108
+ hasListeners(page) {
109
+ return this.pageListeners.has(page);
110
+ }
111
+
112
+ /**
113
+ * Get the number of pages with active listeners
114
+ * @returns {number}
115
+ */
116
+ getActiveListenersCount() {
117
+ return this.pageListeners.size;
118
+ }
119
+
120
+ /**
121
+ * Get all network events until now
122
+ */
123
+ getAllNetworkEvents() {
124
+ return Array.from(this.networkEvents.values());
125
+ }
126
+
127
+ /**
128
+ * Get network events within a range
129
+ * @param {number} startId
130
+ * @param {number} endId
131
+ * @returns {NetworkEvent[]}
132
+ */
133
+ getNetworkEventsInRange(startId, endId) {
134
+ const events = [];
135
+ for (let i = startId; i <= endId; i++) {
136
+ const event = this.networkEvents.get(i.toString());
137
+ if (event) {
138
+ events.push(event);
139
+ }
140
+ }
141
+ return events;
142
+ }
143
+
144
+ /**
145
+ * Get network events since a specific ID
146
+ * @param {number} sinceId
147
+ * @returns {NetworkEvent[]}
148
+ */
149
+ getNetworkEventsSince(sinceId) {
150
+ return this.getNetworkEventsInRange(sinceId + 1, this.networkId);
151
+ }
152
+
153
+ /**
154
+ * Get events by status
155
+ * @param {string} status - 'completed', 'failed'
156
+ * @returns {NetworkEvent[]}
157
+ */
158
+ getEventsByStatus(status) {
159
+ return Array.from(this.networkEvents.values()).filter((event) => event.status === status);
160
+ }
161
+
162
+ /**
163
+ * Get current network ID (latest)
164
+ * @returns {number}
165
+ */
166
+ getCurrentNetworkId() {
167
+ return this.networkId;
168
+ }
169
+
170
+ getCurrentNetworkEventsLength() {
171
+ return this.networkEvents.size;
172
+ }
173
+
174
+ /**
175
+ * Get statistics about stored events
176
+ * @returns {Object}
177
+ */
178
+ getStats() {
179
+ const events = Array.from(this.networkEvents.values());
180
+ return {
181
+ total: events.length,
182
+ completed: events.filter((e) => e.status === "completed").length,
183
+ failed: events.filter((e) => e.status === "failed").length,
184
+ oldestTimestamp: events.length > 0 ? Math.min(...events.map((e) => e.timestamp)) : null,
185
+ newestTimestamp: events.length > 0 ? Math.max(...events.map((e) => e.timestamp)) : null,
186
+ };
187
+ }
188
+
189
+ /**
190
+ * Marshall network event for serialization
191
+ * @param {NetworkEvent} networkEvent
192
+ * @returns {Promise<Object>}
193
+ */
194
+ async marshallNetworkEvent(networkEvent) {
195
+ const { request, response } = networkEvent;
196
+
197
+ try {
198
+ const url = new URL(request.url());
199
+ const marshalledEvent = {
200
+ id: networkEvent.id,
201
+ timestamp: networkEvent.timestamp,
202
+ status: networkEvent.status,
203
+ url: url.href,
204
+ method: request.method(),
205
+ statusCode: response?.status() ?? null,
206
+ statusText: response?.statusText() ?? null,
207
+ queryParams: Object.fromEntries(url.searchParams.entries()),
208
+ };
209
+
210
+ // Try to get response body safely (only for successful responses)
211
+ if (response && networkEvent.status === "completed") {
212
+ try {
213
+ const isBinary =
214
+ !response.headers()["content-type"]?.includes("application/json") &&
215
+ !response.headers()["content-type"]?.includes("text");
216
+ let body;
217
+ if (isBinary) {
218
+ body = await response.body();
219
+ } else {
220
+ body = await response.text();
221
+ }
222
+ let json;
223
+ try {
224
+ if (typeof body === "string") {
225
+ json = JSON.parse(body); // Check if body is valid JSON
226
+ }
227
+ } catch (_) {
228
+ //Ignore
229
+ }
230
+ const responseBody = isBinary ? body : json ? JSON.stringify(json) : body;
231
+ marshalledEvent.contentType = isBinary ? "binary" : json ? "json" : "text";
232
+ marshalledEvent.responseBody = responseBody;
233
+ } catch (error) {
234
+ marshalledEvent.responseBody = `[Error reading response: ${error.message}]`;
235
+ }
236
+ } else if (networkEvent.status === "failed") {
237
+ marshalledEvent.failureReason = request.failure()?.errorText || "Unknown error";
238
+ }
239
+
240
+ console.log("Marshalled network event:", marshalledEvent);
241
+
242
+ return marshalledEvent;
243
+ } catch (error) {
244
+ console.error("Error marshalling network event:", error);
245
+ return {
246
+ id: networkEvent.id,
247
+ timestamp: networkEvent.timestamp,
248
+ status: networkEvent.status,
249
+ url: request.url(),
250
+ method: request.method(),
251
+ error: error.message,
252
+ };
253
+ }
254
+ }
255
+
256
+ /**
257
+ *@returns {Promise<Object[]>}
258
+ * Get all marshalled network events
259
+ * This is useful for sending to the server or saving to a file.
260
+ * */
261
+ async getAllMarshalledNetworkEvents() {
262
+ const events = this.getAllNetworkEvents();
263
+ const marshalledEvents = await Promise.all(events.map((event) => this.marshallNetworkEvent(event)));
264
+ return marshalledEvents;
265
+ }
266
+
267
+ /**
268
+ * Get marshalled network events since this ID
269
+ * @returns {Promise<Object[]>}
270
+ * @param {number} sinceId
271
+ */
272
+ async getMarshalledNetworkEvents(sinceId) {
273
+ const events = this.getNetworkEventsSince(sinceId);
274
+ const marshalledEvents = await Promise.all(events.map((event) => this.marshallNetworkEvent(event)));
275
+ return marshalledEvents;
276
+ }
277
+
278
+ /**
279
+ * Get marshalled network events in a range
280
+ * @param {number} startId
281
+ * @param {number} endId
282
+ * @returns {Promise<Object[]>}
283
+ */
284
+ async getMarshalledNetworkEventsInRange(startId, endId) {
285
+ const events = this.getNetworkEventsInRange(startId, endId);
286
+ const marshalledEvents = await Promise.all(events.map((event) => this.marshallNetworkEvent(event)));
287
+ return marshalledEvents;
288
+ }
289
+
290
+ /**
291
+ * Clear all network events
292
+ */
293
+ clearNetworkEvents() {
294
+ this.networkEvents.clear();
295
+ this.networkId = 0;
296
+ }
297
+ }
298
+
299
+ export default NetworkMonitor;
@@ -15,20 +15,7 @@ export class NamesService {
15
15
  if (!screenshot && commands.length > 1) {
16
16
  screenshot = this.screenshotMap.get(commands[commands.length - 2].inputID);
17
17
  }
18
- this.logger.info(
19
- "data: " +
20
- JSON.stringify(
21
- {
22
- commands,
23
- stepsNames,
24
- parameters,
25
- map,
26
- },
27
- null,
28
- 2
29
- )
30
- );
31
- // get screenshot for the last command
18
+
32
19
  const url = `${getRunsServiceBaseURL()}/generate-step-information/generate`;
33
20
  const TIMEOUT = 120; // 2 minutes
34
21
  const { data } = await axiosClient({
@@ -38,7 +25,7 @@ export class NamesService {
38
25
  commands,
39
26
  stepsNames,
40
27
  parameters,
41
- screenshot,
28
+ //screenshot,
42
29
  map,
43
30
  },
44
31
  headers: {
@@ -65,6 +52,7 @@ export class NamesService {
65
52
  }
66
53
  } catch (error) {
67
54
  if (i === TIMEOUT - 1) {
55
+ this.logger.error("Timeout while generating step details: ", error);
68
56
  console.error("Timeout while generating step details: ", error);
69
57
  }
70
58
  }
@@ -96,7 +84,6 @@ export class NamesService {
96
84
  scenario: scenarioAsText,
97
85
  };
98
86
 
99
- this.logger.info("data: " + JSON.stringify(genObject, null, 2));
100
87
  // get screenshot for the last command
101
88
  const url = `${getRunsServiceBaseURL()}/generate-step-information/generate_scenario_feature`;
102
89
  const TIMEOUT = 120; // 2 minutes
@@ -140,6 +127,7 @@ export class NamesService {
140
127
  if (result.status !== 200) {
141
128
  return { success: false, message: "Error while generating step details" };
142
129
  }
130
+
143
131
  return result.data;
144
132
  }
145
133