@dev-blinq/cucumber_client 1.0.1193-dev → 1.0.1193-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/find_context.js +1 -1
- package/bin/assets/preload/locators.js +18 -0
- package/bin/assets/preload/recorderv3.js +77 -6
- 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 +841 -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 +59 -7
- package/bin/client/cli_helpers.js +11 -13
- package/bin/client/code_cleanup/utils.js +42 -14
- package/bin/client/code_gen/code_inversion.js +51 -14
- 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 +153 -25
- package/bin/client/cucumber/feature.js +103 -28
- package/bin/client/cucumber/project_to_document.js +8 -7
- package/bin/client/cucumber/steps_definitions.js +118 -85
- package/bin/client/local_agent.js +6 -2
- package/bin/client/operations/dump_tree.js +157 -2
- package/bin/client/project.js +6 -2
- package/bin/client/recorderv3/bvt_recorder.js +273 -80
- package/bin/client/recorderv3/cli.js +1 -0
- package/bin/client/recorderv3/implemented_steps.js +70 -15
- package/bin/client/recorderv3/index.js +49 -7
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/step_runner.js +183 -13
- package/bin/client/recorderv3/step_utils.js +163 -14
- package/bin/client/recorderv3/update_feature.js +58 -30
- package/bin/client/recording.js +8 -0
- package/bin/client/run_cucumber.js +16 -2
- package/bin/client/scenario_report.js +35 -8
- package/bin/client/test_scenario.js +0 -1
- package/bin/index.js +1 -0
- package/package.json +15 -8
|
@@ -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, getStepsAndCommandsForScenario } 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,21 @@ 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 { Step } from "../cucumber/feature.js";
|
|
19
|
+
|
|
19
20
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
20
|
-
|
|
21
|
+
|
|
21
22
|
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
|
|
23
|
+
export function getInitScript(config, options) {
|
|
24
|
+
const preScript = `
|
|
25
|
+
window.__bvt_Recorder_config = ${JSON.stringify(config ?? null)};
|
|
26
|
+
window.__PW_options = ${JSON.stringify(options ?? null)};
|
|
27
|
+
`;
|
|
28
|
+
const recorderScript = readFileSync(
|
|
29
|
+
path.join(__dirname, "..", "..", "assets", "bundled_scripts", "recorder.js"),
|
|
30
|
+
"utf8"
|
|
53
31
|
);
|
|
32
|
+
return preScript + recorderScript;
|
|
54
33
|
}
|
|
55
34
|
|
|
56
35
|
async function evaluate(frame, script) {
|
|
@@ -71,7 +50,7 @@ async function findNestedFrameSelector(frame, obj) {
|
|
|
71
50
|
const frameElement = await frame.frameElement();
|
|
72
51
|
if (!frameElement) return;
|
|
73
52
|
const selectors = await parent.evaluate((element) => {
|
|
74
|
-
return window.
|
|
53
|
+
return window.__bvt_Recorder.locatorGenerator.getElementLocators(element, { excludeText: true }).locators;
|
|
75
54
|
}, frameElement);
|
|
76
55
|
return findNestedFrameSelector(parent, { children: obj, selectors });
|
|
77
56
|
} catch (e) {
|
|
@@ -198,6 +177,7 @@ export class BVTRecorder {
|
|
|
198
177
|
this.logger = logger;
|
|
199
178
|
this.screenshotMap = new Map();
|
|
200
179
|
this.snapshotMap = new Map();
|
|
180
|
+
this.scenariosStepsMap = new Map();
|
|
201
181
|
this.namesService = new NamesService({
|
|
202
182
|
screenshotMap: this.screenshotMap,
|
|
203
183
|
TOKEN: this.TOKEN,
|
|
@@ -206,15 +186,38 @@ export class BVTRecorder {
|
|
|
206
186
|
});
|
|
207
187
|
this.stepRunner = new BVTStepRunner({
|
|
208
188
|
projectDir: this.projectDir,
|
|
189
|
+
sendExecutionStatus: (data) => {
|
|
190
|
+
if (data && data.type) {
|
|
191
|
+
switch (data.type) {
|
|
192
|
+
case "cmdExecutionStart":
|
|
193
|
+
console.log("Sending cmdExecutionStart event for cmdId:", data);
|
|
194
|
+
this.sendEvent(this.events.cmdExecutionStart, data);
|
|
195
|
+
break;
|
|
196
|
+
case "cmdExecutionSuccess":
|
|
197
|
+
console.log("Sending cmdExecutionSuccess event for cmdId:", data);
|
|
198
|
+
this.sendEvent(this.events.cmdExecutionSuccess, data);
|
|
199
|
+
break;
|
|
200
|
+
case "cmdExecutionError":
|
|
201
|
+
console.log("Sending cmdExecutionError event for cmdId:", data);
|
|
202
|
+
this.sendEvent(this.events.cmdExecutionError, data);
|
|
203
|
+
break;
|
|
204
|
+
case "interceptResults":
|
|
205
|
+
console.log("Sending interceptResults event");
|
|
206
|
+
this.sendEvent(this.events.interceptResults, data);
|
|
207
|
+
break;
|
|
208
|
+
default:
|
|
209
|
+
console.warn("Unknown command execution status type:", data.type);
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
},
|
|
209
214
|
});
|
|
210
215
|
this.pageSet = new Set();
|
|
211
|
-
|
|
212
216
|
this.lastKnownUrlPath = "";
|
|
213
217
|
// TODO: what is world?
|
|
214
218
|
this.world = { attach: () => {} };
|
|
215
219
|
this.shouldTakeScreenshot = true;
|
|
216
220
|
this.watcher = null;
|
|
217
|
-
this.sendEvent("BVTRecorder.getTestData", {});
|
|
218
221
|
}
|
|
219
222
|
events = {
|
|
220
223
|
onFrameNavigate: "BVTRecorder.onFrameNavigate",
|
|
@@ -225,6 +228,10 @@ export class BVTRecorder {
|
|
|
225
228
|
onStepDetails: "BVTRecorder.onStepDetails",
|
|
226
229
|
getTestData: "BVTRecorder.getTestData",
|
|
227
230
|
onGoto: "BVTRecorder.onGoto",
|
|
231
|
+
cmdExecutionStart: "BVTRecorder.cmdExecutionStart",
|
|
232
|
+
cmdExecutionSuccess: "BVTRecorder.cmdExecutionSuccess",
|
|
233
|
+
cmdExecutionError: "BVTRecorder.cmdExecutionError",
|
|
234
|
+
interceptResults: "BVTRecorder.interceptResults",
|
|
228
235
|
};
|
|
229
236
|
bindings = {
|
|
230
237
|
__bvt_recordCommand: async ({ frame, page, context }, event) => {
|
|
@@ -300,22 +307,15 @@ export class BVTRecorder {
|
|
|
300
307
|
return result;
|
|
301
308
|
}
|
|
302
309
|
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;
|
|
310
|
+
return getInitScript(config, {
|
|
311
|
+
sdkLanguage: "javascript",
|
|
312
|
+
testIdAttributeName: "blinq-test-id",
|
|
313
|
+
stableRafCount: 0,
|
|
314
|
+
browserName: this.browser?.browserType().name(),
|
|
315
|
+
inputFileRoleTextbox: false,
|
|
316
|
+
customEngines: [],
|
|
317
|
+
isUnderTest: true,
|
|
318
|
+
});
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
async _initBrowser({ url }) {
|
|
@@ -334,8 +334,9 @@ export class BVTRecorder {
|
|
|
334
334
|
console.error("Error reading ai_config.json", error);
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
|
+
this.config = ai_config;
|
|
337
338
|
const initScripts = {
|
|
338
|
-
recorderCjs: injectedScriptSource,
|
|
339
|
+
// recorderCjs: injectedScriptSource,
|
|
339
340
|
scripts: [
|
|
340
341
|
this.getInitScripts(ai_config),
|
|
341
342
|
`\ndelete Object.getPrototypeOf(navigator).webdriver;${process.env.WINDOW_DEBUGGER ? "window.debug=true;\n" : ""}`,
|
|
@@ -462,6 +463,75 @@ export class BVTRecorder {
|
|
|
462
463
|
}
|
|
463
464
|
});
|
|
464
465
|
}
|
|
466
|
+
|
|
467
|
+
hasHistoryReplacementAtIndex(previousEntries, currentEntries, index) {
|
|
468
|
+
if (!previousEntries || !currentEntries) return false;
|
|
469
|
+
if (index >= previousEntries.length || index >= currentEntries.length) return false;
|
|
470
|
+
|
|
471
|
+
const prevEntry = previousEntries[index];
|
|
472
|
+
// console.log("prevEntry", prevEntry);
|
|
473
|
+
const currEntry = currentEntries[index];
|
|
474
|
+
// console.log("currEntry", currEntry);
|
|
475
|
+
|
|
476
|
+
// Check if the entry at this index has been replaced
|
|
477
|
+
return prevEntry.id !== currEntry.id;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Even simpler approach for your specific case
|
|
481
|
+
analyzeTransitionType(entries, currentIndex, currentEntry) {
|
|
482
|
+
// console.log("Analyzing transition type");
|
|
483
|
+
// console.log("===========================");
|
|
484
|
+
// console.log("Current Index:", currentIndex);
|
|
485
|
+
// console.log("Current Entry:", currentEntry);
|
|
486
|
+
// console.log("Current Entries:", entries);
|
|
487
|
+
// console.log("Current entries length:", entries.length);
|
|
488
|
+
// console.log("===========================");
|
|
489
|
+
// console.log("Previous Index:", this.previousIndex);
|
|
490
|
+
// // console.log("Previous Entry:", this.previousEntries[this.previousIndex]);
|
|
491
|
+
// console.log("Previous Entries:", this.previousEntries);
|
|
492
|
+
// console.log("Previous entries length:", this.previousHistoryLength);
|
|
493
|
+
|
|
494
|
+
if (this.previousIndex === null || this.previousHistoryLength === null || !this.previousEntries) {
|
|
495
|
+
return {
|
|
496
|
+
action: "initial",
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const indexDiff = currentIndex - this.previousIndex;
|
|
501
|
+
const lengthDiff = entries.length - this.previousHistoryLength;
|
|
502
|
+
|
|
503
|
+
// Backward navigation
|
|
504
|
+
if (indexDiff < 0) {
|
|
505
|
+
return { action: "back" };
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Forward navigation
|
|
509
|
+
if (indexDiff > 0 && lengthDiff === 0) {
|
|
510
|
+
// Check if the entry at current index is the same as before
|
|
511
|
+
const entryReplaced = this.hasHistoryReplacementAtIndex(this.previousEntries, entries, currentIndex);
|
|
512
|
+
|
|
513
|
+
if (entryReplaced) {
|
|
514
|
+
return { action: "navigate" }; // New navigation that replaced forward history
|
|
515
|
+
} else {
|
|
516
|
+
return { action: "forward" }; // True forward navigation
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// New navigation (history grew)
|
|
521
|
+
if (lengthDiff > 0) {
|
|
522
|
+
return { action: "navigate" };
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Same position, same length
|
|
526
|
+
if (lengthDiff <= 0) {
|
|
527
|
+
const entryReplaced = this.hasHistoryReplacementAtIndex(this.previousEntries, entries, currentIndex);
|
|
528
|
+
|
|
529
|
+
return entryReplaced ? { action: "navigate" } : { action: "reload" };
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return { action: "unknown" };
|
|
533
|
+
}
|
|
534
|
+
|
|
465
535
|
async getCurrentTransition() {
|
|
466
536
|
if (this?.web?.browser?._name !== "chromium") {
|
|
467
537
|
return;
|
|
@@ -470,29 +540,70 @@ export class BVTRecorder {
|
|
|
470
540
|
|
|
471
541
|
try {
|
|
472
542
|
const result = await client.send("Page.getNavigationHistory");
|
|
473
|
-
// console.log("
|
|
543
|
+
// console.log("Navigation History:", result);
|
|
474
544
|
const entries = result.entries;
|
|
475
545
|
const currentIndex = result.currentIndex;
|
|
476
546
|
|
|
477
547
|
// ignore if currentIndex is not the last entry
|
|
478
|
-
if (currentIndex !== entries.length - 1) return;
|
|
548
|
+
// if (currentIndex !== entries.length - 1) return;
|
|
479
549
|
|
|
480
550
|
const currentEntry = entries[currentIndex];
|
|
481
|
-
|
|
551
|
+
const transitionInfo = this.analyzeTransitionType(entries, currentIndex, currentEntry);
|
|
552
|
+
this.previousIndex = currentIndex;
|
|
553
|
+
this.previousHistoryLength = entries.length;
|
|
554
|
+
this.previousUrl = currentEntry.url;
|
|
555
|
+
this.previousEntries = [...entries]; // Store a copy of current entries
|
|
556
|
+
|
|
557
|
+
return {
|
|
558
|
+
currentEntry,
|
|
559
|
+
navigationAction: transitionInfo.action,
|
|
560
|
+
};
|
|
482
561
|
} catch (error) {
|
|
483
|
-
console.error("Error in getTransistionType event");
|
|
562
|
+
console.error("Error in getTransistionType event", error);
|
|
484
563
|
} finally {
|
|
485
564
|
await client.detach();
|
|
486
565
|
}
|
|
487
566
|
}
|
|
488
|
-
|
|
567
|
+
userInitiatedTransitionTypes = ["typed", "address_bar"];
|
|
489
568
|
async handlePageTransition() {
|
|
490
569
|
const transition = await this.getCurrentTransition();
|
|
491
570
|
if (!transition) return;
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
571
|
+
|
|
572
|
+
const { currentEntry, navigationAction } = transition;
|
|
573
|
+
|
|
574
|
+
switch (navigationAction) {
|
|
575
|
+
case "initial":
|
|
576
|
+
// console.log("Initial navigation, no action taken");
|
|
577
|
+
return;
|
|
578
|
+
case "navigate":
|
|
579
|
+
// console.log("transitionType", transition.transitionType);
|
|
580
|
+
// console.log("sending onGoto event", { url: currentEntry.url,
|
|
581
|
+
// type: "navigate", });
|
|
582
|
+
if (this.userInitiatedTransitionTypes.includes(currentEntry.transitionType)) {
|
|
583
|
+
const env = JSON.parse(readFileSync(this.envName), "utf8");
|
|
584
|
+
const baseUrl = env.baseUrl;
|
|
585
|
+
let url = currentEntry.userTypedURL;
|
|
586
|
+
if (baseUrl && url.startsWith(baseUrl)) {
|
|
587
|
+
url = url.replace(baseUrl, "{{env.baseUrl}}");
|
|
588
|
+
}
|
|
589
|
+
// console.log("User initiated transition");
|
|
590
|
+
this.sendEvent(this.events.onGoto, { url, type: "navigate" });
|
|
591
|
+
}
|
|
592
|
+
return;
|
|
593
|
+
case "back":
|
|
594
|
+
// console.log("User navigated back");
|
|
595
|
+
// console.log("sending onGoto event", {
|
|
596
|
+
// type: "back",
|
|
597
|
+
// });
|
|
598
|
+
this.sendEvent(this.events.onGoto, { type: "back" });
|
|
599
|
+
return;
|
|
600
|
+
case "forward":
|
|
601
|
+
// console.log("User navigated forward"); console.log("sending onGoto event", { type: "forward", });
|
|
602
|
+
this.sendEvent(this.events.onGoto, { type: "forward" });
|
|
603
|
+
return;
|
|
604
|
+
default:
|
|
605
|
+
this.sendEvent(this.events.onGoto, { type: "unknown" });
|
|
606
|
+
return;
|
|
496
607
|
}
|
|
497
608
|
}
|
|
498
609
|
|
|
@@ -619,10 +730,13 @@ export class BVTRecorder {
|
|
|
619
730
|
}
|
|
620
731
|
async closeBrowser() {
|
|
621
732
|
delete process.env.TEMP_RUN;
|
|
622
|
-
await this.watcher.close().then(() => {
|
|
623
|
-
this.logger.info(`Closed current testData file`);
|
|
624
|
-
});
|
|
733
|
+
await this.watcher.close().then(() => {});
|
|
625
734
|
this.watcher = null;
|
|
735
|
+
this.previousIndex = null;
|
|
736
|
+
this.previousHistoryLength = null;
|
|
737
|
+
this.previousUrl = null;
|
|
738
|
+
this.previousEntries = null;
|
|
739
|
+
|
|
626
740
|
await closeContext();
|
|
627
741
|
this.pageSet.clear();
|
|
628
742
|
}
|
|
@@ -674,6 +788,7 @@ export class BVTRecorder {
|
|
|
674
788
|
}
|
|
675
789
|
|
|
676
790
|
async startRecordingInput() {
|
|
791
|
+
console.log("startRecordingInput");
|
|
677
792
|
await this.setMode("recordingInput");
|
|
678
793
|
}
|
|
679
794
|
async stopRecordingInput() {
|
|
@@ -697,6 +812,7 @@ export class BVTRecorder {
|
|
|
697
812
|
}
|
|
698
813
|
|
|
699
814
|
async abortExecution() {
|
|
815
|
+
this.bvtContext.web.abortedExecution = true;
|
|
700
816
|
await this.stepRunner.abortExecution();
|
|
701
817
|
}
|
|
702
818
|
async dealyedRevertMode() {
|
|
@@ -705,34 +821,47 @@ 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 { skipAfter = true, skipBefore = !isFirstStep } = options || {};
|
|
709
826
|
const _env = {
|
|
710
827
|
TOKEN: this.TOKEN,
|
|
711
828
|
TEMP_RUN: true,
|
|
712
829
|
REPORT_FOLDER: this.bvtContext.reportFolder,
|
|
713
830
|
BLINQ_ENV: this.envName,
|
|
831
|
+
STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
|
|
832
|
+
CURRENT_STEP_ID: step.id,
|
|
714
833
|
};
|
|
715
834
|
|
|
716
835
|
this.bvtContext.navigate = true;
|
|
836
|
+
this.bvtContext.loadedRoutes = null;
|
|
837
|
+
this.bvtContext.web.abortedExecution = false;
|
|
717
838
|
for (const [key, value] of Object.entries(_env)) {
|
|
718
839
|
process.env[key] = value;
|
|
719
840
|
}
|
|
841
|
+
|
|
720
842
|
if (this.timerId) {
|
|
721
843
|
clearTimeout(this.timerId);
|
|
722
844
|
this.timerId = null;
|
|
723
845
|
}
|
|
724
846
|
await this.setMode("running");
|
|
847
|
+
|
|
725
848
|
try {
|
|
726
|
-
await this.stepRunner.runStep(
|
|
849
|
+
const { result, info } = await this.stepRunner.runStep(
|
|
727
850
|
{
|
|
728
851
|
step,
|
|
729
852
|
parametersMap,
|
|
730
853
|
envPath: this.envName,
|
|
854
|
+
tags,
|
|
855
|
+
config: this.config,
|
|
731
856
|
},
|
|
732
857
|
this.bvtContext,
|
|
733
|
-
|
|
858
|
+
{
|
|
859
|
+
skipAfter,
|
|
860
|
+
skipBefore,
|
|
861
|
+
}
|
|
734
862
|
);
|
|
735
863
|
await this.revertMode();
|
|
864
|
+
return { info };
|
|
736
865
|
} catch (error) {
|
|
737
866
|
await this.revertMode();
|
|
738
867
|
throw error;
|
|
@@ -743,22 +872,42 @@ export class BVTRecorder {
|
|
|
743
872
|
this.bvtContext.navigate = false;
|
|
744
873
|
}
|
|
745
874
|
}
|
|
746
|
-
async runScenario({ steps, parametersMap }) {
|
|
747
|
-
for (const step of steps) {
|
|
748
|
-
await this.runStep({ step, parametersMap });
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
875
|
async saveScenario({ scenario, featureName, override, isSingleStep }) {
|
|
752
876
|
await updateStepDefinitions({ scenario, featureName, projectDir: this.projectDir }); // updates mjs files
|
|
753
877
|
if (!isSingleStep) await updateFeatureFile({ featureName, scenario, override, projectDir: this.projectDir }); // updates gherkin files
|
|
754
|
-
await this.cleanup();
|
|
878
|
+
await this.cleanup({ tags: scenario.tags });
|
|
755
879
|
}
|
|
756
880
|
async getImplementedSteps() {
|
|
757
|
-
|
|
881
|
+
const stepsAndScenarios = await getImplementedSteps(this.projectDir);
|
|
882
|
+
const implementedSteps = stepsAndScenarios.implementedSteps;
|
|
883
|
+
const scenarios = stepsAndScenarios.scenarios;
|
|
884
|
+
for (const scenario of scenarios) {
|
|
885
|
+
this.scenariosStepsMap.set(scenario.name, scenario.steps);
|
|
886
|
+
delete scenario.steps;
|
|
887
|
+
}
|
|
888
|
+
return {
|
|
889
|
+
implementedSteps,
|
|
890
|
+
scenarios,
|
|
891
|
+
};
|
|
758
892
|
}
|
|
759
893
|
async getStepsAndCommandsForScenario({ name, featureName }) {
|
|
760
|
-
|
|
894
|
+
const steps = this.scenariosStepsMap.get(name) || [];
|
|
895
|
+
for (const step of steps) {
|
|
896
|
+
if (step.isImplemented) {
|
|
897
|
+
step.commands = this.getCommandsForImplementedStep({ stepName: step.text });
|
|
898
|
+
} else {
|
|
899
|
+
step.commands = [];
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
return steps;
|
|
903
|
+
// return getStepsAndCommandsForScenario({
|
|
904
|
+
// name,
|
|
905
|
+
// featureName,
|
|
906
|
+
// projectDir: this.projectDir,
|
|
907
|
+
// map: this.scenariosStepsMap,
|
|
908
|
+
// });
|
|
761
909
|
}
|
|
910
|
+
|
|
762
911
|
async generateStepName({ commands, stepsNames, parameters, map }) {
|
|
763
912
|
return await this.namesService.generateStepName({ commands, stepsNames, parameters, map });
|
|
764
913
|
}
|
|
@@ -841,9 +990,9 @@ export class BVTRecorder {
|
|
|
841
990
|
}
|
|
842
991
|
}
|
|
843
992
|
|
|
844
|
-
async discardTestData() {
|
|
993
|
+
async discardTestData({ tags }) {
|
|
845
994
|
resetTestData(this.envName, this.world);
|
|
846
|
-
await this.cleanup();
|
|
995
|
+
await this.cleanup({ tags });
|
|
847
996
|
}
|
|
848
997
|
async addToTestData(obj) {
|
|
849
998
|
if (!existsSync(_getDataFile(this.world, this.bvtContext, this.web))) {
|
|
@@ -882,6 +1031,7 @@ export class BVTRecorder {
|
|
|
882
1031
|
const stepParams = parseStepTextParameters(stepName);
|
|
883
1032
|
return getCommandsForImplementedStep(stepName, step_definitions, stepParams).commands;
|
|
884
1033
|
}
|
|
1034
|
+
|
|
885
1035
|
loadExistingScenario({ featureName, scenarioName }) {
|
|
886
1036
|
const step_definitions = loadStepDefinitions(this.projectDir);
|
|
887
1037
|
const featureFilePath = path.join(this.projectDir, "features", featureName);
|
|
@@ -910,6 +1060,7 @@ export class BVTRecorder {
|
|
|
910
1060
|
..._s,
|
|
911
1061
|
keyword: step.keyword.trim(),
|
|
912
1062
|
};
|
|
1063
|
+
parseRouteFiles(this.projectDir, _step);
|
|
913
1064
|
steps.push(_step);
|
|
914
1065
|
}
|
|
915
1066
|
return {
|
|
@@ -949,7 +1100,7 @@ export class BVTRecorder {
|
|
|
949
1100
|
}
|
|
950
1101
|
return result;
|
|
951
1102
|
}
|
|
952
|
-
async cleanup() {
|
|
1103
|
+
async cleanup({ tags }) {
|
|
953
1104
|
const noopStep = {
|
|
954
1105
|
text: "Noop",
|
|
955
1106
|
isImplemented: true,
|
|
@@ -963,6 +1114,7 @@ export class BVTRecorder {
|
|
|
963
1114
|
{
|
|
964
1115
|
step: noopStep,
|
|
965
1116
|
parametersMap: {},
|
|
1117
|
+
tags: tags || [],
|
|
966
1118
|
},
|
|
967
1119
|
{
|
|
968
1120
|
skipAfter: false,
|
|
@@ -1001,6 +1153,47 @@ export class BVTRecorder {
|
|
|
1001
1153
|
return false;
|
|
1002
1154
|
}
|
|
1003
1155
|
}
|
|
1156
|
+
async initExecution({ tags = [] }) {
|
|
1157
|
+
// run before hooks
|
|
1158
|
+
const noopStep = {
|
|
1159
|
+
text: "Noop",
|
|
1160
|
+
isImplemented: true,
|
|
1161
|
+
};
|
|
1162
|
+
await this.runStep(
|
|
1163
|
+
{
|
|
1164
|
+
step: noopStep,
|
|
1165
|
+
parametersMap: {},
|
|
1166
|
+
tags,
|
|
1167
|
+
},
|
|
1168
|
+
{
|
|
1169
|
+
skipBefore: false,
|
|
1170
|
+
skipAfter: true,
|
|
1171
|
+
}
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
async cleanupExecution({ tags = [] }) {
|
|
1175
|
+
// run after hooks
|
|
1176
|
+
const noopStep = {
|
|
1177
|
+
text: "Noop",
|
|
1178
|
+
isImplemented: true,
|
|
1179
|
+
};
|
|
1180
|
+
await this.runStep(
|
|
1181
|
+
{
|
|
1182
|
+
step: noopStep,
|
|
1183
|
+
parametersMap: {},
|
|
1184
|
+
tags,
|
|
1185
|
+
},
|
|
1186
|
+
{
|
|
1187
|
+
skipBefore: true,
|
|
1188
|
+
skipAfter: false,
|
|
1189
|
+
}
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
async resetExecution({ tags = [] }) {
|
|
1193
|
+
// run after hooks followed by before hooks
|
|
1194
|
+
await this.cleanupExecution({ tags });
|
|
1195
|
+
await this.initExecution({ tags });
|
|
1196
|
+
}
|
|
1004
1197
|
}
|
|
1005
1198
|
|
|
1006
1199
|
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
|
});
|