@dev-blinq/cucumber_client 1.0.1309-dev → 1.0.1309-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.
- package/bin/assets/bundled_scripts/recorder.js +106 -106
- package/bin/assets/preload/css_gen.js +10 -10
- package/bin/assets/preload/recorderv3.js +3 -1
- package/bin/assets/preload/toolbar.js +27 -29
- package/bin/assets/preload/unique_locators.js +1 -1
- package/bin/assets/preload/yaml.js +288 -275
- package/bin/assets/scripts/aria_snapshot.js +223 -220
- package/bin/assets/scripts/dom_attr.js +329 -329
- package/bin/assets/scripts/dom_parent.js +169 -174
- package/bin/assets/scripts/event_utils.js +94 -94
- package/bin/assets/scripts/pw.js +2050 -1949
- package/bin/assets/scripts/recorder.js +5 -17
- package/bin/assets/scripts/snapshot_capturer.js +153 -146
- package/bin/assets/scripts/unique_locators.js +925 -793
- package/bin/assets/scripts/yaml.js +796 -783
- package/bin/assets/templates/_hooks_template.txt +41 -0
- package/bin/assets/templates/utils_template.txt +1 -46
- package/bin/client/apiTest/apiTest.js +6 -0
- package/bin/client/cli_helpers.js +11 -13
- package/bin/client/code_cleanup/utils.js +5 -1
- package/bin/client/code_gen/api_codegen.js +2 -2
- package/bin/client/code_gen/code_inversion.js +53 -4
- package/bin/client/code_gen/page_reflection.js +839 -906
- package/bin/client/code_gen/playwright_codeget.js +48 -14
- package/bin/client/cucumber/feature.js +89 -27
- package/bin/client/cucumber/feature_data.js +2 -2
- package/bin/client/cucumber/project_to_document.js +9 -3
- package/bin/client/cucumber/steps_definitions.js +90 -87
- package/bin/client/cucumber_selector.js +17 -1
- package/bin/client/local_agent.js +6 -5
- package/bin/client/parse_feature_file.js +23 -26
- package/bin/client/playground/projects/env.json +2 -2
- package/bin/client/project.js +186 -196
- package/bin/client/recorderv3/bvt_recorder.js +167 -54
- package/bin/client/recorderv3/implemented_steps.js +74 -16
- package/bin/client/recorderv3/index.js +69 -22
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/scriptTest.js +1 -1
- package/bin/client/recorderv3/services.js +4 -16
- package/bin/client/recorderv3/step_runner.js +329 -72
- package/bin/client/recorderv3/step_utils.js +574 -5
- package/bin/client/recorderv3/update_feature.js +32 -30
- package/bin/client/run_cucumber.js +5 -1
- package/bin/client/scenario_report.js +0 -5
- package/bin/client/test_scenario.js +0 -1
- package/bin/client/upload-service.js +2 -2
- package/bin/client/utils/socket_logger.js +132 -0
- package/bin/index.js +1 -0
- package/bin/logger.js +3 -2
- package/bin/min/consoleApi.min.cjs +2 -3
- package/bin/min/injectedScript.min.cjs +16 -16
- package/package.json +20 -11
|
@@ -4,10 +4,23 @@ 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;
|
|
10
11
|
|
|
12
|
+
const responseSize = (response) => {
|
|
13
|
+
try {
|
|
14
|
+
if (typeof response !== "string") {
|
|
15
|
+
return new Blob([JSON.stringify(response)]).size;
|
|
16
|
+
} else {
|
|
17
|
+
return new Blob([response]).size;
|
|
18
|
+
}
|
|
19
|
+
} catch {
|
|
20
|
+
return -1;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
11
24
|
class PromisifiedSocketServer {
|
|
12
25
|
constructor(socket, routes) {
|
|
13
26
|
this.socket = socket;
|
|
@@ -16,7 +29,9 @@ class PromisifiedSocketServer {
|
|
|
16
29
|
init() {
|
|
17
30
|
this.socket.on("request", async (data) => {
|
|
18
31
|
const { event, input, id, roomId, socketId } = data;
|
|
19
|
-
|
|
32
|
+
if (event !== "recorderWindow.getCurrentChromiumPath") {
|
|
33
|
+
socketLogger.info("Received request", { event, input, id, roomId, socketId });
|
|
34
|
+
}
|
|
20
35
|
try {
|
|
21
36
|
const handler = this.routes[event];
|
|
22
37
|
if (!handler) {
|
|
@@ -24,17 +39,19 @@ class PromisifiedSocketServer {
|
|
|
24
39
|
return;
|
|
25
40
|
}
|
|
26
41
|
const response = await handler(input);
|
|
27
|
-
|
|
42
|
+
if (event !== "recorderWindow.getCurrentChromiumPath") {
|
|
43
|
+
socketLogger.info(`Sending response for ${event}, ${responseSize(response)} bytes`);
|
|
44
|
+
}
|
|
28
45
|
this.socket.emit("response", { id, value: response, roomId, socketId });
|
|
29
46
|
} catch (error) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
socketLogger.error("Error handling request", {
|
|
48
|
+
event,
|
|
49
|
+
input,
|
|
50
|
+
id,
|
|
51
|
+
roomId,
|
|
52
|
+
socketId,
|
|
53
|
+
error: error instanceof Error ? `${error.message}\n${error.stack}` : error,
|
|
54
|
+
});
|
|
38
55
|
this.socket.emit("response", {
|
|
39
56
|
id,
|
|
40
57
|
error: {
|
|
@@ -52,13 +69,16 @@ class PromisifiedSocketServer {
|
|
|
52
69
|
}
|
|
53
70
|
|
|
54
71
|
const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
55
|
-
console.log("
|
|
72
|
+
console.log("Connecting to " + WS_URL);
|
|
56
73
|
const socket = io(WS_URL);
|
|
74
|
+
socketLogger.init(socket, { context: "BVTRecorder", eventName: "BVTRecorder.log" });
|
|
57
75
|
socket.on("connect", () => {
|
|
58
|
-
|
|
76
|
+
socketLogger.info("Connected to BVTRecorder server");
|
|
77
|
+
console.log("Connected to BVTRecorder server");
|
|
59
78
|
});
|
|
60
79
|
socket.on("disconnect", () => {
|
|
61
|
-
|
|
80
|
+
socketLogger.info("Disconnected from server");
|
|
81
|
+
console.log("Disconnected from server");
|
|
62
82
|
});
|
|
63
83
|
socket.emit("joinRoom", { id: roomId, window: "cucumber_client/bvt_recorder" });
|
|
64
84
|
const recorder = new BVTRecorder({
|
|
@@ -66,18 +86,20 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
66
86
|
projectDir,
|
|
67
87
|
TOKEN,
|
|
68
88
|
sendEvent: (event, data) => {
|
|
69
|
-
|
|
89
|
+
socketLogger.info("Sending event", { event, data, roomId });
|
|
70
90
|
socket.emit(event, data, roomId);
|
|
71
91
|
},
|
|
92
|
+
logger: socketLogger,
|
|
72
93
|
});
|
|
73
94
|
recorder
|
|
74
95
|
.openBrowser()
|
|
75
96
|
.then(() => {
|
|
76
|
-
|
|
97
|
+
socketLogger.info("BVTRecorder.browserOpened");
|
|
77
98
|
socket.emit("BVTRecorder.browserOpened", null, roomId);
|
|
78
99
|
})
|
|
79
100
|
.catch((e) => {
|
|
80
|
-
|
|
101
|
+
socketLogger.error("BVTRecorder.browserLaunchFailed", e);
|
|
102
|
+
socket.emit("BVTRecorder.browserLaunchFailed", e, roomId);
|
|
81
103
|
});
|
|
82
104
|
const timeOutForFunction = async (promise, timeout = 5000) => {
|
|
83
105
|
const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(), timeout));
|
|
@@ -87,6 +109,7 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
87
109
|
return res;
|
|
88
110
|
} catch (error) {
|
|
89
111
|
console.error(error);
|
|
112
|
+
socketLogger.error(error);
|
|
90
113
|
throw error;
|
|
91
114
|
}
|
|
92
115
|
};
|
|
@@ -96,10 +119,13 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
96
119
|
return recorder
|
|
97
120
|
.openBrowser(input)
|
|
98
121
|
.then(() => {
|
|
122
|
+
socketLogger.info("BVTRecorder.browserOpened");
|
|
123
|
+
console.info("BVTRecorder.browserOpened");
|
|
99
124
|
socket.emit("BVTRecorder.browserOpened", { roomId, window: "cucumber_client/bvt_recorder" });
|
|
100
125
|
})
|
|
101
126
|
.catch((e) => {
|
|
102
|
-
|
|
127
|
+
socketLogger.error("Error opening browser", e);
|
|
128
|
+
console.error("BVTRecorder.browserLaunchFailed", e);
|
|
103
129
|
socket.emit("BVTRecorder.browserLaunchFailed", { roomId, window: "cucumber_client/bvt_recorder" });
|
|
104
130
|
});
|
|
105
131
|
},
|
|
@@ -110,10 +136,13 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
110
136
|
return recorder
|
|
111
137
|
.reOpenBrowser(input)
|
|
112
138
|
.then(() => {
|
|
113
|
-
|
|
139
|
+
socketLogger.info("BVTRecorder.browserOpened");
|
|
140
|
+
console.log("BVTRecorder.browserOpened");
|
|
114
141
|
socket.emit("BVTRecorder.browserOpened", null, roomId);
|
|
115
142
|
})
|
|
116
|
-
.catch(() => {
|
|
143
|
+
.catch((e) => {
|
|
144
|
+
socketLogger.info("BVTRecorder.browserLaunchFailed");
|
|
145
|
+
console.error("BVTRecorder.browserLaunchFailed", e);
|
|
117
146
|
socket.emit("BVTRecorder.browserLaunchFailed", null, roomId);
|
|
118
147
|
});
|
|
119
148
|
},
|
|
@@ -194,6 +223,12 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
194
223
|
"recorderWindow.abortExecution": async (input) => {
|
|
195
224
|
return recorder.abortExecution(input);
|
|
196
225
|
},
|
|
226
|
+
"recorderWindow.pauseExecution": async (input) => {
|
|
227
|
+
return recorder.pauseExecution(input);
|
|
228
|
+
},
|
|
229
|
+
"recorderWindow.resumeExecution": async (input) => {
|
|
230
|
+
return recorder.resumeExecution(input);
|
|
231
|
+
},
|
|
197
232
|
"recorderWindow.loadExistingScenario": async (input) => {
|
|
198
233
|
return recorder.loadExistingScenario(input);
|
|
199
234
|
},
|
|
@@ -206,9 +241,7 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
206
241
|
"recorderWindow.getSnapshotFiles": async (input) => {
|
|
207
242
|
const snapshotFolder = recorder.getSnapshotFolder();
|
|
208
243
|
if (snapshotFolder) {
|
|
209
|
-
// Get the list of filenames in the snapshot folder
|
|
210
244
|
const files = await readdir(snapshotFolder);
|
|
211
|
-
// Filter the files to only include .png files
|
|
212
245
|
const ymlFiles = files.filter((file) => file.endsWith(".yml") || file.endsWith(".yaml"));
|
|
213
246
|
return { folder: snapshotFolder, files: ymlFiles };
|
|
214
247
|
} else return { folder: null, files: [] };
|
|
@@ -239,6 +272,21 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
|
|
|
239
272
|
"recorderWindow.getStepsAndCommandsForScenario": async (input) => {
|
|
240
273
|
return await recorder.getStepsAndCommandsForScenario(input);
|
|
241
274
|
},
|
|
275
|
+
"recorderWindow.getNetworkEvents": async (input) => {
|
|
276
|
+
return await recorder.getNetworkEvents(input);
|
|
277
|
+
},
|
|
278
|
+
"recorderWindow.initExecution": async (input) => {
|
|
279
|
+
return await recorder.initExecution(input);
|
|
280
|
+
},
|
|
281
|
+
"recorderWindow.cleanupExecution": async (input) => {
|
|
282
|
+
return await recorder.cleanupExecution(input);
|
|
283
|
+
},
|
|
284
|
+
"recorderWindow.resetExecution": async (input) => {
|
|
285
|
+
return await recorder.resetExecution(input);
|
|
286
|
+
},
|
|
287
|
+
"recorderWindow.stopRecordingNetwork": async (input) => {
|
|
288
|
+
return recorder.stopRecordingNetwork(input);
|
|
289
|
+
},
|
|
242
290
|
});
|
|
243
291
|
socket.on("targetBrowser.command.event", async (input) => {
|
|
244
292
|
return recorder.onAction(input);
|
|
@@ -265,7 +313,6 @@ try {
|
|
|
265
313
|
showUsage(error, usage);
|
|
266
314
|
}
|
|
267
315
|
try {
|
|
268
|
-
// console.log({ envName, projectDir, featureName, scenarioName, stepIndex, roomId })
|
|
269
316
|
init({
|
|
270
317
|
envName,
|
|
271
318
|
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
|
-
|
|
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
|
|