@dev-blinq/cucumber_client 1.0.1389-dev → 1.0.1389-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 (50) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +107 -107
  2. package/bin/assets/preload/css_gen.js +10 -10
  3. package/bin/assets/preload/toolbar.js +27 -29
  4. package/bin/assets/preload/unique_locators.js +1 -1
  5. package/bin/assets/preload/yaml.js +288 -275
  6. package/bin/assets/scripts/aria_snapshot.js +223 -220
  7. package/bin/assets/scripts/dom_attr.js +329 -329
  8. package/bin/assets/scripts/dom_parent.js +169 -174
  9. package/bin/assets/scripts/event_utils.js +94 -94
  10. package/bin/assets/scripts/pw.js +2050 -1949
  11. package/bin/assets/scripts/recorder.js +13 -23
  12. package/bin/assets/scripts/snapshot_capturer.js +147 -147
  13. package/bin/assets/scripts/unique_locators.js +163 -44
  14. package/bin/assets/scripts/yaml.js +796 -783
  15. package/bin/assets/templates/_hooks_template.txt +6 -2
  16. package/bin/assets/templates/utils_template.txt +2 -2
  17. package/bin/client/code_cleanup/find_step_definition_references.js +0 -2
  18. package/bin/client/code_cleanup/utils.js +5 -1
  19. package/bin/client/code_gen/api_codegen.js +2 -2
  20. package/bin/client/code_gen/code_inversion.js +63 -2
  21. package/bin/client/code_gen/function_signature.js +4 -0
  22. package/bin/client/code_gen/page_reflection.js +846 -906
  23. package/bin/client/code_gen/playwright_codeget.js +27 -3
  24. package/bin/client/cucumber/feature.js +4 -0
  25. package/bin/client/cucumber/feature_data.js +2 -2
  26. package/bin/client/cucumber/project_to_document.js +8 -2
  27. package/bin/client/cucumber/steps_definitions.js +6 -3
  28. package/bin/client/cucumber_selector.js +17 -1
  29. package/bin/client/local_agent.js +3 -2
  30. package/bin/client/parse_feature_file.js +23 -26
  31. package/bin/client/playground/projects/env.json +2 -2
  32. package/bin/client/project.js +186 -202
  33. package/bin/client/recorderv3/bvt_init.js +349 -0
  34. package/bin/client/recorderv3/bvt_recorder.js +1068 -104
  35. package/bin/client/recorderv3/implemented_steps.js +2 -0
  36. package/bin/client/recorderv3/index.js +4 -303
  37. package/bin/client/recorderv3/scriptTest.js +1 -1
  38. package/bin/client/recorderv3/services.js +814 -154
  39. package/bin/client/recorderv3/step_runner.js +315 -206
  40. package/bin/client/recorderv3/step_utils.js +473 -25
  41. package/bin/client/recorderv3/update_feature.js +9 -5
  42. package/bin/client/recorderv3/wbr_entry.js +61 -0
  43. package/bin/client/recording.js +1 -0
  44. package/bin/client/upload-service.js +3 -2
  45. package/bin/client/utils/socket_logger.js +132 -0
  46. package/bin/index.js +4 -1
  47. package/bin/logger.js +3 -2
  48. package/bin/min/consoleApi.min.cjs +2 -3
  49. package/bin/min/injectedScript.min.cjs +16 -16
  50. package/package.json +21 -10
@@ -14,46 +14,69 @@ import { escapeString, getExamplesContent } from "./update_feature.js";
14
14
  import fs from "fs";
15
15
  import { locateDefinitionPath } from "../cucumber/steps_definitions.js";
16
16
  import { tmpdir } from "os";
17
+ import socketLogger from "../utils/socket_logger.js";
17
18
 
