@dev-blinq/cucumber_client 1.0.1353-dev → 1.0.1355-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.
- package/bin/assets/bundled_scripts/recorder.js +1 -1
- package/bin/assets/preload/recorderv3.js +3 -1
- package/bin/assets/scripts/unique_locators.js +822 -815
- package/bin/client/cli_helpers.js +11 -13
- package/bin/client/cucumber/feature.js +80 -27
- package/bin/client/local_agent.js +2 -2
- package/bin/client/project.js +1 -1
- package/bin/client/recorderv3/bvt_recorder.js +7 -5
- package/bin/client/recorderv3/implemented_steps.js +11 -12
- package/bin/client/recorderv3/network.js +22 -5
- package/bin/client/recorderv3/step_runner.js +8 -9
- package/bin/client/recorderv3/update_feature.js +19 -24
- package/bin/client/run_cucumber.js +1 -1
- package/bin/client/scenario_report.js +0 -5
- package/bin/client/test_scenario.js +0 -1
- package/bin/index.js +1 -0
- package/package.json +4 -4
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
|
|
2
1
|
const validateCLIArg = (arg, name) => {
|
|
3
2
|
if (!arg) {
|
|
4
|
-
throw new Error(`${name} is required`)
|
|
3
|
+
throw new Error(`${name} is required`);
|
|
5
4
|
}
|
|
6
|
-
}
|
|
5
|
+
};
|
|
7
6
|
const showUsage = (error, usage) => {
|
|
8
|
-
console.error(error.message)
|
|
9
|
-
console.info(usage)
|
|
10
|
-
process.exit(1)
|
|
11
|
-
}
|
|
12
|
-
const loadArgs = ()=>{
|
|
13
|
-
const args = process.argv.slice(2)
|
|
14
|
-
return args
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export { validateCLIArg, loadArgs, showUsage };
|
|
7
|
+
console.error(error.message);
|
|
8
|
+
console.info(usage);
|
|
9
|
+
process.exit(1);
|
|
10
|
+
};
|
|
11
|
+
const loadArgs = () => {
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
return args;
|
|
14
|
+
};
|
|
15
|
+
export { validateCLIArg, loadArgs, showUsage };
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { IdGenerator } from "@cucumber/messages";
|
|
2
|
+
import { AstBuilder, GherkinClassicTokenMatcher, Parser, compile } from "@cucumber/gherkin";
|
|
1
3
|
import { loadConfiguration, loadSupport, runCucumber } from "@dev-blinq/cucumber-js/api";
|
|
2
4
|
import fs from "fs";
|
|
3
|
-
|
|
5
|
+
import os from "os";
|
|
6
|
+
import path from "path";
|
|
4
7
|
import { parseStepTextParameters, toCucumberExpression, unEscapeNonPrintables } from "./utils.js";
|
|
5
|
-
import
|
|
6
|
-
import { IdGenerator } from "@cucumber/messages";
|
|
8
|
+
import stream from "stream";
|
|
7
9
|
import { testStringForRegex } from "../recorderv3/update_feature.js";
|
|
8
|
-
import
|
|
10
|
+
import { generateTestData } from "./feature_data.js";
|
|
9
11
|
class DataTable {
|
|
10
12
|
constructor(dataTableDocument) {
|
|
11
13
|
if (!dataTableDocument) {
|
|
@@ -449,29 +451,7 @@ class Scenario {
|
|
|
449
451
|
return this.scenarioText;
|
|
450
452
|
}
|
|
451
453
|
}
|
|
452
|
-
const scenarioResolution = async (featureFilePath) => {
|
|
453
|
-
if (!fs.existsSync(featureFilePath)) {
|
|
454
|
-
throw new Error(`Feature file ${featureFilePath} does not exist`);
|
|
455
|
-
}
|
|
456
|
-
const newId = IdGenerator.uuid();
|
|
457
|
-
const builder = new AstBuilder(newId);
|
|
458
|
-
const matcher = new GherkinClassicTokenMatcher();
|
|
459
|
-
|
|
460
|
-
const parser = new Parser(builder, matcher);
|
|
461
|
-
|
|
462
|
-
// normalize the path to start with featuers/ if it's not cut the featureFielPath to only the part after features/
|
|
463
|
-
let uri = featureFilePath.startsWith("features/")
|
|
464
|
-
? featureFilePath
|
|
465
|
-
: "features/" + featureFilePath.split("features/")[1];
|
|
466
454
|
|
|
467
|
-
const featureFileContent = fs.readFileSync(featureFilePath, "utf8");
|
|
468
|
-
const gherkinDocument = parser.parse(featureFileContent, newId);
|
|
469
|
-
|
|
470
|
-
const feature = new Feature(gherkinDocument, featureFileContent);
|
|
471
|
-
//const scenario = feature.getScenario(scenarioName);
|
|
472
|
-
//return scenario;
|
|
473
|
-
return feature;
|
|
474
|
-
};
|
|
475
455
|
const getDocumentAndPickel = (featureName, featureContent, scenarioName) => {
|
|
476
456
|
const newId = IdGenerator.uuid();
|
|
477
457
|
const builder = new AstBuilder(newId);
|
|
@@ -484,12 +464,85 @@ const getDocumentAndPickel = (featureName, featureContent, scenarioName) => {
|
|
|
484
464
|
|
|
485
465
|
const gherkinDocument = parser.parse(featureContent, newId);
|
|
486
466
|
const pickles = compile(gherkinDocument, uri, newId);
|
|
487
|
-
|
|
488
467
|
// Step 3: Find the specific scenario Pickle
|
|
489
468
|
const pickle = pickles.find((pickle) => {
|
|
490
469
|
return pickle.name === scenarioName;
|
|
491
470
|
});
|
|
492
471
|
return { gherkinDocument, pickle };
|
|
493
472
|
};
|
|
473
|
+
const scenarioResolution = async (featureFilePath) => {
|
|
474
|
+
if (!fs.existsSync(featureFilePath)) {
|
|
475
|
+
throw new Error(`Feature file ${featureFilePath} does not exist`);
|
|
476
|
+
}
|
|
477
|
+
const featureFileContent = fs.readFileSync(featureFilePath, "utf8");
|
|
478
|
+
let tmpDir = null;
|
|
479
|
+
try {
|
|
480
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "ai-qa"));
|
|
481
|
+
const tmpFeaturePath = path.join(tmpDir, "features");
|
|
482
|
+
fs.mkdirSync(tmpFeaturePath);
|
|
483
|
+
const tmpFeatureFilePath = path.join(tmpFeaturePath, path.basename(featureFilePath));
|
|
484
|
+
let result = generateTestData(featureFilePath);
|
|
485
|
+
if (result.changed) {
|
|
486
|
+
fs.writeFileSync(tmpFeatureFilePath, result.newContent);
|
|
487
|
+
console.log("Fake data was generated for this scenario");
|
|
488
|
+
console.log("Variables:");
|
|
489
|
+
for (let key in result.variables) {
|
|
490
|
+
console.log(`${key}: ${result.variables[key].fake}`);
|
|
491
|
+
}
|
|
492
|
+
console.log("Other fake data:");
|
|
493
|
+
for (let i = 0; i < result.otherFakeData.length; i++) {
|
|
494
|
+
console.log(`${result.otherFakeData[i].var}: ${result.otherFakeData[i].fake}`);
|
|
495
|
+
}
|
|
496
|
+
} else {
|
|
497
|
+
fs.copyFileSync(featureFilePath, tmpFeatureFilePath);
|
|
498
|
+
}
|
|
499
|
+
const writable = new stream.Writable({
|
|
500
|
+
write: function (chunk, encoding, next) {
|
|
501
|
+
//console.log(chunk.toString());
|
|
502
|
+
next();
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
const environment = { cwd: tmpDir, stdout: writable, stderr: writable };
|
|
506
|
+
// load configuration from a particular file, and override a specific option
|
|
507
|
+
const provided = {
|
|
508
|
+
default: "--publish-quiet",
|
|
509
|
+
require: [tmpDir],
|
|
510
|
+
failFast: false,
|
|
511
|
+
};
|
|
494
512
|
|
|
513
|
+
let gherkinDocument = null;
|
|
514
|
+
const { runConfiguration } = await loadConfiguration({ provided }, environment);
|
|
515
|
+
// load the support code upfront
|
|
516
|
+
const support = await loadSupport(runConfiguration, environment);
|
|
517
|
+
// run cucumber, using the support code we loaded already
|
|
518
|
+
await runCucumber({ ...runConfiguration, support }, environment, function (event) {
|
|
519
|
+
// if (event.source) {
|
|
520
|
+
// scenarioInfo.source = event.source.data;
|
|
521
|
+
// }
|
|
522
|
+
// if (event.pickle && event.pickle.name === scenarioName) {
|
|
523
|
+
// scenarioInfo.pickle = event.pickle;
|
|
524
|
+
// }
|
|
525
|
+
if (event.gherkinDocument) {
|
|
526
|
+
gherkinDocument = event.gherkinDocument;
|
|
527
|
+
}
|
|
528
|
+
//console.log(event);
|
|
529
|
+
//console.log(JSON.stringify(event, null, 2));
|
|
530
|
+
// console.log("");
|
|
531
|
+
});
|
|
532
|
+
const feature = new Feature(gherkinDocument, featureFileContent);
|
|
533
|
+
//const scenario = feature.getScenario(scenarioName);
|
|
534
|
+
//return scenario;
|
|
535
|
+
return feature;
|
|
536
|
+
} finally {
|
|
537
|
+
try {
|
|
538
|
+
if (tmpDir) {
|
|
539
|
+
fs.rmSync(tmpDir, { recursive: true });
|
|
540
|
+
}
|
|
541
|
+
} catch (e) {
|
|
542
|
+
console.error(
|
|
543
|
+
`An error has occurred while removing the temp folder at ${tmpDir}. Please remove it manually. Error: ${e}`
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
};
|
|
495
548
|
export { Feature, Scenario, Step, DataTable, Examples, scenarioResolution, getDocumentAndPickel };
|
|
@@ -971,7 +971,7 @@ class LocalAgent {
|
|
|
971
971
|
async createNewStepLocal(
|
|
972
972
|
featureName,
|
|
973
973
|
cucumberStep,
|
|
974
|
-
|
|
974
|
+
comments,
|
|
975
975
|
userData,
|
|
976
976
|
firstStep,
|
|
977
977
|
previousTasks,
|
|
@@ -1087,7 +1087,7 @@ class LocalAgent {
|
|
|
1087
1087
|
previousTasks,
|
|
1088
1088
|
scenarioDocument,
|
|
1089
1089
|
scenarioStepIndex,
|
|
1090
|
-
comments
|
|
1090
|
+
comments,
|
|
1091
1091
|
featureFileText,
|
|
1092
1092
|
recover,
|
|
1093
1093
|
dumpConfig: this.dumpConfig,
|
package/bin/client/project.js
CHANGED
|
@@ -50,7 +50,7 @@ async function findNestedFrameSelector(frame, obj) {
|
|
|
50
50
|
const frameElement = await frame.frameElement();
|
|
51
51
|
if (!frameElement) return;
|
|
52
52
|
const selectors = await parent.evaluate((element) => {
|
|
53
|
-
return window.
|
|
53
|
+
return window.__bvt_Recorder.locatorGenerator.getElementLocators(element, { excludeText: true }).locators;
|
|
54
54
|
}, frameElement);
|
|
55
55
|
return findNestedFrameSelector(parent, { children: obj, selectors });
|
|
56
56
|
} catch (e) {
|
|
@@ -269,7 +269,6 @@ export class BVTRecorder {
|
|
|
269
269
|
const locator = await this.web.page.locator(selector);
|
|
270
270
|
const snapshot = await locator.ariaSnapshot();
|
|
271
271
|
return snapshot;
|
|
272
|
-
// Triggering workflow
|
|
273
272
|
};
|
|
274
273
|
|
|
275
274
|
processObject = async ({ type, action, value }) => {
|
|
@@ -335,6 +334,7 @@ export class BVTRecorder {
|
|
|
335
334
|
console.error("Error reading ai_config.json", error);
|
|
336
335
|
}
|
|
337
336
|
}
|
|
337
|
+
this.config = ai_config;
|
|
338
338
|
const initScripts = {
|
|
339
339
|
// recorderCjs: injectedScriptSource,
|
|
340
340
|
scripts: [
|
|
@@ -623,6 +623,7 @@ export class BVTRecorder {
|
|
|
623
623
|
this.pageSet.add(page);
|
|
624
624
|
|
|
625
625
|
await page.waitForLoadState("domcontentloaded");
|
|
626
|
+
|
|
626
627
|
// add listener for frame navigation on new tab
|
|
627
628
|
this._addFrameNavigateListener(page);
|
|
628
629
|
} catch (error) {
|
|
@@ -712,7 +713,6 @@ export class BVTRecorder {
|
|
|
712
713
|
if (this.shouldTakeScreenshot) {
|
|
713
714
|
await this.storeScreenshot(event);
|
|
714
715
|
}
|
|
715
|
-
|
|
716
716
|
this.sendEvent(this.events.onNewCommand, cmdEvent);
|
|
717
717
|
this._updateUrlPath();
|
|
718
718
|
}
|
|
@@ -852,6 +852,7 @@ export class BVTRecorder {
|
|
|
852
852
|
parametersMap,
|
|
853
853
|
envPath: this.envName,
|
|
854
854
|
tags,
|
|
855
|
+
config: this.config,
|
|
855
856
|
},
|
|
856
857
|
this.bvtContext,
|
|
857
858
|
{
|
|
@@ -906,6 +907,7 @@ export class BVTRecorder {
|
|
|
906
907
|
// map: this.scenariosStepsMap,
|
|
907
908
|
// });
|
|
908
909
|
}
|
|
910
|
+
|
|
909
911
|
async generateStepName({ commands, stepsNames, parameters, map }) {
|
|
910
912
|
return await this.namesService.generateStepName({ commands, stepsNames, parameters, map });
|
|
911
913
|
}
|
|
@@ -1189,8 +1191,8 @@ export class BVTRecorder {
|
|
|
1189
1191
|
}
|
|
1190
1192
|
async resetExecution({ tags = [] }) {
|
|
1191
1193
|
// run after hooks followed by before hooks
|
|
1192
|
-
await this.
|
|
1193
|
-
await this.
|
|
1194
|
+
await this.cleanupExecution({ tags });
|
|
1195
|
+
await this.initExecution({ tags });
|
|
1194
1196
|
}
|
|
1195
1197
|
}
|
|
1196
1198
|
|
|
@@ -13,7 +13,6 @@ const uuidFn = () => (++id).toString(16);
|
|
|
13
13
|
const builder = new AstBuilder(uuidFn);
|
|
14
14
|
const matcher = new GherkinClassicTokenMatcher();
|
|
15
15
|
const parser = new Parser(builder, matcher);
|
|
16
|
-
|
|
17
16
|
let i = 0;
|
|
18
17
|
const getImplId = () => {
|
|
19
18
|
return `I-${i++}`;
|
|
@@ -289,17 +288,17 @@ export const getImplementedSteps = async (projectDir) => {
|
|
|
289
288
|
for (const tag of scenario.tags) {
|
|
290
289
|
delete tag.location;
|
|
291
290
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
291
|
+
for (const scenario of scenarios) {
|
|
292
|
+
for (const step of scenario.steps) {
|
|
293
|
+
if (step.templateIndex === undefined) {
|
|
294
|
+
const cleanStepName = stepsDefinitions._stepNameToTemplate(step.text);
|
|
295
|
+
const index = implementedSteps.findIndex((istep) => {
|
|
296
|
+
return cleanStepName === istep.pattern;
|
|
297
|
+
});
|
|
298
|
+
step.templateIndex = index;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
303
302
|
}
|
|
304
303
|
if (foundErrors.length > 0) {
|
|
305
304
|
console.log("foundErrors", foundErrors);
|
|
@@ -1,8 +1,18 @@
|
|
|
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
|
+
|
|
1
10
|
class NetworkMonitor {
|
|
2
11
|
constructor() {
|
|
3
12
|
this.networkId = 0;
|
|
4
|
-
|
|
13
|
+
/** @type {Map<string, NetworkEvent>} */
|
|
5
14
|
this.requestIdMap = new Map();
|
|
15
|
+
this.networkEvents = new Map();
|
|
6
16
|
/** @type {Map<import('playwright').Page, {responseListener: Function, requestFailedListener: Function}>} */
|
|
7
17
|
this.pageListeners = new Map();
|
|
8
18
|
}
|
|
@@ -12,7 +22,6 @@ class NetworkMonitor {
|
|
|
12
22
|
* @param {import('playwright').Page} page
|
|
13
23
|
*/
|
|
14
24
|
addNetworkEventListener(page) {
|
|
15
|
-
|
|
16
25
|
// Create the listener functions
|
|
17
26
|
const responseListener = async (response) => {
|
|
18
27
|
const request = response.request();
|
|
@@ -201,7 +210,6 @@ class NetworkMonitor {
|
|
|
201
210
|
// Try to get response body safely (only for successful responses)
|
|
202
211
|
if (response && networkEvent.status === "completed") {
|
|
203
212
|
try {
|
|
204
|
-
|
|
205
213
|
const isBinary =
|
|
206
214
|
!response.headers()["content-type"]?.includes("application/json") &&
|
|
207
215
|
!response.headers()["content-type"]?.includes("text");
|
|
@@ -229,7 +237,6 @@ class NetworkMonitor {
|
|
|
229
237
|
marshalledEvent.failureReason = request.failure()?.errorText || "Unknown error";
|
|
230
238
|
}
|
|
231
239
|
|
|
232
|
-
|
|
233
240
|
console.log("Marshalled network event:", marshalledEvent);
|
|
234
241
|
|
|
235
242
|
return marshalledEvent;
|
|
@@ -246,7 +253,18 @@ class NetworkMonitor {
|
|
|
246
253
|
}
|
|
247
254
|
}
|
|
248
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
|
+
}
|
|
249
266
|
|
|
267
|
+
/**
|
|
250
268
|
* Get marshalled network events since this ID
|
|
251
269
|
* @returns {Promise<Object[]>}
|
|
252
270
|
* @param {number} sinceId
|
|
@@ -263,7 +281,6 @@ class NetworkMonitor {
|
|
|
263
281
|
* @param {number} endId
|
|
264
282
|
* @returns {Promise<Object[]>}
|
|
265
283
|
*/
|
|
266
|
-
|
|
267
284
|
async getMarshalledNetworkEventsInRange(startId, endId) {
|
|
268
285
|
const events = this.getNetworkEventsInRange(startId, endId);
|
|
269
286
|
const marshalledEvents = await Promise.all(events.map((event) => this.marshallNetworkEvent(event)));
|
|
@@ -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,6 +11,7 @@ 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
17
|
|
|
@@ -78,7 +78,7 @@ export class BVTStepRunner {
|
|
|
78
78
|
return tFilePath;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
executeStepRemote = async ({ feature_file_path, scenario, tempFolderPath, stepText }, options) => {
|
|
81
|
+
executeStepRemote = async ({ feature_file_path, scenario, tempFolderPath, stepText, config }, options) => {
|
|
82
82
|
const { skipAfter = true, skipBefore = true } = options || {};
|
|
83
83
|
const environment = {
|
|
84
84
|
...process.env,
|
|
@@ -110,7 +110,7 @@ export class BVTStepRunner {
|
|
|
110
110
|
// ignore afterAll/after hooks
|
|
111
111
|
support.afterTestCaseHookDefinitions = [];
|
|
112
112
|
}
|
|
113
|
-
if (skipBefore) {
|
|
113
|
+
if (skipBefore && !config.legacySyntax) {
|
|
114
114
|
// ignore beforeAll/before hooks
|
|
115
115
|
support.beforeTestCaseHookDefinitions = support.beforeTestCaseHookDefinitions.filter((hook) => {
|
|
116
116
|
return hook.uri.endsWith("utils.mjs");
|
|
@@ -135,9 +135,7 @@ export class BVTStepRunner {
|
|
|
135
135
|
}
|
|
136
136
|
if (testStepResult.status === "UNDEFINED") {
|
|
137
137
|
if (!errorMesssage) {
|
|
138
|
-
errorMesssage = stepText
|
|
139
|
-
? `step ${JSON.stringify(stepText)} is ${testStepResult.status}`
|
|
140
|
-
: testStepResult.message;
|
|
138
|
+
errorMesssage = `step ${JSON.stringify(stepText)} is ${testStepResult.status}`;
|
|
141
139
|
if (info) {
|
|
142
140
|
errInfo = info;
|
|
143
141
|
}
|
|
@@ -193,7 +191,7 @@ export class BVTStepRunner {
|
|
|
193
191
|
}
|
|
194
192
|
};
|
|
195
193
|
|
|
196
|
-
async runStep({ step, parametersMap, envPath, tags }, bvtContext, options) {
|
|
194
|
+
async runStep({ step, parametersMap, envPath, tags, config }, bvtContext, options) {
|
|
197
195
|
let cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
|
|
198
196
|
if (bvtContext.web) {
|
|
199
197
|
bvtContext.web.getCmdId = () => {
|
|
@@ -250,7 +248,7 @@ export class BVTStepRunner {
|
|
|
250
248
|
} else {
|
|
251
249
|
let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
252
250
|
if (process.env.TEMP_RUN === "true") {
|
|
253
|
-
console.log("Save routes in temp folder for running:", routesPath);
|
|
251
|
+
// console.log("Save routes in temp folder for running:", routesPath);
|
|
254
252
|
if (existsSync(routesPath)) {
|
|
255
253
|
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
256
254
|
rmSync(routesPath, { recursive: true });
|
|
@@ -283,12 +281,13 @@ export class BVTStepRunner {
|
|
|
283
281
|
const stepExecController = new AbortController();
|
|
284
282
|
this.#currentStepController = stepExecController;
|
|
285
283
|
const { result, info } = await withAbort(async () => {
|
|
286
|
-
return this.executeStepRemote(
|
|
284
|
+
return await this.executeStepRemote(
|
|
287
285
|
{
|
|
288
286
|
feature_file_path,
|
|
289
287
|
tempFolderPath,
|
|
290
288
|
stepText: step.text,
|
|
291
289
|
scenario: "Temp Scenario",
|
|
290
|
+
config,
|
|
292
291
|
},
|
|
293
292
|
options
|
|
294
293
|
);
|
|
@@ -213,14 +213,12 @@ const GherkinToObject = (gherkin) => {
|
|
|
213
213
|
steps: [],
|
|
214
214
|
};
|
|
215
215
|
while (idx < lines.length && lines[idx].startsWith("@")) {
|
|
216
|
-
skipEmptyLines();
|
|
217
216
|
const tags = [...lines[idx].matchAll(/@([^@]+)/g)].map((match) => match[1].trim());
|
|
218
217
|
scenario.tags.push(...(tags ?? []));
|
|
219
218
|
idx++;
|
|
219
|
+
skipEmptyLines();
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
skipEmptyLines();
|
|
223
|
-
|
|
224
222
|
if (idx < lines.length && (lines[idx].startsWith("Scenario:") || lines[idx].startsWith("Scenario Outline:"))) {
|
|
225
223
|
scenario.name = lines[idx].substring(lines[idx].indexOf(":") + 1).trim();
|
|
226
224
|
idx++;
|
|
@@ -243,32 +241,32 @@ const GherkinToObject = (gherkin) => {
|
|
|
243
241
|
!lines[idx].startsWith("@")
|
|
244
242
|
) {
|
|
245
243
|
const line = lines[idx++];
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
type: "comment",
|
|
251
|
-
text: comment,
|
|
252
|
-
};
|
|
253
|
-
scenario.steps.push(command);
|
|
254
|
-
}
|
|
255
|
-
} else if (line.startsWith("Examples:")) {
|
|
256
|
-
obj.hasParams = true;
|
|
257
|
-
const command = {
|
|
244
|
+
let command;
|
|
245
|
+
if (line.startsWith("Examples:")) {
|
|
246
|
+
scenario.hasParams = true;
|
|
247
|
+
command = {
|
|
258
248
|
type: "examples",
|
|
259
249
|
lines: [],
|
|
260
250
|
};
|
|
261
|
-
|
|
262
251
|
while (idx < lines.length && lines[idx].startsWith("|")) {
|
|
263
252
|
const line = lines[idx++];
|
|
264
253
|
command.lines.push(line);
|
|
265
254
|
}
|
|
266
255
|
} else {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
256
|
+
if (line.startsWith("#")) {
|
|
257
|
+
command = {
|
|
258
|
+
type: "comment",
|
|
259
|
+
text: line,
|
|
260
|
+
};
|
|
261
|
+
} else {
|
|
262
|
+
command = {
|
|
263
|
+
type: "step",
|
|
264
|
+
text: line,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
271
267
|
}
|
|
268
|
+
scenario.steps.push(command);
|
|
269
|
+
skipEmptyLines();
|
|
272
270
|
}
|
|
273
271
|
|
|
274
272
|
return scenario;
|
|
@@ -277,7 +275,6 @@ const GherkinToObject = (gherkin) => {
|
|
|
277
275
|
while (idx < lines.length) {
|
|
278
276
|
const scenario = getScenario();
|
|
279
277
|
if (scenario === -1) break;
|
|
280
|
-
|
|
281
278
|
if (scenario.error) {
|
|
282
279
|
return {
|
|
283
280
|
error: scenario.error,
|
|
@@ -303,8 +300,7 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
|
|
|
303
300
|
skipScenarioIndex = i;
|
|
304
301
|
continue;
|
|
305
302
|
}
|
|
306
|
-
let scenarioContent = `${
|
|
307
|
-
|
|
303
|
+
let scenarioContent = `${scenario.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
|
|
308
304
|
let tagsLine;
|
|
309
305
|
if (scenario.tags?.length > 0) {
|
|
310
306
|
tagsLine = `${scenario.tags.map((t) => `@${t}`).join(" ")}`;
|
|
@@ -327,7 +323,6 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
|
|
|
327
323
|
if (skipScenarioIndex !== -1) {
|
|
328
324
|
finalContent = results.join("\n") + "\n" + scenarioContent;
|
|
329
325
|
}
|
|
330
|
-
|
|
331
326
|
return finalContent;
|
|
332
327
|
}
|
|
333
328
|
export async function updateFeatureFile({ featureName, scenario, override, projectDir }) {
|
|
@@ -33,17 +33,12 @@ const findNextIdInFolder = (folder) => {
|
|
|
33
33
|
// get temp file path from --temp-file arg
|
|
34
34
|
const getTempFilePath = () => {
|
|
35
35
|
let tempFilePath = null;
|
|
36
|
-
|
|
37
36
|
for (const arg of process.argv) {
|
|
38
37
|
const [key, path] = arg.split("=");
|
|
39
38
|
if (key === "--temp-file" && !!path) {
|
|
40
39
|
tempFilePath = path;
|
|
41
40
|
}
|
|
42
41
|
}
|
|
43
|
-
|
|
44
|
-
if (tempFilePath === null) {
|
|
45
|
-
tempFilePath = process.env.TEMP_FILE_PATH;
|
|
46
|
-
}
|
|
47
42
|
return tempFilePath;
|
|
48
43
|
};
|
|
49
44
|
|
package/bin/index.js
CHANGED
|
@@ -13,4 +13,5 @@ export * from "./client/cucumber/feature_data.js";
|
|
|
13
13
|
export * from "./client/cucumber/steps_definitions.js";
|
|
14
14
|
export * from "./client/profiler.js";
|
|
15
15
|
export * from "./client/code_cleanup/utils.js";
|
|
16
|
+
|
|
16
17
|
export * from "./client/code_cleanup/find_step_definition_references.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev-blinq/cucumber_client",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "1.0.1355-dev",
|
|
4
|
+
"description": " ",
|
|
5
5
|
"main": "bin/index.js",
|
|
6
6
|
"types": "bin/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"socket.io-client": "^4.7.5",
|
|
54
54
|
"tunnel": "^0.0.6",
|
|
55
55
|
"unzipper": "^0.12.3",
|
|
56
|
+
"win-ca": "^3.5.1",
|
|
56
57
|
"winston": "^3.10.0",
|
|
57
58
|
"winston-daily-rotate-file": "^4.7.1",
|
|
58
59
|
"ws": "^8.16.0",
|
|
@@ -65,7 +66,6 @@
|
|
|
65
66
|
"mocha": "^10.2.0",
|
|
66
67
|
"readline-sync": "^1.4.10",
|
|
67
68
|
"tsup": "^8.5.0",
|
|
68
|
-
"typescript": "^5.8.3"
|
|
69
|
-
"win-ca": "^3.5.1"
|
|
69
|
+
"typescript": "^5.8.3"
|
|
70
70
|
}
|
|
71
71
|
}
|