@dev-blinq/cucumber_client 1.0.1312-dev → 1.0.1314-dev

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.
@@ -674,6 +674,22 @@ const _generateCodeFromCommand = (step, elements, userData) => {
674
674
  return { codeLines, elements: elementsChanged ? elements : null, elementIdentifier, allStrategyLocators };
675
675
  };
676
676
 
677
+ /**
678
+ * Generates a report command based on the given position.
679
+ * @param {"start"|"end"} position
680
+ */
681
+ const generateReportCommand = (position, cmdId) => {
682
+ const codeLines = [];
683
+ if (position === "start") {
684
+ const line = `await context.web.addCommandToReport("${cmdId}", "PASSED", '{"status":"start","cmdId":"${cmdId}"}', {type:"cmdReport"},this);`;
685
+ codeLines.push(line);
686
+ } else if (position === "end") {
687
+ const line = `await context.web.addCommandToReport("${cmdId}", "PASSED", '{"status":"end","cmdId":"${cmdId}"}', {type:"cmdReport"},this);`;
688
+ codeLines.push(line);
689
+ }
690
+ return codeLines;
691
+ };
692
+
677
693
  const generateCode = (recording, codePage, userData, projectDir, methodName) => {
678
694
  const stepsDefinitions = new StepsDefinitions(projectDir);
679
695
  stepsDefinitions.load(false);
@@ -714,12 +730,15 @@ const generateCode = (recording, codePage, userData, projectDir, methodName) =>
714
730
  if (recordingStep.type === Types.COMPLETE) {
715
731
  return;
716
732
  }
717
- // if (!recordingStep.element) {
718
- // logger.info(`Step ${recordingStep.type} doesn't have an element, ignoring`);
719
- // return;
720
- // }
733
+
734
+ if (process.env.TEMP_RUN === "true") {
735
+ codeLines.push(...generateReportCommand("start", recordingStep.cmdId));
736
+ }
721
737
  const result = _generateCodeFromCommand(recordingStep, elements, userData);
722
738
  codeLines.push(...result.codeLines);
739
+ if (process.env.TEMP_RUN === "true") {
740
+ codeLines.push(...generateReportCommand("end", recordingStep.cmdId));
741
+ }
723
742
  if (result.elements) {
724
743
  elements = result.elements;
725
744
  }
@@ -1,6 +1,6 @@
1
1
  // define the jsdoc type for the input
2
2
  import { closeContext, initContext, _getDataFile, resetTestData } from "automation_model";
3
- import { existsSync, readdirSync, readFileSync, rmSync } from "fs";
3
+ import { existsSync, mkdir, mkdirSync, readdirSync, readFileSync, rmSync } from "fs";
4
4
  import path from "path";
5
5
  import url from "url";
6
6
  import { getImplementedSteps, getStepsAndCommandsForScenario } from "./implemented_steps.js";
@@ -15,6 +15,7 @@ import chokidar from "chokidar";
15
15
  import logger from "../../logger.js";
16
16
  import { unEscapeNonPrintables } from "../cucumber/utils.js";
17
17
  import { findAvailablePort } from "../utils/index.js";
18
+ import NetworkMonitor from "./network.js";
18
19
 
19
20
  const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
20
21
 
@@ -185,12 +186,33 @@ export class BVTRecorder {
185
186
  });
186
187
  this.stepRunner = new BVTStepRunner({
187
188
  projectDir: this.projectDir,
189
+ sendExecutionStatus: (data) => {
190
+ if (data && data.type) {
191
+ switch (data.type) {
192
+ case "cmdExecutionStart":
193
+ console.log("Sending cmdExecutionStart event for cmdId:", data.cmdId);
194
+ this.sendEvent(this.events.cmdExecutionStart, data.cmdId);
195
+ break;
196
+ case "cmdExecutionSuccess":
197
+ console.log("Sending cmdExecutionSuccess event for cmdId:", data.cmdId);
198
+ this.sendEvent(this.events.cmdExecutionSuccess, data.cmdId);
199
+ break;
200
+ case "cmdExecutionFailure":
201
+ console.log("Sending cmdExecutionFailure event for cmdId:", data.cmdId);
202
+ this.sendEvent(this.events.cmdExecutionFailure, data.cmdId);
203
+ break;
204
+ default:
205
+ console.warn("Unknown command execution status type:", data.type);
206
+ break;
207
+ }
208
+ }
209
+ },
188
210
  });
