@dev-blinq/cucumber_client 1.0.1184-dev → 1.0.1184-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 +220 -0
- package/bin/assets/preload/accessibility.js +1 -1
- package/bin/assets/preload/find_context.js +1 -1
- package/bin/assets/preload/generateSelector.js +24 -0
- package/bin/assets/preload/locators.js +18 -0
- package/bin/assets/preload/recorderv3.js +80 -9
- package/bin/assets/preload/unique_locators.js +24 -3
- package/bin/assets/scripts/aria_snapshot.js +235 -0
- package/bin/assets/scripts/dom_attr.js +372 -0
- package/bin/assets/scripts/dom_element.js +0 -0
- package/bin/assets/scripts/dom_parent.js +185 -0
- package/bin/assets/scripts/event_utils.js +105 -0
- package/bin/assets/scripts/pw.js +7886 -0
- package/bin/assets/scripts/recorder.js +1147 -0
- package/bin/assets/scripts/snapshot_capturer.js +155 -0
- package/bin/assets/scripts/unique_locators.js +844 -0
- package/bin/assets/scripts/yaml.js +4770 -0
- package/bin/assets/templates/page_template.txt +2 -16
- package/bin/assets/templates/utils_template.txt +65 -12
- package/bin/client/cli_helpers.js +0 -1
- package/bin/client/code_cleanup/utils.js +43 -14
- package/bin/client/code_gen/code_inversion.js +44 -12
- package/bin/client/code_gen/index.js +3 -0
- package/bin/client/code_gen/page_reflection.js +37 -20
- package/bin/client/code_gen/playwright_codeget.js +149 -43
- package/bin/client/cucumber/feature.js +96 -42
- package/bin/client/cucumber/project_to_document.js +8 -7
- package/bin/client/cucumber/steps_definitions.js +49 -16
- package/bin/client/local_agent.js +9 -7
- package/bin/client/operations/dump_tree.js +159 -5
- package/bin/client/playground/playground.js +1 -1
- package/bin/client/project.js +6 -2
- package/bin/client/recorderv3/bvt_recorder.js +279 -81
- package/bin/client/recorderv3/cli.js +1 -0
- package/bin/client/recorderv3/implemented_steps.js +111 -11
- package/bin/client/recorderv3/index.js +48 -4
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/step_runner.js +183 -13
- package/bin/client/recorderv3/step_utils.js +159 -14
- package/bin/client/recorderv3/update_feature.js +53 -28
- package/bin/client/recording.js +8 -0
- package/bin/client/run_cucumber.js +16 -2
- package/bin/client/scenario_report.js +112 -55
- package/bin/client/test_scenario.js +0 -1
- package/bin/index.js +1 -0
- package/package.json +15 -8
- package/bin/client/code_gen/get_implemented_steps.js +0 -27
|
@@ -3,8 +3,7 @@ import { closeContext, initContext, _getDataFile, resetTestData } from "automati
|
|
|
3
3
|
import { existsSync, readdirSync, readFileSync, rmSync } from "fs";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import url from "url";
|
|
6
|
-
import
|
|
7
|
-
import { getImplementedSteps } from "./implemented_steps.js";
|
|
6
|
+
import { getImplementedSteps, parseRouteFiles } from "./implemented_steps.js";
|
|
8
7
|
import { NamesService } from "./services.js";
|
|
9
8
|
import { BVTStepRunner } from "./step_runner.js";
|
|
10
9
|
import { readFile, writeFile } from "fs/promises";
|
|
@@ -16,41 +15,22 @@ import chokidar from "chokidar";
|
|
|
16
15
|
import logger from "../../logger.js";
|
|
17
16
|
import { unEscapeNonPrintables } from "../cucumber/utils.js";
|
|
18
17
|
import { findAvailablePort } from "../utils/index.js";
|
|
18
|
+
import NetworkMonitor from "./network.js";
|
|
19
|
+
import { Step } from "../cucumber/feature.js";
|
|
20
|
+
|
|
19
21
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
20
|
-
|
|
22
|
+
|
|
21
23
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
22
|
-
export function getInitScript(config) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
window.__bvt_Recorder.setPopupHandlers(${JSON.stringify(popupHandlers)});
|
|
31
|
-
window.__bvt_Recorder.setDisableHighlight(${JSON.stringify(disableHighlight)});
|
|
32
|
-
window.__bvt_Recorder.setImproviseLocators(${JSON.stringify(!disableMultipleLocators)});`;
|
|
33
|
-
return (
|
|
34
|
-
[
|
|
35
|
-
path.join(__dirname, "..", "..", "assets", "preload", "accessibility.js"),
|
|
36
|
-
path.join(__dirname, "..", "..", "assets", "preload", "dom-utils.js"),
|
|
37
|
-
path.join(__dirname, "..", "..", "assets", "preload", "generateSelector.js"),
|
|
38
|
-
path.join(__dirname, "..", "..", "assets", "preload", "locators.js"),
|
|
39
|
-
path.join(__dirname, "..", "..", "assets", "preload", "unique_locators.js"),
|
|
40
|
-
// path.join(__dirname, "..", "..", "assets", "preload", "pw_locators.js"),
|
|
41
|
-
path.join(__dirname, "..", "..", "assets", "preload", "climb.js"),
|
|
42
|
-
path.join(__dirname, "..", "..", "assets", "preload", "text-locator.js"),
|
|
43
|
-
path.join(__dirname, "..", "..", "assets", "preload", "toolbar.js"),
|
|
44
|
-
path.join(__dirname, "..", "..", "assets", "preload", "recording-tool.js"),
|
|
45
|
-
path.join(__dirname, "..", "..", "assets", "preload", "find_context.js"),
|
|
46
|
-
path.join(__dirname, "..", "..", "assets", "preload", "recorderv3.js"),
|
|
47
|
-
path.join(__dirname, "..", "..", "assets", "preload", "findElementText.js"),
|
|
48
|
-
path.join(__dirname, "..", "..", "assets", "preload", "css_gen.js"),
|
|
49
|
-
path.join(__dirname, "..", "..", "assets", "preload", "yaml.js"),
|
|
50
|
-
]
|
|
51
|
-
.map((filePath) => readFileSync(filePath, "utf8"))
|
|
52
|
-
.join("\n") + popupScript
|
|
24
|
+
export function getInitScript(config, options) {
|
|
25
|
+
const preScript = `
|
|
26
|
+
window.__bvt_Recorder_config = ${JSON.stringify(config ?? null)};
|
|
27
|
+
window.__PW_options = ${JSON.stringify(options ?? null)};
|
|
28
|
+
`;
|
|
29
|
+
const recorderScript = readFileSync(
|
|
30
|
+
path.join(__dirname, "..", "..", "assets", "bundled_scripts", "recorder.js"),
|
|
31
|
+
"utf8"
|
|
53
32
|
);
|
|
33
|
+
return preScript + recorderScript;
|
|
54
34
|
}
|
|
55
35
|
|
|
56
36
|
async function evaluate(frame, script) {
|
|
@@ -71,7 +51,7 @@ async function findNestedFrameSelector(frame, obj) {
|
|
|
71
51
|
const frameElement = await frame.frameElement();
|
|
72
52
|
if (!frameElement) return;
|
|
73
53
|
const selectors = await parent.evaluate((element) => {
|
|
74
|
-
return window.
|
|
54
|
+
return window.__bvt_Recorder.locatorGenerator.getElementLocators(element, { excludeText: true }).locators;
|
|
75
55
|
}, frameElement);
|
|
76
56
|
return findNestedFrameSelector(parent, { children: obj, selectors });
|
|
77
57
|
} catch (e) {
|
|
@@ -198,6 +178,7 @@ export class BVTRecorder {
|
|
|
198
178
|
this.logger = logger;
|
|
199
179
|
this.screenshotMap = new Map();
|
|
200
180
|
this.snapshotMap = new Map();
|
|
181
|
+
this.scenariosStepsMap = new Map();
|
|
201
182
|
this.namesService = new NamesService({
|
|
202
183
|
screenshotMap: this.screenshotMap,
|
|
203
184
|
TOKEN: this.TOKEN,
|
|
@@ -206,15 +187,39 @@ export class BVTRecorder {
|
|
|
206
187
|
});
|
|
207
188
|
this.stepRunner = new BVTStepRunner({
|
|
208
189
|
projectDir: this.projectDir,
|
|
190
|
+
sendExecutionStatus: (data) => {
|
|
191
|
+
if (data && data.type) {
|
|
192
|
+
switch (data.type) {
|
|
193
|
+
case "cmdExecutionStart":
|
|
194
|
+
// console.log("Sending cmdExecutionStart event for cmdId:", data);
|
|
195
|
+
this.sendEvent(this.events.cmdExecutionStart, data);
|
|
196
|
+
break;
|
|
197
|
+
case "cmdExecutionSuccess":
|
|
198
|
+
// console.log("Sending cmdExecutionSuccess event for cmdId:", data);
|
|
199
|
+
this.sendEvent(this.events.cmdExecutionSuccess, data);
|
|
200
|
+
break;
|
|
201
|
+
case "cmdExecutionError":
|
|
202
|
+
// console.log("Sending cmdExecutionError event for cmdId:", data);
|
|
203
|
+
this.sendEvent(this.events.cmdExecutionError, data);
|
|
204
|
+
break;
|
|
205
|
+
case "interceptResults":
|
|
206
|
+
// console.log("Sending interceptResults event");
|
|
207
|
+
this.sendEvent(this.events.interceptResults, data);
|
|
208
|
+
break;
|
|
209
|
+
default:
|
|
210
|
+
console.warn("Unknown command execution status type:", data.type);
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
},
|
|
209
215
|
});
|
|
210
216
|
this.pageSet = new Set();
|
|
211
|
-
|
|
217
|
+
this.pageMetaDataSet = new Set();
|
|
212
218
|
this.lastKnownUrlPath = "";
|
|
213
219
|
// TODO: what is world?
|
|
214
|
-
this.world = { attach: () => {} };
|
|
220
|
+
this.world = { attach: () => { } };
|
|
215
221
|
this.shouldTakeScreenshot = true;
|
|
216
222
|
this.watcher = null;
|
|
217
|
-
this.sendEvent("BVTRecorder.getTestData", {});
|
|
218
223
|
}
|
|
219
224
|
events = {
|
|
220
225
|
onFrameNavigate: "BVTRecorder.onFrameNavigate",
|
|
@@ -225,6 +230,10 @@ export class BVTRecorder {
|
|
|
225
230
|
onStepDetails: "BVTRecorder.onStepDetails",
|
|
226
231
|
getTestData: "BVTRecorder.getTestData",
|
|
227
232
|
onGoto: "BVTRecorder.onGoto",
|
|
233
|
+
cmdExecutionStart: "BVTRecorder.cmdExecutionStart",
|
|
234
|
+
cmdExecutionSuccess: "BVTRecorder.cmdExecutionSuccess",
|
|
235
|
+
cmdExecutionError: "BVTRecorder.cmdExecutionError",
|
|
236
|
+
interceptResults: "BVTRecorder.interceptResults",
|
|
228
237
|
};
|
|
229
238
|
bindings = {
|
|
230
239
|
__bvt_recordCommand: async ({ frame, page, context }, event) => {
|
|
@@ -300,22 +309,15 @@ export class BVTRecorder {
|
|
|
300
309
|
return result;
|
|
301
310
|
}
|
|
302
311
|
getInitScripts(config) {
|
|
303
|
-
return getInitScript(config
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
// const inlineScript = `
|
|
313
|
-
// window.__bvt_Recorder.setPopupHandlers(${JSON.stringify(popupHandlers)});
|
|
314
|
-
// window.__bvt_Recorder.setDisableHighlight(${JSON.stringify(disableHighlight)});
|
|
315
|
-
// window.__bvt_Recorder.setImproviseLocators(${JSON.stringify(!disableMultipleLocators)});
|
|
316
|
-
// `
|
|
317
|
-
// scripts.push(inlineScript);
|
|
318
|
-
// return scripts;
|
|
312
|
+
return getInitScript(config, {
|
|
313
|
+
sdkLanguage: "javascript",
|
|
314
|
+
testIdAttributeName: "blinq-test-id",
|
|
315
|
+
stableRafCount: 0,
|
|
316
|
+
browserName: this.browser?.browserType().name(),
|
|
317
|
+
inputFileRoleTextbox: false,
|
|
318
|
+
customEngines: [],
|
|
319
|
+
isUnderTest: true,
|
|
320
|
+
});
|
|
319
321
|
}
|
|
320
322
|
|
|
321
323
|
async _initBrowser({ url }) {
|
|
@@ -323,7 +325,7 @@ export class BVTRecorder {
|
|
|
323
325
|
process.env.CDP_LISTEN_PORT = this.#remoteDebuggerPort;
|
|
324
326
|
|
|
325
327
|
this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
|
|
326
|
-
this.world = { attach: () => {} };
|
|
328
|
+
this.world = { attach: () => { } };
|
|
327
329
|
|
|
328
330
|
const ai_config_file = path.join(this.projectDir, "ai_config.json");
|
|
329
331
|
let ai_config = {};
|
|
@@ -334,8 +336,9 @@ export class BVTRecorder {
|
|
|
334
336
|
console.error("Error reading ai_config.json", error);
|
|
335
337
|
}
|
|
336
338
|
}
|
|
339
|
+
this.config = ai_config;
|
|
337
340
|
const initScripts = {
|
|
338
|
-
recorderCjs: injectedScriptSource,
|
|
341
|
+
// recorderCjs: injectedScriptSource,
|
|
339
342
|
scripts: [
|
|
340
343
|
this.getInitScripts(ai_config),
|
|
341
344
|
`\ndelete Object.getPrototypeOf(navigator).webdriver;${process.env.WINDOW_DEBUGGER ? "window.debug=true;\n" : ""}`,
|
|
@@ -462,6 +465,75 @@ export class BVTRecorder {
|
|
|
462
465
|
}
|
|
463
466
|
});
|
|
464
467
|
}
|
|
468
|
+
|
|
469
|
+
hasHistoryReplacementAtIndex(previousEntries, currentEntries, index) {
|
|
470
|
+
if (!previousEntries || !currentEntries) return false;
|
|
471
|
+
if (index >= previousEntries.length || index >= currentEntries.length) return false;
|
|
472
|
+
|
|
473
|
+
const prevEntry = previousEntries[index];
|
|
474
|
+
// console.log("prevEntry", prevEntry);
|
|
475
|
+
const currEntry = currentEntries[index];
|
|
476
|
+
// console.log("currEntry", currEntry);
|
|
477
|
+
|
|
478
|
+
// Check if the entry at this index has been replaced
|
|
479
|
+
return prevEntry.id !== currEntry.id;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Even simpler approach for your specific case
|
|
483
|
+
analyzeTransitionType(entries, currentIndex, currentEntry) {
|
|
484
|
+
// console.log("Analyzing transition type");
|
|
485
|
+
// console.log("===========================");
|
|
486
|
+
// console.log("Current Index:", currentIndex);
|
|
487
|
+
// console.log("Current Entry:", currentEntry);
|
|
488
|
+
// console.log("Current Entries:", entries);
|
|
489
|
+
// console.log("Current entries length:", entries.length);
|
|
490
|
+
// console.log("===========================");
|
|
491
|
+
// console.log("Previous Index:", this.previousIndex);
|
|
492
|
+
// // console.log("Previous Entry:", this.previousEntries[this.previousIndex]);
|
|
493
|
+
// console.log("Previous Entries:", this.previousEntries);
|
|
494
|
+
// console.log("Previous entries length:", this.previousHistoryLength);
|
|
495
|
+
|
|
496
|
+
if (this.previousIndex === null || this.previousHistoryLength === null || !this.previousEntries) {
|
|
497
|
+
return {
|
|
498
|
+
action: "initial",
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const indexDiff = currentIndex - this.previousIndex;
|
|
503
|
+
const lengthDiff = entries.length - this.previousHistoryLength;
|
|
504
|
+
|
|
505
|
+
// Backward navigation
|
|
506
|
+
if (indexDiff < 0) {
|
|
507
|
+
return { action: "back" };
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Forward navigation
|
|
511
|
+
if (indexDiff > 0 && lengthDiff === 0) {
|
|
512
|
+
// Check if the entry at current index is the same as before
|
|
513
|
+
const entryReplaced = this.hasHistoryReplacementAtIndex(this.previousEntries, entries, currentIndex);
|
|
514
|
+
|
|
515
|
+
if (entryReplaced) {
|
|
516
|
+
return { action: "navigate" }; // New navigation that replaced forward history
|
|
517
|
+
} else {
|
|
518
|
+
return { action: "forward" }; // True forward navigation
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// New navigation (history grew)
|
|
523
|
+
if (lengthDiff > 0) {
|
|
524
|
+
return { action: "navigate" };
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Same position, same length
|
|
528
|
+
if (lengthDiff <= 0) {
|
|
529
|
+
const entryReplaced = this.hasHistoryReplacementAtIndex(this.previousEntries, entries, currentIndex);
|
|
530
|
+
|
|
531
|
+
return entryReplaced ? { action: "navigate" } : { action: "reload" };
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return { action: "unknown" };
|
|
535
|
+
}
|
|
536
|
+
|
|
465
537
|
async getCurrentTransition() {
|
|
466
538
|
if (this?.web?.browser?._name !== "chromium") {
|
|
467
539
|
return;
|
|
@@ -470,29 +542,70 @@ export class BVTRecorder {
|
|
|
470
542
|
|
|
471
543
|
try {
|
|
472
544
|
const result = await client.send("Page.getNavigationHistory");
|
|
473
|
-
// console.log("
|
|
545
|
+
// console.log("Navigation History:", result);
|
|
474
546
|
const entries = result.entries;
|
|
475
547
|
const currentIndex = result.currentIndex;
|
|
476
548
|
|
|
477
549
|
// ignore if currentIndex is not the last entry
|
|
478
|
-
if (currentIndex !== entries.length - 1) return;
|
|
550
|
+
// if (currentIndex !== entries.length - 1) return;
|
|
479
551
|
|
|
480
552
|
const currentEntry = entries[currentIndex];
|
|
481
|
-
|
|
553
|
+
const transitionInfo = this.analyzeTransitionType(entries, currentIndex, currentEntry);
|
|
554
|
+
this.previousIndex = currentIndex;
|
|
555
|
+
this.previousHistoryLength = entries.length;
|
|
556
|
+
this.previousUrl = currentEntry.url;
|
|
557
|
+
this.previousEntries = [...entries]; // Store a copy of current entries
|
|
558
|
+
|
|
559
|
+
return {
|
|
560
|
+
currentEntry,
|
|
561
|
+
navigationAction: transitionInfo.action,
|
|
562
|
+
};
|
|
482
563
|
} catch (error) {
|
|
483
|
-
console.error("Error in getTransistionType event");
|
|
564
|
+
console.error("Error in getTransistionType event", error);
|
|
484
565
|
} finally {
|
|
485
566
|
await client.detach();
|
|
486
567
|
}
|
|
487
568
|
}
|
|
488
|
-
|
|
569
|
+
userInitiatedTransitionTypes = ["typed", "address_bar"];
|
|
489
570
|
async handlePageTransition() {
|
|
490
571
|
const transition = await this.getCurrentTransition();
|
|
491
572
|
if (!transition) return;
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
573
|
+
|
|
574
|
+
const { currentEntry, navigationAction } = transition;
|
|
575
|
+
|
|
576
|
+
switch (navigationAction) {
|
|
577
|
+
case "initial":
|
|
578
|
+
// console.log("Initial navigation, no action taken");
|
|
579
|
+
return;
|
|
580
|
+
case "navigate":
|
|
581
|
+
// console.log("transitionType", transition.transitionType);
|
|
582
|
+
// console.log("sending onGoto event", { url: currentEntry.url,
|
|
583
|
+
// type: "navigate", });
|
|
584
|
+
if (this.userInitiatedTransitionTypes.includes(currentEntry.transitionType)) {
|
|
585
|
+
const env = JSON.parse(readFileSync(this.envName), "utf8");
|
|
586
|
+
const baseUrl = env.baseUrl;
|
|
587
|
+
let url = currentEntry.userTypedURL;
|
|
588
|
+
if (baseUrl && url.startsWith(baseUrl)) {
|
|
589
|
+
url = url.replace(baseUrl, "{{env.baseUrl}}");
|
|
590
|
+
}
|
|
591
|
+
// console.log("User initiated transition");
|
|
592
|
+
this.sendEvent(this.events.onGoto, { url, type: "navigate" });
|
|
593
|
+
}
|
|
594
|
+
return;
|
|
595
|
+
case "back":
|
|
596
|
+
// console.log("User navigated back");
|
|
597
|
+
// console.log("sending onGoto event", {
|
|
598
|
+
// type: "back",
|
|
599
|
+
// });
|
|
600
|
+
this.sendEvent(this.events.onGoto, { type: "back" });
|
|
601
|
+
return;
|
|
602
|
+
case "forward":
|
|
603
|
+
// console.log("User navigated forward"); console.log("sending onGoto event", { type: "forward", });
|
|
604
|
+
this.sendEvent(this.events.onGoto, { type: "forward" });
|
|
605
|
+
return;
|
|
606
|
+
default:
|
|
607
|
+
this.sendEvent(this.events.onGoto, { type: "unknown" });
|
|
608
|
+
return;
|
|
496
609
|
}
|
|
497
610
|
}
|
|
498
611
|
|
|
@@ -619,10 +732,13 @@ export class BVTRecorder {
|
|
|
619
732
|
}
|
|
620
733
|
async closeBrowser() {
|
|
621
734
|
delete process.env.TEMP_RUN;
|
|
622
|
-
await this.watcher.close().then(() => {
|
|
623
|
-
this.logger.info(`Closed current testData file`);
|
|
624
|
-
});
|
|
735
|
+
await this.watcher.close().then(() => { });
|
|
625
736
|
this.watcher = null;
|
|
737
|
+
this.previousIndex = null;
|
|
738
|
+
this.previousHistoryLength = null;
|
|
739
|
+
this.previousUrl = null;
|
|
740
|
+
this.previousEntries = null;
|
|
741
|
+
|
|
626
742
|
await closeContext();
|
|
627
743
|
this.pageSet.clear();
|
|
628
744
|
}
|
|
@@ -705,34 +821,49 @@ export class BVTRecorder {
|
|
|
705
821
|
}, 100);
|
|
706
822
|
this.timerId = timerId;
|
|
707
823
|
}
|
|
708
|
-
async runStep({ step, parametersMap }, options) {
|
|
824
|
+
async runStep({ step, parametersMap, tags, isFirstStep, listenNetwork }, options) {
|
|
825
|
+
const {
|
|
826
|
+
skipAfter = true,
|
|
827
|
+
skipBefore = !isFirstStep,
|
|
828
|
+
} = options || {};
|
|
709
829
|
const _env = {
|
|
710
830
|
TOKEN: this.TOKEN,
|
|
711
831
|
TEMP_RUN: true,
|
|
712
832
|
REPORT_FOLDER: this.bvtContext.reportFolder,
|
|
713
833
|
BLINQ_ENV: this.envName,
|
|
834
|
+
STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
|
|
835
|
+
CURRENT_STEP_ID: step.id,
|
|
714
836
|
};
|
|
715
837
|
|
|
716
838
|
this.bvtContext.navigate = true;
|
|
839
|
+
this.bvtContext.loadedRoutes = null;
|
|
717
840
|
for (const [key, value] of Object.entries(_env)) {
|
|
718
841
|
process.env[key] = value;
|
|
719
842
|
}
|
|
843
|
+
|
|
720
844
|
if (this.timerId) {
|
|
721
845
|
clearTimeout(this.timerId);
|
|
722
846
|
this.timerId = null;
|
|
723
847
|
}
|
|
724
848
|
await this.setMode("running");
|
|
849
|
+
|
|
725
850
|
try {
|
|
726
|
-
await this.stepRunner.runStep(
|
|
851
|
+
const { result, info } = await this.stepRunner.runStep(
|
|
727
852
|
{
|
|
728
853
|
step,
|
|
729
854
|
parametersMap,
|
|
730
855
|
envPath: this.envName,
|
|
856
|
+
tags,
|
|
857
|
+
config: this.config,
|
|
731
858
|
},
|
|
732
859
|
this.bvtContext,
|
|
733
|
-
|
|
860
|
+
{
|
|
861
|
+
skipAfter,
|
|
862
|
+
skipBefore,
|
|
863
|
+
}
|
|
734
864
|
);
|
|
735
865
|
await this.revertMode();
|
|
866
|
+
return { info };
|
|
736
867
|
} catch (error) {
|
|
737
868
|
await this.revertMode();
|
|
738
869
|
throw error;
|
|
@@ -743,19 +874,42 @@ export class BVTRecorder {
|
|
|
743
874
|
this.bvtContext.navigate = false;
|
|
744
875
|
}
|
|
745
876
|
}
|
|
746
|
-
async runScenario({ steps, parametersMap }) {
|
|
747
|
-
for (const step of steps) {
|
|
748
|
-
await this.runStep({ step, parametersMap });
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
877
|
async saveScenario({ scenario, featureName, override, isSingleStep }) {
|
|
752
878
|
await updateStepDefinitions({ scenario, featureName, projectDir: this.projectDir }); // updates mjs files
|
|
753
879
|
if (!isSingleStep) await updateFeatureFile({ featureName, scenario, override, projectDir: this.projectDir }); // updates gherkin files
|
|
754
|
-
await this.cleanup();
|
|
880
|
+
await this.cleanup({ tags: scenario.tags });
|
|
755
881
|
}
|
|
756
882
|
async getImplementedSteps() {
|
|
757
|
-
|
|
883
|
+
const stepsAndScenarios = await getImplementedSteps(this.projectDir);
|
|
884
|
+
const implementedSteps = stepsAndScenarios.implementedSteps;
|
|
885
|
+
const scenarios = stepsAndScenarios.scenarios;
|
|
886
|
+
for (const scenario of scenarios) {
|
|
887
|
+
this.scenariosStepsMap.set(scenario.name, scenario.steps);
|
|
888
|
+
delete scenario.steps;
|
|
889
|
+
}
|
|
890
|
+
return {
|
|
891
|
+
implementedSteps,
|
|
892
|
+
scenarios,
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
async getStepsAndCommandsForScenario({ name, featureName }) {
|
|
896
|
+
const steps = this.scenariosStepsMap.get(name) || [];
|
|
897
|
+
for (const step of steps) {
|
|
898
|
+
if (step.isImplemented) {
|
|
899
|
+
step.commands = this.getCommandsForImplementedStep({ stepName: step.text });
|
|
900
|
+
} else {
|
|
901
|
+
step.commands = [];
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return steps;
|
|
905
|
+
// return getStepsAndCommandsForScenario({
|
|
906
|
+
// name,
|
|
907
|
+
// featureName,
|
|
908
|
+
// projectDir: this.projectDir,
|
|
909
|
+
// map: this.scenariosStepsMap,
|
|
910
|
+
// });
|
|
758
911
|
}
|
|
912
|
+
|
|
759
913
|
async generateStepName({ commands, stepsNames, parameters, map }) {
|
|
760
914
|
return await this.namesService.generateStepName({ commands, stepsNames, parameters, map });
|
|
761
915
|
}
|
|
@@ -838,9 +992,9 @@ export class BVTRecorder {
|
|
|
838
992
|
}
|
|
839
993
|
}
|
|
840
994
|
|
|
841
|
-
async discardTestData() {
|
|
995
|
+
async discardTestData({ tags }) {
|
|
842
996
|
resetTestData(this.envName, this.world);
|
|
843
|
-
await this.cleanup();
|
|
997
|
+
await this.cleanup({ tags });
|
|
844
998
|
}
|
|
845
999
|
async addToTestData(obj) {
|
|
846
1000
|
if (!existsSync(_getDataFile(this.world, this.bvtContext, this.web))) {
|
|
@@ -879,6 +1033,7 @@ export class BVTRecorder {
|
|
|
879
1033
|
const stepParams = parseStepTextParameters(stepName);
|
|
880
1034
|
return getCommandsForImplementedStep(stepName, step_definitions, stepParams).commands;
|
|
881
1035
|
}
|
|
1036
|
+
|
|
882
1037
|
loadExistingScenario({ featureName, scenarioName }) {
|
|
883
1038
|
const step_definitions = loadStepDefinitions(this.projectDir);
|
|
884
1039
|
const featureFilePath = path.join(this.projectDir, "features", featureName);
|
|
@@ -907,6 +1062,7 @@ export class BVTRecorder {
|
|
|
907
1062
|
..._s,
|
|
908
1063
|
keyword: step.keyword.trim(),
|
|
909
1064
|
};
|
|
1065
|
+
parseRouteFiles(this.projectDir, _step);
|
|
910
1066
|
steps.push(_step);
|
|
911
1067
|
}
|
|
912
1068
|
return {
|
|
@@ -946,7 +1102,7 @@ export class BVTRecorder {
|
|
|
946
1102
|
}
|
|
947
1103
|
return result;
|
|
948
1104
|
}
|
|
949
|
-
async cleanup() {
|
|
1105
|
+
async cleanup({ tags }) {
|
|
950
1106
|
const noopStep = {
|
|
951
1107
|
text: "Noop",
|
|
952
1108
|
isImplemented: true,
|
|
@@ -960,6 +1116,7 @@ export class BVTRecorder {
|
|
|
960
1116
|
{
|
|
961
1117
|
step: noopStep,
|
|
962
1118
|
parametersMap: {},
|
|
1119
|
+
tags: tags || [],
|
|
963
1120
|
},
|
|
964
1121
|
{
|
|
965
1122
|
skipAfter: false,
|
|
@@ -998,6 +1155,47 @@ export class BVTRecorder {
|
|
|
998
1155
|
return false;
|
|
999
1156
|
}
|
|
1000
1157
|
}
|
|
1158
|
+
async initExecution({ tags = [] }) {
|
|
1159
|
+
// run before hooks
|
|
1160
|
+
const noopStep = {
|
|
1161
|
+
text: "Noop",
|
|
1162
|
+
isImplemented: true,
|
|
1163
|
+
};
|
|
1164
|
+
await this.runStep(
|
|
1165
|
+
{
|
|
1166
|
+
step: noopStep,
|
|
1167
|
+
parametersMap: {},
|
|
1168
|
+
tags,
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
skipBefore: false,
|
|
1172
|
+
skipAfter: true,
|
|
1173
|
+
}
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1176
|
+
async cleanupExecution({ tags = [] }) {
|
|
1177
|
+
// run after hooks
|
|
1178
|
+
const noopStep = {
|
|
1179
|
+
text: "Noop",
|
|
1180
|
+
isImplemented: true,
|
|
1181
|
+
};
|
|
1182
|
+
await this.runStep(
|
|
1183
|
+
{
|
|
1184
|
+
step: noopStep,
|
|
1185
|
+
parametersMap: {},
|
|
1186
|
+
tags,
|
|
1187
|
+
},
|
|
1188
|
+
{
|
|
1189
|
+
skipBefore: true,
|
|
1190
|
+
skipAfter: false,
|
|
1191
|
+
}
|
|
1192
|
+
);
|
|
1193
|
+
}
|
|
1194
|
+
async resetExecution({ tags = [] }) {
|
|
1195
|
+
// run after hooks followed by before hooks
|
|
1196
|
+
await this.cleanupExecution({ tags });
|
|
1197
|
+
await this.initExecution({ tags });
|
|
1198
|
+
}
|
|
1001
1199
|
}
|
|
1002
1200
|
|
|
1003
1201
|
const parseFeatureFile = (featureFilePath) => {
|
|
@@ -34,6 +34,7 @@ let recorder = null;
|
|
|
34
34
|
const init = async ({ envName, projectDir, roomId }) => {
|
|
35
35
|
console.log("connecting to " + WS_URL);
|
|
36
36
|
const socket = io(WS_URL);
|
|
37
|
+
// Disconnect from the server when the process exits
|
|
37
38
|
socket.on("connect", () => {
|
|
38
39
|
// console.log('connected to server')
|
|
39
40
|
});
|