@dev-blinq/cucumber_client 1.0.1361-dev → 1.0.1361-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 +107 -107
- package/bin/assets/preload/css_gen.js +10 -10
- 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 +13 -23
- package/bin/assets/scripts/snapshot_capturer.js +147 -147
- package/bin/assets/scripts/unique_locators.js +163 -44
- package/bin/assets/scripts/yaml.js +796 -783
- package/bin/assets/templates/_hooks_template.txt +41 -0
- package/bin/assets/templates/utils_template.txt +2 -45
- package/bin/client/apiTest/apiTest.js +6 -0
- 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 +107 -2
- package/bin/client/code_gen/function_signature.js +4 -0
- package/bin/client/code_gen/page_reflection.js +846 -906
- package/bin/client/code_gen/playwright_codeget.js +25 -11
- package/bin/client/cucumber/feature.js +4 -0
- 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 +6 -3
- package/bin/client/cucumber_selector.js +17 -1
- package/bin/client/local_agent.js +4 -3
- 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 +213 -90
- package/bin/client/recorderv3/implemented_steps.js +8 -0
- package/bin/client/recorderv3/index.js +59 -54
- package/bin/client/recorderv3/scriptTest.js +1 -1
- package/bin/client/recorderv3/services.js +4 -16
- package/bin/client/recorderv3/step_runner.js +315 -205
- package/bin/client/recorderv3/step_utils.js +475 -16
- package/bin/client/recorderv3/update_feature.js +9 -5
- package/bin/client/recording.js +1 -0
- package/bin/client/upload-service.js +3 -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 -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
|
-
|
|
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,210 +99,282 @@ export class BVTStepRunner {
|
|
|
78
99
|
return tFilePath;
|
|
79
100
|
}
|
|
80
101
|
|
|
81
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
+
});
|
|
175
239
|
}
|
|
176
240
|
}
|
|
177
|
-
});
|
|
178
|
-
if (errorMesssage) {
|
|
179
|
-
const bvtError = new Error(errorMesssage);
|
|
180
|
-
Object.assign(bvtError, { info: errInfo });
|
|
181
|
-
throw bvtError;
|
|
182
241
|
}
|
|
242
|
+
});
|
|
183
243
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
} catch (error) {
|
|
189
|
-
console.error("Error running cucumber-js", error);
|
|
190
|
-
throw error;
|
|
244
|
+
if (errorMessage) {
|
|
245
|
+
const bvtError = new Error(errorMessage);
|
|
246
|
+
Object.assign(bvtError, { info: errInfo });
|
|
247
|
+
throw bvtError;
|
|
191
248
|
}
|
|
192
|
-
|
|
249
|
+
|
|
250
|
+
return { result, info };
|
|
251
|
+
}
|
|
193
252
|
|
|
194
253
|
async runStep({ step, parametersMap, envPath, tags, config }, bvtContext, options) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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: () => {},
|
|
205
270
|
});
|
|
206
|
-
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
let codePage; // = getCodePage();
|
|
210
|
-
// const tempFolderPath = process.env.tempFeaturesFolderPath;
|
|
211
|
-
const __temp_features_FolderName = "__temp_features" + Math.random().toString(36).substring(2, 7);
|
|
212
|
-
const tempFolderPath = path.join(this.projectDir, __temp_features_FolderName);
|
|
213
|
-
process.env.tempFeaturesFolderPath = __temp_features_FolderName;
|
|
214
|
-
process.env.TESTCASE_REPORT_FOLDER_PATH = tempFolderPath;
|
|
215
|
-
// if (!copiedCodeToTemp) {
|
|
216
|
-
// await this.copyCodetoTempFolder({ step, parametersMap, tempFolderPath });
|
|
217
|
-
// }
|
|
218
|
-
await this.copyCodetoTempFolder({ step, parametersMap, tempFolderPath });
|
|
219
|
-
// console.log({ feature_file_path });
|
|
220
|
-
let stepsDefinitions = loadStepDefinitions(this.projectDir, false, true);
|
|
221
|
-
// console.log({ stepsDefinitions });
|
|
222
|
-
const cucumberStep = getCucumberStep({ step });
|
|
223
|
-
if (cucumberStep.parameters && Array.isArray(cucumberStep.parameters)) {
|
|
224
|
-
cucumberStep.parameters.forEach((param) => {
|
|
225
|
-
if (param.variableName) {
|
|
226
|
-
param.callValue = parametersMap[param.variableName];
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
}
|
|
271
|
+
}
|
|
230
272
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
+
};
|
|
236
286
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
+
};
|
|
244
300
|
}
|
|
245
|
-
|
|
246
|
-
|
|
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
|
+
});
|
|
247
321
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (existsSync(
|
|
253
|
-
|
|
254
|
-
|
|
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);
|
|
255
344
|
}
|
|
256
|
-
mkdirSync(routesPath, { recursive: true });
|
|
257
|
-
console.log("Created temp_routes_folder:", routesPath);
|
|
258
|
-
saveRoutes({ step, folderPath: routesPath });
|
|
259
345
|
} else {
|
|
260
|
-
|
|
261
|
-
if (
|
|
262
|
-
|
|
263
|
-
try {
|
|
346
|
+
let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
347
|
+
if (process.env.TEMP_RUN === "true") {
|
|
348
|
+
if (existsSync(routesPath)) {
|
|
264
349
|
rmSync(routesPath, { recursive: true });
|
|
265
|
-
console.log("Removed temp_routes_folder:", routesPath);
|
|
266
|
-
} catch (error) {
|
|
267
|
-
console.error("Error removing temp_routes folder", error);
|
|
268
350
|
}
|
|
269
|
-
}
|
|
270
|
-
routesPath = path.join(this.projectDir, "data", "routes");
|
|
271
|
-
console.log("Saving routes to:", routesPath);
|
|
272
|
-
if (!existsSync(routesPath)) {
|
|
273
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 });
|
|
274
366
|
}
|
|
275
|
-
saveRoutes({ step, folderPath: routesPath });
|
|
276
367
|
}
|
|
277
|
-
}
|
|
278
|
-
const feature_file_path = await this.writeTempFeatureFile({ step, parametersMap, tempFolderPath, tags });
|
|
279
|
-
// console.log({ feature_file_path, step_text: step.text });
|
|
280
368
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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(
|
|
285
378
|
{
|
|
286
379
|
feature_file_path,
|
|
287
380
|
tempFolderPath,
|
|
@@ -291,12 +384,29 @@ export class BVTStepRunner {
|
|
|
291
384
|
},
|
|
292
385
|
options
|
|
293
386
|
);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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);
|
|
298
409
|
}
|
|
299
|
-
}
|
|
300
|
-
return { result, info };
|
|
410
|
+
}
|
|
301
411
|
}
|
|
302
412
|
}
|