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