18
- // let copiedCodeToTemp = false;
19
- async function withAbort(fn, signal) {
20
- if (!signal) {
21
- return await fn();
22
- }
23
- return new Promise((resolve, reject) => {
24
- const abortHandler = () => reject(new Error("Aborted"));
25
- signal.addEventListener("abort", abortHandler, { once: true });
26
-
27
- fn()
28
- .then(resolve)
29
- .catch(reject)
30
- .finally(() => {
31
- signal.removeEventListener("abort", abortHandler);
32
- });
33
- });
34
- }
35
19
  export class BVTStepRunner {
36
- #currentStepController;
20
+ #currentStepController = null;
37
21
  #port;
38
- constructor({ projectDir, sendExecutionStatus }) {
22
+ #lastAttemptedCmdId = null;
23
+
24
+ constructor({ projectDir, sendExecutionStatus, bvtContext }) {
39
25
  this.projectDir = projectDir;
40
26
  this.sendExecutionStatus = sendExecutionStatus;
27
+ this.bvtContext = bvtContext;
28
+ this.liveExecutionMap = new Map();
41
29
  }
30
+
42
31
  setRemoteDebugPort(port) {
43
32
  this.#port = port;
44
33
  }
34
+
35
+ // Abort the current cucumber step execution by signaling the wrapper
45
36
  async abortExecution() {
37
+ if (this.bvtContext.web.pausedCmd) {
38
+ this.bvtContext.web.pausedCmd = null;
39
+ }
40
+ this.liveExecutionMap.clear();
46
41
  if (this.#currentStepController) {
47
42
  this.#currentStepController.abort();
48
43
  }
49
44
  }
50
45
 
46
+ async pauseExecution(cmdId) {
47
+ if (this.bvtContext.web) {
48
+ this.bvtContext.web.pausedCmd = {
49
+ id: cmdId,
50
+ ...this.liveExecutionMap.get(cmdId),
51
+ };
52
+ }
53
+ }
54
+
55
+ async resumeExecution(cmdId) {
56
+ if (this.bvtContext.web.pausedCmd) {
57
+ const { resolve } = this.bvtContext.web.pausedCmd;
58
+ if (resolve) {
59
+ resolve();
60
+ }
61
+ this.bvtContext.web.pausedCmd = null;
62
+ } else {
63
+ socketLogger.warn(`bvtContext.web.pausedCmd is null`);
64
+ if (this.liveExecutionMap.has(cmdId)) {
65
+ const { resolve } = this.liveExecutionMap.get(cmdId);
66
+ if (resolve) {
67
+ resolve();
68
+ }
69
+ } else {
70
+ console.warn(`No paused command found for cmdId: ${cmdId}`);
71
+ socketLogger.error(`No paused command found for cmdId: ${cmdId}`);
72
+ }
73
+ }
74
+ }
75
+
51
76
  async copyCodetoTempFolder({ step, parametersMap, tempFolderPath }) {
52
- // const tempFolderPath = path.join(this.projectDir, "__temp_features");
53
77
  if (!fs.existsSync(tempFolderPath)) {
54
78
  fs.mkdirSync(tempFolderPath);
55
79
  }
56
- //copy all files from "./features" "./temp" folder
57
80
  if (fs.existsSync(tempFolderPath)) {
58
81
  fs.rmSync(tempFolderPath, { recursive: true });
59
82
  }
@@ -61,12 +84,10 @@ export class BVTStepRunner {
61
84
  overwrite: true,
62
85
  recursive: true,
63
86
  });
64
- // copiedCodeToTemp = true;
65
87
  }
66
88
 
67
89
  async writeTempFeatureFile({ step, parametersMap, tempFolderPath, tags }) {
68
90
  const tFilePath = path.join(tempFolderPath, "__temp.feature");
69
- // console.log(tFilePath);
70
91
  let tFileContent = `# temp feature file
71
92
  Feature: Temp feature
72
93
  ${tags ? tags.join(" ") : ""}
@@ -78,211 +99,282 @@ export class BVTStepRunner {
78
99
  return tFilePath;
79
100
  }
80
101
 
81
- executeStepRemote = async ({ feature_file_path, scenario, tempFolderPath, stepText, config }, options) => {
102
+ // Generate wrapper code that integrates AbortSignal into cucumber step definitions
103
+ generateWrapperCode() {
104
+ return `
105
+ import {setDefinitionFunctionWrapper} from "@dev-blinq/cucumber-js";
106
+
107
+ setDefinitionFunctionWrapper((fn) => {
108
+ return async function (...args) {
109
+ const signal = global.__BVT_STEP_ABORT_SIGNAL;
110
+ if (signal) {
111
+ signal.throwIfAborted?.();
112
+ const abortHandler = () => {
113
+ throw new Error("Aborted");
114
+ };
115
+ signal.addEventListener("abort", abortHandler, { once: true });
116
+ try {
117
+ return await fn.apply(this, args);
118
+ } finally {
119
+ signal.removeEventListener("abort", abortHandler);
120
+ }
121
+ }
122
+ return await fn.apply(this, args);
123
+ };
124
+ });
125
+
126
+ `;
127
+ }
128
+
129
+ // Write the wrapper code to temp folder
130
+ async writeWrapperCode(tempFolderPath, abortSignal) {
131
+ // tempFolderPath/step_definitions/utils.mjs -> Make a file name that follows this file but always before the next file
132
+ let fileName = "utils" + Math.random().toString(36).substring(2, 7) + ".mjs";
133
+ while (existsSync(path.join(tempFolderPath, "step_definitions", fileName))) {
134
+ fileName = "utils" + Math.random().toString(36).substring(2, 7) + ".mjs";
135
+ }
136
+ const wrapperCode = this.generateWrapperCode();
137
+
138
+ // Ensure directory exists
139
+ const stepDefinitionFolderPath = path.join(tempFolderPath, "step_definitions");
140
+ if (!existsSync(stepDefinitionFolderPath)) {
141
+ mkdirSync(stepDefinitionFolderPath, { recursive: true });
142
+ }
143
+
144
+ writeFileSync(path.join(stepDefinitionFolderPath, fileName), wrapperCode);
145
+
146
+ // Set the abort signal globally so the wrapper can access it
147
+ global.__BVT_STEP_ABORT_SIGNAL = abortSignal;
148
+
149
+ return path.join(stepDefinitionFolderPath, fileName);
150
+ }
151
+
152
+ // Execute cucumber step - simplified without abort signal handling at this level
153
+ async executeStepWithAbort({ feature_file_path, scenario, tempFolderPath, stepText, config }, options) {
82
154
  const { skipAfter = true, skipBefore = true } = options || {};
83
- const environment = {
84
- ...process.env,
85
- };
86
155
 
87
- try {
88
- const { loadConfiguration, loadSupport, runCucumber } = await import("@dev-blinq/cucumber-js/api");
89
- const { runConfiguration } = await loadConfiguration(
90
- {
91
- provided: {
92
- name: [scenario],
93
- paths: [feature_file_path],
94
- import: [path.join(tempFolderPath, "step_definitions", "**", "*.mjs")],
95
- // format: ["bvt"],
96
- },
156
+ const environment = { ...process.env };
157
+ const { loadConfiguration, loadSupport, runCucumber } = await import("@dev-blinq/cucumber-js/api");
158
+
159
+ const { runConfiguration } = await loadConfiguration(
160
+ {
161
+ provided: {
162
+ name: [scenario],
163
+ paths: [feature_file_path],
164
+ import: [path.join(tempFolderPath, "step_definitions", "**", "*.mjs")],
97
165
  },
98
- { cwd: process.cwd(), env: environment }
99
- );
100
- // const files = glob.sync(path.join(tempFolderPath, "step_definitions", "**", "*.mjs"));
101
- // console.log("Files found:", files);
102
- const support = await loadSupport(runConfiguration, { cwd: process.cwd(), env: environment });
103
- // console.log("found ", support.stepDefinitions.length, "step definitions");
104
- // support.stepDefinitions.map((step) => {
105
- // console.log("step", step.pattern);
106
- // });
107
-
108
- support.afterTestRunHookDefinitions = [];
109
- if (skipAfter) {
110
- // ignore afterAll/after hooks
111
- support.afterTestCaseHookDefinitions = [];
112
- }
113
- if (skipBefore && !config.legacySyntax) {
114
- // ignore beforeAll/before hooks
115
- support.beforeTestCaseHookDefinitions = support.beforeTestCaseHookDefinitions.filter((hook) => {
116
- return hook.uri.endsWith("utils.mjs");
117
- });
118
- }
119
- support.beforeTestRunHookDefinitions = [];
120
-
121
- let errorMesssage = null;
122
- let info = null;
123
- let errInfo = null;
124
- const result = await runCucumber({ ...runConfiguration, support }, environment, (message) => {
125
- if (message.testStepFinished) {
126
- const { testStepFinished } = message;
127
- const { testStepResult } = testStepFinished;
128
- if (testStepResult.status === "FAILED" || testStepResult.status === "AMBIGUOUS") {
129
- if (!errorMesssage) {
130
- errorMesssage = testStepResult.message;
131
- if (info) {
132
- errInfo = info;
133
- }
166
+ },
167
+ { cwd: process.cwd(), env: environment }
168
+ );
169
+
170
+ const support = await loadSupport(runConfiguration, { cwd: process.cwd(), env: environment });
171
+
172
+ support.afterTestRunHookDefinitions = [];
173
+ if (skipAfter) {
174
+ support.afterTestCaseHookDefinitions = [];
175
+ }
176
+ if (skipBefore && !config.legacySyntax) {
177
+ support.beforeTestCaseHookDefinitions = support.beforeTestCaseHookDefinitions.filter((hook) => {
178
+ return hook.uri.endsWith("_hooks.mjs");
179
+ });
180
+ }
181
+ support.beforeTestRunHookDefinitions = [];
182
+
183
+ let errorMessage = null;
184
+ let info = null;
185
+ let errInfo = null;
186
+
187
+ const result = await runCucumber({ ...runConfiguration, support }, environment, (message) => {
188
+ if (message.testStepFinished) {
189
+ const { testStepFinished } = message;
190
+ const { testStepResult } = testStepFinished;
191
+ if (testStepResult.status === "FAILED" || testStepResult.status === "AMBIGUOUS") {
192
+ if (!errorMessage) {
193
+ errorMessage = testStepResult.message;
194
+ if (info) {
195
+ errInfo = info;
134
196
  }
135
197
  }
136
- if (testStepResult.status === "UNDEFINED") {
137
- if (!errorMesssage) {
138
- errorMesssage = `step ${JSON.stringify(stepText)} is ${testStepResult.status}`;
139
- if (info) {
140
- errInfo = info;
141
- }
198
+ }
199
+ if (testStepResult.status === "UNDEFINED") {
200
+ if (!errorMessage) {
201
+ errorMessage = `step ${JSON.stringify(stepText)} is ${testStepResult.status}`;
202
+ if (info) {
203
+ errInfo = info;
142
204
  }
143
205
  }
144
206
  }
145
- if (message.attachment) {
146
- const attachment = message.attachment;
147
- if (attachment.mediaType === "application/json" && attachment.body) {
148
- const body = JSON.parse(attachment.body);
149
- info = body.info;
150
- const result = body.result;
151
-
152
- if (result.status === "PASSED") {
153
- this.sendExecutionStatus({
154
- type: "cmdExecutionSuccess",
155
- cmdId: body.cmdId,
156
- selectedStrategy: info?.selectedStrategy,
157
- });
158
- } else {
159
- this.sendExecutionStatus({
160
- type: "cmdExecutionError",
161
- cmdId: body.cmdId,
162
- error: {
163
- message: result.message,
164
- info,
165
- },
166
- });
167
- }
168
- } else if (attachment.mediaType === "application/json+intercept-results" && attachment.body) {
169
- const body = JSON.parse(attachment.body);
170
- if (body) {
171
- this.sendExecutionStatus({
172
- type: "interceptResults",
173
- interceptResults: body,
174
- });
175
- }
207
+ }
208
+ if (message.attachment) {
209
+ const attachment = message.attachment;
210
+ if (attachment.mediaType === "application/json" && attachment.body) {
211
+ const body = JSON.parse(attachment.body);
212
+ info = body.info;
213
+ const result = body.result;
214
+
215
+ if (result.status === "PASSED") {
216
+ this.sendExecutionStatus({
217
+ type: "cmdExecutionSuccess",
218
+ cmdId: body.cmdId,
219
+ info,
220
+ selectedStrategy: info?.selectedStrategy,
221
+ });
222
+ } else {
223
+ this.sendExecutionStatus({
224
+ type: "cmdExecutionError",
225
+ cmdId: body.cmdId,
226
+ error: {
227
+ message: result.message,
228
+ info,
229
+ },
230
+ });
231
+ }
232
+ } else if (attachment.mediaType === "application/json+intercept-results" && attachment.body) {
233
+ const body = JSON.parse(attachment.body);
234
+ if (body) {
235
+ this.sendExecutionStatus({
236
+ type: "interceptResults",
237
+ interceptResults: body,
238
+ });
176
239
  }
177
240
  }
178
- });
179
- if (errorMesssage) {
180
- const bvtError = new Error(errorMesssage);
181
- Object.assign(bvtError, { info: errInfo });
182
- throw bvtError;
183
241
  }
242
+ });
184
243
 
185
- return {
186
- result,
187
- info,
188
- };
189
- } catch (error) {
190
- console.error("Error running cucumber-js", error);
191
- throw error;
244
+ if (errorMessage) {
245
+ const bvtError = new Error(errorMessage);
246
+ Object.assign(bvtError, { info: errInfo });
247
+ throw bvtError;
192
248
  }
193
- };
249
+
250
+ return { result, info };
251
+ }
194
252
 
195
253
  async runStep({ step, parametersMap, envPath, tags, config }, bvtContext, options) {
196
- let cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
197
- if (bvtContext.web) {
198
- bvtContext.web.getCmdId = () => {
199
- if (cmdIDs.length === 0) {
200
- cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
201
- }
202
- const cId = cmdIDs.shift();
203
- this.sendExecutionStatus({
204
- type: "cmdExecutionStart",
205
- cmdId: cId,
254
+ // Create a new AbortController for this specific step execution
255
+ this.#currentStepController = new AbortController();
256
+ const { signal } = this.#currentStepController;
257
+
258
+ try {
259
+ this.#lastAttemptedCmdId = null;
260
+ let cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId ?? cmd.id);
261
+ bvtContext.web.pausedCmd = null;
262
+
263
+ // Clear the liveExecutionMap and set up new entries for this step
264
+ this.liveExecutionMap.clear();
265
+
266
+ for (const cmdId of cmdIDs) {
267
+ this.liveExecutionMap.set(cmdId, {
268
+ resolve: () => {},
269
+ reject: () => {},
206
270
  });
207
- return cId;
208
- };
209
- }
210
- let codePage; // = getCodePage();
211
- // const tempFolderPath = process.env.tempFeaturesFolderPath;
212
- const __temp_features_FolderName = "__temp_features" + Math.random().toString(36).substring(2, 7);
213
- const tempFolderPath = path.join(this.projectDir, __temp_features_FolderName);
214
- process.env.tempFeaturesFolderPath = __temp_features_FolderName;
215
- process.env.TESTCASE_REPORT_FOLDER_PATH = tempFolderPath;
216
- // if (!copiedCodeToTemp) {
217
- // await this.copyCodetoTempFolder({ step, parametersMap, tempFolderPath });
218
- // }
219
- await this.copyCodetoTempFolder({ step, parametersMap, tempFolderPath });
220
- // console.log({ feature_file_path });
221
- let stepsDefinitions = loadStepDefinitions(this.projectDir, false, true);
222
- // console.log({ stepsDefinitions });
223
- const cucumberStep = getCucumberStep({ step });
224
- if (cucumberStep.parameters && Array.isArray(cucumberStep.parameters)) {
225
- cucumberStep.parameters.forEach((param) => {
226
- if (param.variableName) {
227
- param.callValue = parametersMap[param.variableName];
228
- }
229
- });
230
- }
271
+ }
231
272
 
232
- if (!step.isImplemented && step.commands.length > 0) {
233
- const pageName = generatePageName(step.startFrame?.url ?? "default");
234
- const stepDefinitionFolderPath = path.join(tempFolderPath, "step_definitions");
235
- if (!existsSync(stepDefinitionFolderPath)) {
236
- mkdirSync(stepDefinitionFolderPath, { recursive: true });
273
+ if (bvtContext.web) {
274
+ bvtContext.web.getCmdId = () => {
275
+ if (cmdIDs.length === 0) {
276
+ cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId ?? cmd.id);
277
+ }
278
+ const cId = cmdIDs.shift();
279
+ this.sendExecutionStatus({
280
+ type: "cmdExecutionStart",
281
+ cmdId: cId,
282
+ });
283
+ this.#lastAttemptedCmdId = cId;
284
+ return cId;
285
+ };
237
286
  }
238
- const stepDefsFilePath = locateDefinitionPath(tempFolderPath, pageName);
239
- //path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
240
- codePage = getCodePage(stepDefsFilePath);
241
- codePage = await saveRecording({ step, cucumberStep, codePage, projectDir: this.projectDir, stepsDefinitions });
242
- if (codePage) {
243
- await codePage.save(stepDefsFilePath);
244
- // console.log("saved code page: ", stepDefsFilePath);
287
+ if (bvtContext.api) {
288
+ bvtContext.api.getCmdId = () => {
289
+ if (cmdIDs.length === 0) {
290
+ cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId ?? cmd.id);
291
+ }
292
+ const cId = cmdIDs.shift();
293
+ this.sendExecutionStatus({
294
+ type: "cmdExecutionStart",
295
+ cmdId: cId,
296
+ });
297
+ this.#lastAttemptedCmdId = cId;
298
+ return cId;
299
+ };
245
300
  }
246
- if (!codePage) {
247
- codePage = getUtilsCodePage(this.projectDir);
301
+
302
+ const __temp_features_FolderName = "__temp_features" + Math.random().toString(36).substring(2, 7);
303
+ const tempFolderPath = path.join(this.projectDir, __temp_features_FolderName);
304
+ process.env.tempFeaturesFolderPath = __temp_features_FolderName;
305
+ process.env.TESTCASE_REPORT_FOLDER_PATH = tempFolderPath;
306
+
307
+ await this.copyCodetoTempFolder({ step, parametersMap, tempFolderPath });
308
+
309
+ // Write abort wrapper code with this step's signal
310
+ await this.writeWrapperCode(tempFolderPath, signal);
311
+
312
+ let stepsDefinitions = loadStepDefinitions(this.projectDir, false, true);
313
+ const cucumberStep = getCucumberStep({ step });
314
+
315
+ if (cucumberStep.parameters && Array.isArray(cucumberStep.parameters)) {
316
+ cucumberStep.parameters.forEach((param) => {
317
+ if (param.variableName) {
318
+ param.callValue = parametersMap[param.variableName];
319
+ }
320
+ });
248
321
  }
249
- } else {
250
- let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
251
- if (process.env.TEMP_RUN === "true") {
252
- // console.log("Save routes in temp folder for running:", routesPath);
253
- if (existsSync(routesPath)) {
254
- console.log("Removing existing temp_routes_folder:", routesPath);
255
- rmSync(routesPath, { recursive: true });
322
+
323
+ if (!step.isImplemented && step.commands.length > 0) {
324
+ const pageName = generatePageName(step.startFrame?.url ?? "default");
325
+ const stepDefinitionFolderPath = path.join(tempFolderPath, "step_definitions");
326
+ if (!existsSync(stepDefinitionFolderPath)) {
327
+ mkdirSync(stepDefinitionFolderPath, { recursive: true });
328
+ }
329
+ const stepDefsFilePath = locateDefinitionPath(tempFolderPath, pageName);
330
+ let codePage = getCodePage(stepDefsFilePath);
331
+ codePage = await saveRecording({
332
+ step,
333
+ cucumberStep,
334
+ codePage,
335
+ projectDir: this.projectDir,
336
+ stepsDefinitions,
337
+ parametersMap,
338
+ });
339
+ if (codePage) {
340
+ await codePage.save(stepDefsFilePath);
341
+ }
342
+ if (!codePage) {
343
+ codePage = getUtilsCodePage(this.projectDir);
256
344
  }
257
- mkdirSync(routesPath, { recursive: true });
258
- console.log("Created temp_routes_folder:", routesPath);
259
- saveRoutes({ step, folderPath: routesPath });
260
345
  } else {
261
- console.log("Saving routes in project directory:", this.projectDir);
262
- if (existsSync(routesPath)) {
263
- // remove the folder
264
- try {
346
+ let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
347
+ if (process.env.TEMP_RUN === "true") {
348
+ if (existsSync(routesPath)) {
265
349
  rmSync(routesPath, { recursive: true });
266
- console.log("Removed temp_routes_folder:", routesPath);
267
- } catch (error) {
268
- console.error("Error removing temp_routes folder", error);
269
350
  }
270
- }
271
- routesPath = path.join(this.projectDir, "data", "routes");
272
- console.log("Saving routes to:", routesPath);
273
- if (!existsSync(routesPath)) {
274
351
  mkdirSync(routesPath, { recursive: true });
352
+ saveRoutes({ step, folderPath: routesPath });
353
+ } else {
354
+ if (existsSync(routesPath)) {
355
+ try {
356
+ rmSync(routesPath, { recursive: true });
357
+ } catch (error) {
358
+ console.error("Error removing temp_routes folder", error);
359
+ }
360
+ }
361
+ routesPath = path.join(this.projectDir, "data", "routes");
362
+ if (!existsSync(routesPath)) {
363
+ mkdirSync(routesPath, { recursive: true });
364
+ }
365
+ saveRoutes({ step, folderPath: routesPath });
275
366
  }
276
- saveRoutes({ step, folderPath: routesPath });
277
367
  }
278
- }
279
- const feature_file_path = await this.writeTempFeatureFile({ step, parametersMap, tempFolderPath, tags });
280
- // console.log({ feature_file_path, step_text: step.text });
281
368
 
282
- const stepExecController = new AbortController();
283
- this.#currentStepController = stepExecController;
284
- const { result, info } = await withAbort(async () => {
285
- return await this.executeStepRemote(
369
+ const feature_file_path = await this.writeTempFeatureFile({
370
+ step,
371
+ parametersMap,
372
+ tempFolderPath,
373
+ tags,
374
+ });
375
+
376
+ // Execute the cucumber step - if wrapper throws "Aborted", it will propagate up
377
+ const { result, info } = await this.executeStepWithAbort(
286
378
  {
287
379
  feature_file_path,
288
380
  tempFolderPath,
@@ -292,12 +384,29 @@ export class BVTStepRunner {
292
384
  },
293
385
  options
294
386
  );
295
- }, stepExecController.signal).finally(() => {
296
- // rm temp folder
297
- if (fs.existsSync(tempFolderPath)) {
298
- fs.rmSync(tempFolderPath, { recursive: true });
387
+
388
+ return { result, info };
389
+ } catch (error) {
390
+ if (error.message && error.message.includes("Aborted")) {
391
+ throw new Error("Aborted");
392
+ } else throw error;
393
+ } finally {
394
+ // Clean up this step's controller and global reference
395
+ this.#currentStepController = null;
396
+ global.__BVT_STEP_ABORT_SIGNAL = null;
397
+
398
+ try {
399
+ // Clean up temp folder
400
+ const __temp_features_FolderName = process.env.tempFeaturesFolderPath;
401
+ if (__temp_features_FolderName) {
402
+ const tempFolderPath = path.join(this.projectDir, __temp_features_FolderName);
403
+ if (fs.existsSync(tempFolderPath)) {
404
+ fs.rmSync(tempFolderPath, { recursive: true });
405
+ }
406
+ }
407
+ } catch (error) {
408
+ console.error("Error cleaning up temp folder", error);
299
409
  }
300
- });
301
- return { result, info };
410
+ }
302
411
  }
303
412
  }