189
211
  this.pageSet = new Set();
190
-
212
+ this.networkMonitor = new NetworkMonitor();
191
213
  this.lastKnownUrlPath = "";
192
214
  // TODO: what is world?
193
- this.world = { attach: () => { } };
215
+ this.world = { attach: () => {} };
194
216
  this.shouldTakeScreenshot = true;
195
217
  this.watcher = null;
196
218
  }
@@ -203,6 +225,9 @@ export class BVTRecorder {
203
225
  onStepDetails: "BVTRecorder.onStepDetails",
204
226
  getTestData: "BVTRecorder.getTestData",
205
227
  onGoto: "BVTRecorder.onGoto",
228
+ cmdExecutionStart: "BVTRecorder.cmdExecutionStart",
229
+ cmdExecutionSuccess: "BVTRecorder.cmdExecutionSuccess",
230
+ cmdExecutionFailure: "BVTRecorder.cmdExecutionFailure",
206
231
  };
207
232
  bindings = {
208
233
  __bvt_recordCommand: async ({ frame, page, context }, event) => {
@@ -240,6 +265,7 @@ export class BVTRecorder {
240
265
  const locator = await this.web.page.locator(selector);
241
266
  const snapshot = await locator.ariaSnapshot();
242
267
  return snapshot;
268
+ // Triggering workflow
243
269
  };
244
270
 
245
271
  processObject = async ({ type, action, value }) => {
@@ -294,7 +320,7 @@ export class BVTRecorder {
294
320
  process.env.CDP_LISTEN_PORT = this.#remoteDebuggerPort;
295
321
 
296
322
  this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
297
- this.world = { attach: () => { } };
323
+ this.world = { attach: () => {} };
298
324
 
299
325
  const ai_config_file = path.join(this.projectDir, "ai_config.json");
300
326
  let ai_config = {};
@@ -700,7 +726,7 @@ export class BVTRecorder {
700
726
  }
701
727
  async closeBrowser() {
702
728
  delete process.env.TEMP_RUN;
703
- await this.watcher.close().then(() => { });
729
+ await this.watcher.close().then(() => {});
704
730
  this.watcher = null;
705
731
  this.previousIndex = null;
706
732
  this.previousHistoryLength = null;
@@ -789,30 +815,34 @@ export class BVTRecorder {
789
815
  }, 100);
790
816
  this.timerId = timerId;
791
817
  }
792
- async runStep({ step, parametersMap, tags, isFirstStep }, options) {
818
+ async runStep({ step, parametersMap, tags, isFirstStep, listenNetwork }, options) {
793
819
  const _env = {
794
820
  TOKEN: this.TOKEN,
795
821
  TEMP_RUN: true,
796
822
  REPORT_FOLDER: this.bvtContext.reportFolder,
797
823
  BLINQ_ENV: this.envName,
824
+ STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
825
+ CURRENT_STEP_ID: step.id,
798
826
  };
799
827
 
800
828
  this.bvtContext.navigate = true;
801
829
  for (const [key, value] of Object.entries(_env)) {
802
830
  process.env[key] = value;
803
831
  }
832
+
804
833
  if (this.timerId) {
805
834
  clearTimeout(this.timerId);
806
835
  this.timerId = null;
807
836
  }
808
837
  await this.setMode("running");
838
+
809
839
  try {
810
840
  const { result, info } = await this.stepRunner.runStep(
811
841
  {
812
842
  step,
813
843
  parametersMap,
814
844
  envPath: this.envName,
815
- tags
845
+ tags,
816
846
  },
817
847
  this.bvtContext,
818
848
  options ? { ...options, skipBefore: !isFirstStep } : { skipBefore: !isFirstStep }
@@ -51,6 +51,37 @@ class PromisifiedSocketServer {
51
51
  }
52
52
  }
53
53
 
54
+ function memorySizeOf(obj) {
55
+ var bytes = 0;
56
+
57
+ function sizeOf(obj) {
58
+ if (obj !== null && obj !== undefined) {
59
+ switch (typeof obj) {
60
+ case "number":
61
+ bytes += 8;
62
+ break;
63
+ case "string":
64
+ bytes += obj.length * 2;
65
+ break;
66
+ case "boolean":
67
+ bytes += 4;
68
+ break;
69
+ case "object":
70
+ var objClass = Object.prototype.toString.call(obj).slice(8, -1);
71
+ if (objClass === "Object" || objClass === "Array") {
72
+ for (var key in obj) {
73
+ if (!obj.hasOwnProperty(key)) continue;
74
+ sizeOf(obj[key]);
75
+ }
76
+ } else bytes += obj.toString().length * 2;
77
+ break;
78
+ }
79
+ }
80
+ return bytes;
81
+ }
82
+ return sizeOf(obj);
83
+ }
84
+
54
85
  const init = ({ envName, projectDir, roomId, TOKEN }) => {
55
86
  console.log("connecting to " + WS_URL);
56
87
  const socket = io(WS_URL);
@@ -66,8 +97,10 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
66
97
  projectDir,
67
98
  TOKEN,
68
99
  sendEvent: (event, data) => {
100
+ console.log("Size of data", memorySizeOf(data), "bytes");
69
101
  console.log("----", event, data, "roomId", roomId);
70
102
  socket.emit(event, data, roomId);
103
+ console.log("Successfully sent event", event, "to room", roomId);
71
104
  },
72
105
  });
73
106
  recorder
@@ -77,7 +110,7 @@ const init = ({ envName, projectDir, roomId, TOKEN }) => {
77
110
  socket.emit("BVTRecorder.browserOpened", null, roomId);
78
111
  })
79
112
  .catch((e) => {
80
- socket.emit("BVTRecorder.browserLaunchFailed", null, roomId);
113
+ socket.emit("BVTRecorder.browserLaunchFailed", e, roomId);
81
114
  });
82
115
  const timeOutForFunction = async (promise, timeout = 5000) => {
83
116
  const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(), timeout));
@@ -239,6 +272,9 @@ 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
+ },
242
278
  });
