@dev-blinq/cucumber_client 1.0.1216-dev → 1.0.1216-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/recorderv3.js +74 -4
- 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/_hooks_template.txt +37 -0
- package/bin/assets/templates/page_template.txt +2 -16
- package/bin/assets/templates/utils_template.txt +48 -63
- package/bin/client/apiTest/apiTest.js +6 -0
- 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 +92 -11
- 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 +170 -33
- package/bin/client/cucumber/feature.js +85 -27
- package/bin/client/cucumber/steps_definitions.js +85 -77
- package/bin/client/local_agent.js +7 -3
- package/bin/client/project.js +7 -1
- package/bin/client/recorderv3/bvt_recorder.js +278 -79
- package/bin/client/recorderv3/implemented_steps.js +75 -14
- package/bin/client/recorderv3/index.js +49 -7
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/step_runner.js +181 -12
- package/bin/client/recorderv3/step_utils.js +157 -6
- package/bin/client/recorderv3/update_feature.js +58 -30
- package/bin/client/recording.js +7 -0
- package/bin/client/run_cucumber.js +15 -2
- package/bin/client/scenario_report.js +18 -6
- package/bin/client/test_scenario.js +0 -1
- package/bin/index.js +1 -0
- package/package.json +15 -8
package/bin/client/project.js
CHANGED
|
@@ -82,6 +82,12 @@ class Project {
|
|
|
82
82
|
const utilsContent = readFileSync(utilsPath, "utf8");
|
|
83
83
|
const utilsFileName = this.stepsFolder + "/utils.mjs";
|
|
84
84
|
writeFileSync(utilsFileName, utilsContent, "utf8");
|
|
85
|
+
const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
|
|
86
|
+
if (existsSync(hooksTemplateFilePath)) {
|
|
87
|
+
const hooksFilePath = path.join(this.stepsFolder, "_hooks.mjs");
|
|
88
|
+
const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
|
|
89
|
+
writeFileSync(hooksFilePath, hooksContent, "utf8");
|
|
90
|
+
}
|
|
85
91
|
} catch (e) {
|
|
86
92
|
logger.error("Error loading utils_template");
|
|
87
93
|
}
|
|
@@ -104,7 +110,7 @@ class Project {
|
|
|
104
110
|
this.pages.push(page);
|
|
105
111
|
}
|
|
106
112
|
}
|
|
107
|
-
return
|
|
113
|
+
return this.environment.name;
|
|
108
114
|
}
|
|
109
115
|
getPagesNames() {
|
|
110
116
|
let result = [];
|
|
@@ -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,12 +186,37 @@ 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
|
-
|
|
216
|
+
this.pageMetaDataSet = new Set();
|
|
212
217
|
this.lastKnownUrlPath = "";
|
|
213
218
|
// TODO: what is world?
|
|
214
|
-
this.world = { attach: () => {} };
|
|
219
|
+
this.world = { attach: () => { } };
|
|
215
220
|
this.shouldTakeScreenshot = true;
|
|
216
221
|
this.watcher = null;
|
|
217
222
|
}
|
|
@@ -224,6 +229,10 @@ export class BVTRecorder {
|
|
|
224
229
|
onStepDetails: "BVTRecorder.onStepDetails",
|
|
225
230
|
getTestData: "BVTRecorder.getTestData",
|
|
226
231
|
onGoto: "BVTRecorder.onGoto",
|
|
232
|
+
cmdExecutionStart: "BVTRecorder.cmdExecutionStart",
|
|
233
|
+
cmdExecutionSuccess: "BVTRecorder.cmdExecutionSuccess",
|
|
234
|
+
cmdExecutionError: "BVTRecorder.cmdExecutionError",
|
|
235
|
+
interceptResults: "BVTRecorder.interceptResults",
|
|
227
236
|
};
|
|
228
237
|
bindings = {
|
|
229
238
|
__bvt_recordCommand: async ({ frame, page, context }, event) => {
|
|
@@ -299,22 +308,15 @@ export class BVTRecorder {
|
|
|
299
308
|
return result;
|
|
300
309
|
}
|
|
301
310
|
getInitScripts(config) {
|
|
302
|
-
return getInitScript(config
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
// const inlineScript = `
|
|
312
|
-
// window.__bvt_Recorder.setPopupHandlers(${JSON.stringify(popupHandlers)});
|
|
313
|
-
// window.__bvt_Recorder.setDisableHighlight(${JSON.stringify(disableHighlight)});
|
|
314
|
-
// window.__bvt_Recorder.setImproviseLocators(${JSON.stringify(!disableMultipleLocators)});
|
|
315
|
-
// `
|
|
316
|
-
// scripts.push(inlineScript);
|
|
317
|
-
// return scripts;
|
|
311
|
+
return getInitScript(config, {
|
|
312
|
+
sdkLanguage: "javascript",
|
|
313
|
+
testIdAttributeName: "blinq-test-id",
|
|
314
|
+
stableRafCount: 0,
|
|
315
|
+
browserName: this.browser?.browserType().name(),
|
|
316
|
+
inputFileRoleTextbox: false,
|
|
317
|
+
customEngines: [],
|
|
318
|
+
isUnderTest: true,
|
|
319
|
+
});
|
|
318
320
|
}
|
|
319
321
|
|
|
320
322
|
async _initBrowser({ url }) {
|
|
@@ -322,7 +324,7 @@ export class BVTRecorder {
|
|
|
322
324
|
process.env.CDP_LISTEN_PORT = this.#remoteDebuggerPort;
|
|
323
325
|
|
|
324
326
|
this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
|
|
325
|
-
this.world = { attach: () => {} };
|
|
327
|
+
this.world = { attach: () => { } };
|
|
326
328
|
|
|
327
329
|
const ai_config_file = path.join(this.projectDir, "ai_config.json");
|
|
328
330
|
let ai_config = {};
|
|
@@ -333,8 +335,9 @@ export class BVTRecorder {
|
|
|
333
335
|
console.error("Error reading ai_config.json", error);
|
|
334
336
|
}
|
|
335
337
|
}
|
|
338
|
+
this.config = ai_config;
|
|
336
339
|
const initScripts = {
|
|
337
|
-
recorderCjs: injectedScriptSource,
|
|
340
|
+
// recorderCjs: injectedScriptSource,
|
|
338
341
|
scripts: [
|
|
339
342
|
this.getInitScripts(ai_config),
|
|
340
343
|
`\ndelete Object.getPrototypeOf(navigator).webdriver;${process.env.WINDOW_DEBUGGER ? "window.debug=true;\n" : ""}`,
|
|
@@ -349,6 +352,7 @@ export class BVTRecorder {
|
|
|
349
352
|
const context = bvtContext.playContext;
|
|
350
353
|
this.context = context;
|
|
351
354
|
this.web = bvtContext.stable || bvtContext.web;
|
|
355
|
+
this.web.tryAllStrategies = true;
|
|
352
356
|
this.page = bvtContext.page;
|
|
353
357
|
|
|
354
358
|
this.pageSet.add(this.page);
|
|
@@ -461,6 +465,75 @@ export class BVTRecorder {
|
|
|
461
465
|
}
|
|
462
466
|
});
|
|
463
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
|
+
|
|
464
537
|
async getCurrentTransition() {
|
|
465
538
|
if (this?.web?.browser?._name !== "chromium") {
|
|
466
539
|
return;
|
|
@@ -469,29 +542,70 @@ export class BVTRecorder {
|
|
|
469
542
|
|
|
470
543
|
try {
|
|
471
544
|
const result = await client.send("Page.getNavigationHistory");
|
|
472
|
-
// console.log("
|
|
545
|
+
// console.log("Navigation History:", result);
|
|
473
546
|
const entries = result.entries;
|
|
474
547
|
const currentIndex = result.currentIndex;
|
|
475
548
|
|
|
476
549
|
// ignore if currentIndex is not the last entry
|
|
477
|
-
if (currentIndex !== entries.length - 1) return;
|
|
550
|
+
// if (currentIndex !== entries.length - 1) return;
|
|
478
551
|
|
|
479
552
|
const currentEntry = entries[currentIndex];
|
|
480
|
-
|
|
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
|
+
};
|
|
481
563
|
} catch (error) {
|
|
482
|
-
console.error("Error in getTransistionType event");
|
|
564
|
+
console.error("Error in getTransistionType event", error);
|
|
483
565
|
} finally {
|
|
484
566
|
await client.detach();
|
|
485
567
|
}
|
|
486
568
|
}
|
|
487
|
-
|
|
569
|
+
userInitiatedTransitionTypes = ["typed", "address_bar"];
|
|
488
570
|
async handlePageTransition() {
|
|
489
571
|
const transition = await this.getCurrentTransition();
|
|
490
572
|
if (!transition) return;
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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;
|
|
495
609
|
}
|
|
496
610
|
}
|
|
497
611
|
|
|
@@ -618,8 +732,13 @@ export class BVTRecorder {
|
|
|
618
732
|
}
|
|
619
733
|
async closeBrowser() {
|
|
620
734
|
delete process.env.TEMP_RUN;
|
|
621
|
-
await this.watcher.close().then(() => {});
|
|
735
|
+
await this.watcher.close().then(() => { });
|
|
622
736
|
this.watcher = null;
|
|
737
|
+
this.previousIndex = null;
|
|
738
|
+
this.previousHistoryLength = null;
|
|
739
|
+
this.previousUrl = null;
|
|
740
|
+
this.previousEntries = null;
|
|
741
|
+
|
|
623
742
|
await closeContext();
|
|
624
743
|
this.pageSet.clear();
|
|
625
744
|
}
|
|
@@ -671,6 +790,7 @@ export class BVTRecorder {
|
|
|
671
790
|
}
|
|
672
791
|
|
|
673
792
|
async startRecordingInput() {
|
|
793
|
+
console.log("startRecordingInput");
|
|
674
794
|
await this.setMode("recordingInput");
|
|
675
795
|
}
|
|
676
796
|
async stopRecordingInput() {
|
|
@@ -694,6 +814,7 @@ export class BVTRecorder {
|
|
|
694
814
|
}
|
|
695
815
|
|
|
696
816
|
async abortExecution() {
|
|
817
|
+
this.bvtContext.web.abortedExecution = true;
|
|
697
818
|
await this.stepRunner.abortExecution();
|
|
698
819
|
}
|
|
699
820
|
async dealyedRevertMode() {
|
|
@@ -702,34 +823,47 @@ export class BVTRecorder {
|
|
|
702
823
|
}, 100);
|
|
703
824
|
this.timerId = timerId;
|
|
704
825
|
}
|
|
705
|
-
async runStep({ step, parametersMap }, options) {
|
|
826
|
+
async runStep({ step, parametersMap, tags, isFirstStep, listenNetwork }, options) {
|
|
827
|
+
const { skipAfter = true, skipBefore = !isFirstStep } = options || {};
|
|
706
828
|
const _env = {
|
|
707
829
|
TOKEN: this.TOKEN,
|
|
708
830
|
TEMP_RUN: true,
|
|
709
831
|
REPORT_FOLDER: this.bvtContext.reportFolder,
|
|
710
832
|
BLINQ_ENV: this.envName,
|
|
833
|
+
STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
|
|
834
|
+
CURRENT_STEP_ID: step.id,
|
|
711
835
|
};
|
|
712
836
|
|
|
713
837
|
this.bvtContext.navigate = true;
|
|
838
|
+
this.bvtContext.loadedRoutes = null;
|
|
839
|
+
this.bvtContext.web.abortedExecution = false;
|
|
714
840
|
for (const [key, value] of Object.entries(_env)) {
|
|
715
841
|
process.env[key] = value;
|
|
716
842
|
}
|
|
843
|
+
|
|
717
844
|
if (this.timerId) {
|
|
718
845
|
clearTimeout(this.timerId);
|
|
719
846
|
this.timerId = null;
|
|
720
847
|
}
|
|
721
848
|
await this.setMode("running");
|
|
849
|
+
|
|
722
850
|
try {
|
|
723
|
-
await this.stepRunner.runStep(
|
|
851
|
+
const { result, info } = await this.stepRunner.runStep(
|
|
724
852
|
{
|
|
725
853
|
step,
|
|
726
854
|
parametersMap,
|
|
727
855
|
envPath: this.envName,
|
|
856
|
+
tags,
|
|
857
|
+
config: this.config,
|
|
728
858
|
},
|
|
729
859
|
this.bvtContext,
|
|
730
|
-
|
|
860
|
+
{
|
|
861
|
+
skipAfter,
|
|
862
|
+
skipBefore,
|
|
863
|
+
}
|
|
731
864
|
);
|
|
732
865
|
await this.revertMode();
|
|
866
|
+
return { info };
|
|
733
867
|
} catch (error) {
|
|
734
868
|
await this.revertMode();
|
|
735
869
|
throw error;
|
|
@@ -738,24 +872,45 @@ export class BVTRecorder {
|
|
|
738
872
|
delete process.env[key];
|
|
739
873
|
}
|
|
740
874
|
this.bvtContext.navigate = false;
|
|
741
|
-
|
|
742
|
-
}
|
|
743
|
-
async runScenario({ steps, parametersMap }) {
|
|
744
|
-
for (const step of steps) {
|
|
745
|
-
await this.runStep({ step, parametersMap });
|
|
875
|
+
this.bvtContext.web.abortedExecution = false;
|
|
746
876
|
}
|
|
747
877
|
}
|
|
748
878
|
async saveScenario({ scenario, featureName, override, isSingleStep }) {
|
|
749
879
|
await updateStepDefinitions({ scenario, featureName, projectDir: this.projectDir }); // updates mjs files
|
|
750
880
|
if (!isSingleStep) await updateFeatureFile({ featureName, scenario, override, projectDir: this.projectDir }); // updates gherkin files
|
|
751
|
-
await this.cleanup();
|
|
881
|
+
await this.cleanup({ tags: scenario.tags });
|
|
752
882
|
}
|
|
753
883
|
async getImplementedSteps() {
|
|
754
|
-
|
|
884
|
+
const stepsAndScenarios = await getImplementedSteps(this.projectDir);
|
|
885
|
+
const implementedSteps = stepsAndScenarios.implementedSteps;
|
|
886
|
+
const scenarios = stepsAndScenarios.scenarios;
|
|
887
|
+
for (const scenario of scenarios) {
|
|
888
|
+
this.scenariosStepsMap.set(scenario.name, scenario.steps);
|
|
889
|
+
delete scenario.steps;
|
|
890
|
+
}
|
|
891
|
+
return {
|
|
892
|
+
implementedSteps,
|
|
893
|
+
scenarios,
|
|
894
|
+
};
|
|
755
895
|
}
|
|
756
896
|
async getStepsAndCommandsForScenario({ name, featureName }) {
|
|
757
|
-
|
|
897
|
+
const steps = this.scenariosStepsMap.get(name) || [];
|
|
898
|
+
for (const step of steps) {
|
|
899
|
+
if (step.isImplemented) {
|
|
900
|
+
step.commands = this.getCommandsForImplementedStep({ stepName: step.text });
|
|
901
|
+
} else {
|
|
902
|
+
step.commands = [];
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return steps;
|
|
906
|
+
// return getStepsAndCommandsForScenario({
|
|
907
|
+
// name,
|
|
908
|
+
// featureName,
|
|
909
|
+
// projectDir: this.projectDir,
|
|
910
|
+
// map: this.scenariosStepsMap,
|
|
911
|
+
// });
|
|
758
912
|
}
|
|
913
|
+
|
|
759
914
|
async generateStepName({ commands, stepsNames, parameters, map }) {
|
|
760
915
|
return await this.namesService.generateStepName({ commands, stepsNames, parameters, map });
|
|
761
916
|
}
|
|
@@ -838,9 +993,9 @@ export class BVTRecorder {
|
|
|
838
993
|
}
|
|
839
994
|
}
|
|
840
995
|
|
|
841
|
-
async discardTestData() {
|
|
996
|
+
async discardTestData({ tags }) {
|
|
842
997
|
resetTestData(this.envName, this.world);
|
|
843
|
-
await this.cleanup();
|
|
998
|
+
await this.cleanup({ tags });
|
|
844
999
|
}
|
|
845
1000
|
async addToTestData(obj) {
|
|
846
1001
|
if (!existsSync(_getDataFile(this.world, this.bvtContext, this.web))) {
|
|
@@ -879,6 +1034,7 @@ export class BVTRecorder {
|
|
|
879
1034
|
const stepParams = parseStepTextParameters(stepName);
|
|
880
1035
|
return getCommandsForImplementedStep(stepName, step_definitions, stepParams).commands;
|
|
881
1036
|
}
|
|
1037
|
+
|
|
882
1038
|
loadExistingScenario({ featureName, scenarioName }) {
|
|
883
1039
|
const step_definitions = loadStepDefinitions(this.projectDir);
|
|
884
1040
|
const featureFilePath = path.join(this.projectDir, "features", featureName);
|
|
@@ -907,6 +1063,7 @@ export class BVTRecorder {
|
|
|
907
1063
|
..._s,
|
|
908
1064
|
keyword: step.keyword.trim(),
|
|
909
1065
|
};
|
|
1066
|
+
parseRouteFiles(this.projectDir, _step);
|
|
910
1067
|
steps.push(_step);
|
|
911
1068
|
}
|
|
912
1069
|
return {
|
|
@@ -946,7 +1103,7 @@ export class BVTRecorder {
|
|
|
946
1103
|
}
|
|
947
1104
|
return result;
|
|
948
1105
|
}
|
|
949
|
-
async cleanup() {
|
|
1106
|
+
async cleanup({ tags }) {
|
|
950
1107
|
const noopStep = {
|
|
951
1108
|
text: "Noop",
|
|
952
1109
|
isImplemented: true,
|
|
@@ -960,6 +1117,7 @@ export class BVTRecorder {
|
|
|
960
1117
|
{
|
|
961
1118
|
step: noopStep,
|
|
962
1119
|
parametersMap: {},
|
|
1120
|
+
tags: tags || [],
|
|
963
1121
|
},
|
|
964
1122
|
{
|
|
965
1123
|
skipAfter: false,
|
|
@@ -998,6 +1156,47 @@ export class BVTRecorder {
|
|
|
998
1156
|
return false;
|
|
999
1157
|
}
|
|
1000
1158
|
}
|
|
1159
|
+
async initExecution({ tags = [] }) {
|
|
1160
|
+
// run before hooks
|
|
1161
|
+
const noopStep = {
|
|
1162
|
+
text: "Noop",
|
|
1163
|
+
isImplemented: true,
|
|
1164
|
+
};
|
|
1165
|
+
await this.runStep(
|
|
1166
|
+
{
|
|
1167
|
+
step: noopStep,
|
|
1168
|
+
parametersMap: {},
|
|
1169
|
+
tags,
|
|
1170
|
+
},
|
|
1171
|
+
{
|
|
1172
|
+
skipBefore: false,
|
|
1173
|
+
skipAfter: true,
|
|
1174
|
+
}
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
async cleanupExecution({ tags = [] }) {
|
|
1178
|
+
// run after hooks
|
|
1179
|
+
const noopStep = {
|
|
1180
|
+
text: "Noop",
|
|
1181
|
+
isImplemented: true,
|
|
1182
|
+
};
|
|
1183
|
+
await this.runStep(
|
|
1184
|
+
{
|
|
1185
|
+
step: noopStep,
|
|
1186
|
+
parametersMap: {},
|
|
1187
|
+
tags,
|
|
1188
|
+
},
|
|
1189
|
+
{
|
|
1190
|
+
skipBefore: true,
|
|
1191
|
+
skipAfter: false,
|
|
1192
|
+
}
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
async resetExecution({ tags = [] }) {
|
|
1196
|
+
// run after hooks followed by before hooks
|
|
1197
|
+
await this.cleanupExecution({ tags });
|
|
1198
|
+
await this.initExecution({ tags });
|
|
1199
|
+
}
|
|
1001
1200
|
}
|
|
1002
1201
|
|
|
1003
1202
|
const parseFeatureFile = (featureFilePath) => {
|