243
279
  socket.on("targetBrowser.command.event", async (input) => {
244
280
  return recorder.onAction(input);
@@ -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;
@@ -33,8 +33,9 @@ async function withAbort(fn, signal) {
33
33
  export class BVTStepRunner {
34
34
  #currentStepController;
35
35
  #port;
36
- constructor({ projectDir }) {
36
+ constructor({ projectDir, sendExecutionStatus }) {
37
37
  this.projectDir = projectDir;
38
+ this.sendExecutionStatus = sendExecutionStatus;
38
39
  }
39
40
  setRemoteDebugPort(port) {
40
41
  this.#port = port;
@@ -74,6 +75,119 @@ export class BVTStepRunner {
74
75
  writeFileSync(tFilePath, tFileContent);
75
76
  return tFilePath;
76
77
  }
78
+
79
+ executeStepRemote = async ({ feature_file_path, scenario, tempFolderPath, stepText }, options) => {
80
+ if (!options) {
81
+ options = {
82
+ skipAfter: true,
83
+ };
84
+ }
85
+ const environment = {
86
+ ...process.env,
87
+ };
88
+
89
+ try {
90
+ const { loadConfiguration, loadSupport, runCucumber } = await import("@dev-blinq/cucumber-js/api");
91
+ const { runConfiguration } = await loadConfiguration(
92
+ {
93
+ provided: {
94
+ name: [scenario],
95
+ paths: [feature_file_path],
96
+ import: [path.join(tempFolderPath, "step_definitions", "**", "*.mjs")],
97
+ // format: ["bvt"],
98
+ },
99
+ },
100
+ { cwd: process.cwd(), env: environment }
101
+ );
102
+ // const files = glob.sync(path.join(tempFolderPath, "step_definitions", "**", "*.mjs"));
103
+ // console.log("Files found:", files);
104
+ const support = await loadSupport(runConfiguration, { cwd: process.cwd(), env: environment });
105
+ // console.log("found ", support.stepDefinitions.length, "step definitions");
106
+ // support.stepDefinitions.map((step) => {
107
+ // console.log("step", step.pattern);
108
+ // });
109
+
110
+ if (options.skipAfter) {
111
+ // ignore afterAll/after hooks
112
+ support.afterTestCaseHookDefinitions = [];
113
+ support.afterTestRunHookDefinitions = [];
114
+ }
115
+
116
+ let errorMesssage = null;
117
+ let info = null;
118
+ let errInfo = null;
119
+ const result = await runCucumber({ ...runConfiguration, support }, environment, (message) => {
120
+ if (message.testStepFinished) {
121
+ const { testStepFinished } = message;
122
+ const { testStepResult } = testStepFinished;
123
+ if (testStepResult.status === "FAILED" || testStepResult.status === "AMBIGUOUS") {
124
+ if (!errorMesssage) {
125
+ errorMesssage = testStepResult.message;
126
+ if (info) {
127
+ errInfo = info;
128
+ }
129
+ }
130
+ }
131
+ if (testStepResult.status === "UNDEFINED") {
132
+ if (!errorMesssage) {
133
+ errorMesssage = `step ${JSON.stringify(stepText)} is ${testStepResult.status}`;
134
+ if (info) {
135
+ errInfo = info;
136
+ }
137
+ }
138
+ }
139
+ }
140
+ if (message.attachment) {
141
+ const attachment = message.attachment;
142
+ if (attachment.mediaType === "application/json" && attachment.body) {
143
+ const body = JSON.parse(attachment.body);
144
+ info = body.info;
145
+
146
+ if (body && body.payload) {
147
+ const payload = body.payload;
148
+ const content = payload.content;
149
+ const type = payload.type;
150
+ if (type === "cmdReport") {
151
+ if (content) {
152
+ const report = JSON.parse(content);
153
+ switch (report.status) {
154
+ case "start":
155
+ this.sendExecutionStatus({
156
+ type: "cmdExecutionStart",
157
+ cmdId: report.cmdId,
158
+ });
159
+ break;
160
+ case "end":
161
+ this.sendExecutionStatus({
162
+ type: "cmdExecutionSuccess",
163
+ cmdId: report.cmdId,
164
+ });
165
+ break;
166
+ default:
167
+ console.warn("Unknown command report status:", report.status);
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ });
175
+ if (errorMesssage) {
176
+ const bvtError = new Error(errorMesssage);
177
+ Object.assign(bvtError, { info: errInfo });
178
+ throw bvtError;
179
+ }
180
+
181
+ return {
182
+ result,
183
+ info,
184
+ };
185
+ } catch (error) {
186
+ console.error("Error running cucumber-js", error);
187
+ throw error;
188
+ }
189
+ };
190
+
77
191
  async runStep({ step, parametersMap, envPath, tags }, bvtContext, options) {
78
192
  let codePage; // = getCodePage();
79
193
  // const tempFolderPath = process.env.tempFeaturesFolderPath;
@@ -121,7 +235,7 @@ export class BVTStepRunner {
121
235
  const stepExecController = new AbortController();
122
236
  this.#currentStepController = stepExecController;
123
237
  const { result, info } = await withAbort(async () => {
124
- return await stepsDefinitions.executeStepRemote(
238
+ return await this.executeStepRemote(
125
239
  {
126
240
  feature_file_path,
127
241
  tempFolderPath,