@dev-blinq/cucumber_client 1.0.1203-dev → 1.0.1203-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/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 +48 -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 +109 -83
- package/bin/client/local_agent.js +6 -2
- package/bin/client/project.js +6 -2
- package/bin/client/recorderv3/bvt_recorder.js +276 -79
- package/bin/client/recorderv3/implemented_steps.js +69 -14
- package/bin/client/recorderv3/index.js +49 -7
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/step_runner.js +184 -13
- package/bin/client/recorderv3/step_utils.js +155 -8
- package/bin/client/recorderv3/update_feature.js +58 -30
- package/bin/client/recording.js +7 -0
- package/bin/client/run_cucumber.js +16 -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
|
@@ -655,6 +655,7 @@ class LocalAgent {
|
|
|
655
655
|
|
|
656
656
|
let page = agent.project.getPage(agent.pageName, true);
|
|
657
657
|
const generateCodeResult = generateCode(recording, page, userData, agent.project.rootFolder, methodName);
|
|
658
|
+
|
|
658
659
|
if (generateCodeResult.simple === true) {
|
|
659
660
|
agent.sendDone("generateStepCode", null);
|
|
660
661
|
break;
|
|
@@ -707,6 +708,9 @@ class LocalAgent {
|
|
|
707
708
|
cucumberStep: agent.cucumberStep,
|
|
708
709
|
},
|
|
709
710
|
});
|
|
711
|
+
if (generateCodeResult.locatorsMetadata) {
|
|
712
|
+
page.addLocatorsMetadata(generateCodeResult.locatorsMetadata);
|
|
713
|
+
}
|
|
710
714
|
await page.save();
|
|
711
715
|
agent.scenarioReport.updateLastStep({
|
|
712
716
|
recording: command.data.recording,
|
|
@@ -967,7 +971,7 @@ class LocalAgent {
|
|
|
967
971
|
async createNewStepLocal(
|
|
968
972
|
featureName,
|
|
969
973
|
cucumberStep,
|
|
970
|
-
|
|
974
|
+
comments,
|
|
971
975
|
userData,
|
|
972
976
|
firstStep,
|
|
973
977
|
previousTasks,
|
|
@@ -1083,7 +1087,7 @@ class LocalAgent {
|
|
|
1083
1087
|
previousTasks,
|
|
1084
1088
|
scenarioDocument,
|
|
1085
1089
|
scenarioStepIndex,
|
|
1086
|
-
comments
|
|
1090
|
+
comments,
|
|
1087
1091
|
featureFileText,
|
|
1088
1092
|
recover,
|
|
1089
1093
|
dumpConfig: this.dumpConfig,
|
package/bin/client/project.js
CHANGED
|
@@ -4,6 +4,7 @@ import { CodePage } from "./code_gen/page_reflection.js";
|
|
|
4
4
|
import logger from "../logger.js";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
|
+
import { findFilesWithExtension } from "./cucumber/steps_definitions.js";
|
|
7
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
9
|
const __dirname = path.dirname(__filename);
|
|
9
10
|
|
|
@@ -85,7 +86,10 @@ class Project {
|
|
|
85
86
|
logger.error("Error loading utils_template");
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
const files = findFilesWithExtension(this.stepsFolder, "mjs");
|
|
90
|
+
|
|
91
|
+
//let files = readdirSync(this.stepsFolder);
|
|
92
|
+
|
|
89
93
|
for (let i = 0; i < files.length; i++) {
|
|
90
94
|
let file = files[i];
|
|
91
95
|
if (file.startsWith("_")) {
|
|
@@ -100,7 +104,7 @@ class Project {
|
|
|
100
104
|
this.pages.push(page);
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
|
-
return
|
|
107
|
+
return this.environment.name;
|
|
104
108
|
}
|
|
105
109
|
getPagesNames() {
|
|
106
110
|
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,36 @@ 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
|
-
this.world = { attach: () => {} };
|
|
218
|
+
this.world = { attach: () => { } };
|
|
215
219
|
this.shouldTakeScreenshot = true;
|
|
216
220
|
this.watcher = null;
|
|
217
221
|
}
|
|
@@ -224,6 +228,10 @@ export class BVTRecorder {
|
|
|
224
228
|
onStepDetails: "BVTRecorder.onStepDetails",
|
|
225
229
|
getTestData: "BVTRecorder.getTestData",
|
|
226
230
|
onGoto: "BVTRecorder.onGoto",
|
|
231
|
+
cmdExecutionStart: "BVTRecorder.cmdExecutionStart",
|
|
232
|
+
cmdExecutionSuccess: "BVTRecorder.cmdExecutionSuccess",
|
|
233
|
+
cmdExecutionError: "BVTRecorder.cmdExecutionError",
|
|
234
|
+
interceptResults: "BVTRecorder.interceptResults",
|
|
227
235
|
};
|
|
228
236
|
bindings = {
|
|
229
237
|
__bvt_recordCommand: async ({ frame, page, context }, event) => {
|
|
@@ -299,22 +307,15 @@ export class BVTRecorder {
|
|
|
299
307
|
return result;
|
|
300
308
|
}
|
|
301
309
|
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;
|
|
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
|
+
});
|
|
318
319
|
}
|
|
319
320
|
|
|
320
321
|
async _initBrowser({ url }) {
|
|
@@ -322,7 +323,7 @@ export class BVTRecorder {
|
|
|
322
323
|
process.env.CDP_LISTEN_PORT = this.#remoteDebuggerPort;
|
|
323
324
|
|
|
324
325
|
this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
|
|
325
|
-
this.world = { attach: () => {} };
|
|
326
|
+
this.world = { attach: () => { } };
|
|
326
327
|
|
|
327
328
|
const ai_config_file = path.join(this.projectDir, "ai_config.json");
|
|
328
329
|
let ai_config = {};
|
|
@@ -333,8 +334,9 @@ export class BVTRecorder {
|
|
|
333
334
|
console.error("Error reading ai_config.json", error);
|
|
334
335
|
}
|
|
335
336
|
}
|
|
337
|
+
this.config = ai_config;
|
|
336
338
|
const initScripts = {
|
|
337
|
-
recorderCjs: injectedScriptSource,
|
|
339
|
+
// recorderCjs: injectedScriptSource,
|
|
338
340
|
scripts: [
|
|
339
341
|
this.getInitScripts(ai_config),
|
|
340
342
|
`\ndelete Object.getPrototypeOf(navigator).webdriver;${process.env.WINDOW_DEBUGGER ? "window.debug=true;\n" : ""}`,
|
|
@@ -349,6 +351,7 @@ export class BVTRecorder {
|
|
|
349
351
|
const context = bvtContext.playContext;
|
|
350
352
|
this.context = context;
|
|
351
353
|
this.web = bvtContext.stable || bvtContext.web;
|
|
354
|
+
this.web.tryAllStrategies = true;
|
|
352
355
|
this.page = bvtContext.page;
|
|
353
356
|
|
|
354
357
|
this.pageSet.add(this.page);
|
|
@@ -461,6 +464,75 @@ export class BVTRecorder {
|
|
|
461
464
|
}
|
|
462
465
|
});
|
|
463
466
|
}
|
|
467
|
+
|
|
468
|
+
hasHistoryReplacementAtIndex(previousEntries, currentEntries, index) {
|
|
469
|
+
if (!previousEntries || !currentEntries) return false;
|
|
470
|
+
if (index >= previousEntries.length || index >= currentEntries.length) return false;
|
|
471
|
+
|
|
472
|
+
const prevEntry = previousEntries[index];
|
|
473
|
+
// console.log("prevEntry", prevEntry);
|
|
474
|
+
const currEntry = currentEntries[index];
|
|
475
|
+
// console.log("currEntry", currEntry);
|
|
476
|
+
|
|
477
|
+
// Check if the entry at this index has been replaced
|
|
478
|
+
return prevEntry.id !== currEntry.id;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Even simpler approach for your specific case
|
|
482
|
+
analyzeTransitionType(entries, currentIndex, currentEntry) {
|
|
483
|
+
// console.log("Analyzing transition type");
|
|
484
|
+
// console.log("===========================");
|
|
485
|
+
// console.log("Current Index:", currentIndex);
|
|
486
|
+
// console.log("Current Entry:", currentEntry);
|
|
487
|
+
// console.log("Current Entries:", entries);
|
|
488
|
+
// console.log("Current entries length:", entries.length);
|
|
489
|
+
// console.log("===========================");
|
|
490
|
+
// console.log("Previous Index:", this.previousIndex);
|
|
491
|
+
// // console.log("Previous Entry:", this.previousEntries[this.previousIndex]);
|
|
492
|
+
// console.log("Previous Entries:", this.previousEntries);
|
|
493
|
+
// console.log("Previous entries length:", this.previousHistoryLength);
|
|
494
|
+
|
|
495
|
+
if (this.previousIndex === null || this.previousHistoryLength === null || !this.previousEntries) {
|
|
496
|
+
return {
|
|
497
|
+
action: "initial",
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const indexDiff = currentIndex - this.previousIndex;
|
|
502
|
+
const lengthDiff = entries.length - this.previousHistoryLength;
|
|
503
|
+
|
|
504
|
+
// Backward navigation
|
|
505
|
+
if (indexDiff < 0) {
|
|
506
|
+
return { action: "back" };
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Forward navigation
|
|
510
|
+
if (indexDiff > 0 && lengthDiff === 0) {
|
|
511
|
+
// Check if the entry at current index is the same as before
|
|
512
|
+
const entryReplaced = this.hasHistoryReplacementAtIndex(this.previousEntries, entries, currentIndex);
|
|
513
|
+
|
|
514
|
+
if (entryReplaced) {
|
|
515
|
+
return { action: "navigate" }; // New navigation that replaced forward history
|
|
516
|
+
} else {
|
|
517
|
+
return { action: "forward" }; // True forward navigation
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// New navigation (history grew)
|
|
522
|
+
if (lengthDiff > 0) {
|
|
523
|
+
return { action: "navigate" };
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Same position, same length
|
|
527
|
+
if (lengthDiff <= 0) {
|
|
528
|
+
const entryReplaced = this.hasHistoryReplacementAtIndex(this.previousEntries, entries, currentIndex);
|
|
529
|
+
|
|
530
|
+
return entryReplaced ? { action: "navigate" } : { action: "reload" };
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return { action: "unknown" };
|
|
534
|
+
}
|
|
535
|
+
|
|
464
536
|
async getCurrentTransition() {
|
|
465
537
|
if (this?.web?.browser?._name !== "chromium") {
|
|
466
538
|
return;
|
|
@@ -469,29 +541,70 @@ export class BVTRecorder {
|
|
|
469
541
|
|
|
470
542
|
try {
|
|
471
543
|
const result = await client.send("Page.getNavigationHistory");
|
|
472
|
-
// console.log("
|
|
544
|
+
// console.log("Navigation History:", result);
|
|
473
545
|
const entries = result.entries;
|
|
474
546
|
const currentIndex = result.currentIndex;
|
|
475
547
|
|
|
476
548
|
// ignore if currentIndex is not the last entry
|
|
477
|
-
if (currentIndex !== entries.length - 1) return;
|
|
549
|
+
// if (currentIndex !== entries.length - 1) return;
|
|
478
550
|
|
|
479
551
|
const currentEntry = entries[currentIndex];
|
|
480
|
-
|
|
552
|
+
const transitionInfo = this.analyzeTransitionType(entries, currentIndex, currentEntry);
|
|
553
|
+
this.previousIndex = currentIndex;
|
|
554
|
+
this.previousHistoryLength = entries.length;
|
|
555
|
+
this.previousUrl = currentEntry.url;
|
|
556
|
+
this.previousEntries = [...entries]; // Store a copy of current entries
|
|
557
|
+
|
|
558
|
+
return {
|
|
559
|
+
currentEntry,
|
|
560
|
+
navigationAction: transitionInfo.action,
|
|
561
|
+
};
|
|
481
562
|
} catch (error) {
|
|
482
|
-
console.error("Error in getTransistionType event");
|
|
563
|
+
console.error("Error in getTransistionType event", error);
|
|
483
564
|
} finally {
|
|
484
565
|
await client.detach();
|
|
485
566
|
}
|
|
486
567
|
}
|
|
487
|
-
|
|
568
|
+
userInitiatedTransitionTypes = ["typed", "address_bar"];
|
|
488
569
|
async handlePageTransition() {
|
|
489
570
|
const transition = await this.getCurrentTransition();
|
|
490
571
|
if (!transition) return;
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
572
|
+
|
|
573
|
+
const { currentEntry, navigationAction } = transition;
|
|
574
|
+
|
|
575
|
+
switch (navigationAction) {
|
|
576
|
+
case "initial":
|
|
577
|
+
// console.log("Initial navigation, no action taken");
|
|
578
|
+
return;
|
|
579
|
+
case "navigate":
|
|
580
|
+
// console.log("transitionType", transition.transitionType);
|
|
581
|
+
// console.log("sending onGoto event", { url: currentEntry.url,
|
|
582
|
+
// type: "navigate", });
|
|
583
|
+
if (this.userInitiatedTransitionTypes.includes(currentEntry.transitionType)) {
|
|
584
|
+
const env = JSON.parse(readFileSync(this.envName), "utf8");
|
|
585
|
+
const baseUrl = env.baseUrl;
|
|
586
|
+
let url = currentEntry.userTypedURL;
|
|
587
|
+
if (baseUrl && url.startsWith(baseUrl)) {
|
|
588
|
+
url = url.replace(baseUrl, "{{env.baseUrl}}");
|
|
589
|
+
}
|
|
590
|
+
// console.log("User initiated transition");
|
|
591
|
+
this.sendEvent(this.events.onGoto, { url, type: "navigate" });
|
|
592
|
+
}
|
|
593
|
+
return;
|
|
594
|
+
case "back":
|
|
595
|
+
// console.log("User navigated back");
|
|
596
|
+
// console.log("sending onGoto event", {
|
|
597
|
+
// type: "back",
|
|
598
|
+
// });
|
|
599
|
+
this.sendEvent(this.events.onGoto, { type: "back" });
|
|
600
|
+
return;
|
|
601
|
+
case "forward":
|
|
602
|
+
// console.log("User navigated forward"); console.log("sending onGoto event", { type: "forward", });
|
|
603
|
+
this.sendEvent(this.events.onGoto, { type: "forward" });
|
|
604
|
+
return;
|
|
605
|
+
default:
|
|
606
|
+
this.sendEvent(this.events.onGoto, { type: "unknown" });
|
|
607
|
+
return;
|
|
495
608
|
}
|
|
496
609
|
}
|
|
497
610
|
|
|
@@ -618,8 +731,13 @@ export class BVTRecorder {
|
|
|
618
731
|
}
|
|
619
732
|
async closeBrowser() {
|
|
620
733
|
delete process.env.TEMP_RUN;
|
|
621
|
-
await this.watcher.close().then(() => {});
|
|
734
|
+
await this.watcher.close().then(() => { });
|
|
622
735
|
this.watcher = null;
|
|
736
|
+
this.previousIndex = null;
|
|
737
|
+
this.previousHistoryLength = null;
|
|
738
|
+
this.previousUrl = null;
|
|
739
|
+
this.previousEntries = null;
|
|
740
|
+
|
|
623
741
|
await closeContext();
|
|
624
742
|
this.pageSet.clear();
|
|
625
743
|
}
|
|
@@ -671,6 +789,7 @@ export class BVTRecorder {
|
|
|
671
789
|
}
|
|
672
790
|
|
|
673
791
|
async startRecordingInput() {
|
|
792
|
+
console.log("startRecordingInput");
|
|
674
793
|
await this.setMode("recordingInput");
|
|
675
794
|
}
|
|
676
795
|
async stopRecordingInput() {
|
|
@@ -694,6 +813,7 @@ export class BVTRecorder {
|
|
|
694
813
|
}
|
|
695
814
|
|
|
696
815
|
async abortExecution() {
|
|
816
|
+
this.bvtContext.web.abortedExecution = true;
|
|
697
817
|
await this.stepRunner.abortExecution();
|
|
698
818
|
}
|
|
699
819
|
async dealyedRevertMode() {
|
|
@@ -702,34 +822,47 @@ export class BVTRecorder {
|
|
|
702
822
|
}, 100);
|
|
703
823
|
this.timerId = timerId;
|
|
704
824
|
}
|
|
705
|
-
async runStep({ step, parametersMap }, options) {
|
|
825
|
+
async runStep({ step, parametersMap, tags, isFirstStep, listenNetwork }, options) {
|
|
826
|
+
const { skipAfter = true, skipBefore = !isFirstStep } = options || {};
|
|
706
827
|
const _env = {
|
|
707
828
|
TOKEN: this.TOKEN,
|
|
708
829
|
TEMP_RUN: true,
|
|
709
830
|
REPORT_FOLDER: this.bvtContext.reportFolder,
|
|
710
831
|
BLINQ_ENV: this.envName,
|
|
832
|
+
STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
|
|
833
|
+
CURRENT_STEP_ID: step.id,
|
|
711
834
|
};
|
|
712
835
|
|
|
713
836
|
this.bvtContext.navigate = true;
|
|
837
|
+
this.bvtContext.loadedRoutes = null;
|
|
838
|
+
this.bvtContext.web.abortedExecution = false;
|
|
714
839
|
for (const [key, value] of Object.entries(_env)) {
|
|
715
840
|
process.env[key] = value;
|
|
716
841
|
}
|
|
842
|
+
|
|
717
843
|
if (this.timerId) {
|
|
718
844
|
clearTimeout(this.timerId);
|
|
719
845
|
this.timerId = null;
|
|
720
846
|
}
|
|
721
847
|
await this.setMode("running");
|
|
848
|
+
|
|
722
849
|
try {
|
|
723
|
-
await this.stepRunner.runStep(
|
|
850
|
+
const { result, info } = await this.stepRunner.runStep(
|
|
724
851
|
{
|
|
725
852
|
step,
|
|
726
853
|
parametersMap,
|
|
727
854
|
envPath: this.envName,
|
|
855
|
+
tags,
|
|
856
|
+
config: this.config,
|
|
728
857
|
},
|
|
729
858
|
this.bvtContext,
|
|
730
|
-
|
|
859
|
+
{
|
|
860
|
+
skipAfter,
|
|
861
|
+
skipBefore,
|
|
862
|
+
}
|
|
731
863
|
);
|
|
732
864
|
await this.revertMode();
|
|
865
|
+
return { info };
|
|
733
866
|
} catch (error) {
|
|
734
867
|
await this.revertMode();
|
|
735
868
|
throw error;
|
|
@@ -740,22 +873,42 @@ export class BVTRecorder {
|
|
|
740
873
|
this.bvtContext.navigate = false;
|
|
741
874
|
}
|
|
742
875
|
}
|
|
743
|
-
async runScenario({ steps, parametersMap }) {
|
|
744
|
-
for (const step of steps) {
|
|
745
|
-
await this.runStep({ step, parametersMap });
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
876
|
async saveScenario({ scenario, featureName, override, isSingleStep }) {
|
|
749
877
|
await updateStepDefinitions({ scenario, featureName, projectDir: this.projectDir }); // updates mjs files
|
|
750
878
|
if (!isSingleStep) await updateFeatureFile({ featureName, scenario, override, projectDir: this.projectDir }); // updates gherkin files
|
|
751
|
-
await this.cleanup();
|
|
879
|
+
await this.cleanup({ tags: scenario.tags });
|
|
752
880
|
}
|
|
753
881
|
async getImplementedSteps() {
|
|
754
|
-
|
|
882
|
+
const stepsAndScenarios = await getImplementedSteps(this.projectDir);
|
|
883
|
+
const implementedSteps = stepsAndScenarios.implementedSteps;
|
|
884
|
+
const scenarios = stepsAndScenarios.scenarios;
|
|
885
|
+
for (const scenario of scenarios) {
|
|
886
|
+
this.scenariosStepsMap.set(scenario.name, scenario.steps);
|
|
887
|
+
delete scenario.steps;
|
|
888
|
+
}
|
|
889
|
+
return {
|
|
890
|
+
implementedSteps,
|
|
891
|
+
scenarios,
|
|
892
|
+
};
|
|
755
893
|
}
|
|
756
894
|
async getStepsAndCommandsForScenario({ name, featureName }) {
|
|
757
|
-
|
|
895
|
+
const steps = this.scenariosStepsMap.get(name) || [];
|
|
896
|
+
for (const step of steps) {
|
|
897
|
+
if (step.isImplemented) {
|
|
898
|
+
step.commands = this.getCommandsForImplementedStep({ stepName: step.text });
|
|
899
|
+
} else {
|
|
900
|
+
step.commands = [];
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return steps;
|
|
904
|
+
// return getStepsAndCommandsForScenario({
|
|
905
|
+
// name,
|
|
906
|
+
// featureName,
|
|
907
|
+
// projectDir: this.projectDir,
|
|
908
|
+
// map: this.scenariosStepsMap,
|
|
909
|
+
// });
|
|
758
910
|
}
|
|
911
|
+
|
|
759
912
|
async generateStepName({ commands, stepsNames, parameters, map }) {
|
|
760
913
|
return await this.namesService.generateStepName({ commands, stepsNames, parameters, map });
|
|
761
914
|
}
|
|
@@ -838,9 +991,9 @@ export class BVTRecorder {
|
|
|
838
991
|
}
|
|
839
992
|
}
|
|
840
993
|
|
|
841
|
-
async discardTestData() {
|
|
994
|
+
async discardTestData({ tags }) {
|
|
842
995
|
resetTestData(this.envName, this.world);
|
|
843
|
-
await this.cleanup();
|
|
996
|
+
await this.cleanup({ tags });
|
|
844
997
|
}
|
|
845
998
|
async addToTestData(obj) {
|
|
846
999
|
if (!existsSync(_getDataFile(this.world, this.bvtContext, this.web))) {
|
|
@@ -879,6 +1032,7 @@ export class BVTRecorder {
|
|
|
879
1032
|
const stepParams = parseStepTextParameters(stepName);
|
|
880
1033
|
return getCommandsForImplementedStep(stepName, step_definitions, stepParams).commands;
|
|
881
1034
|
}
|
|
1035
|
+
|
|
882
1036
|
loadExistingScenario({ featureName, scenarioName }) {
|
|
883
1037
|
const step_definitions = loadStepDefinitions(this.projectDir);
|
|
884
1038
|
const featureFilePath = path.join(this.projectDir, "features", featureName);
|
|
@@ -907,6 +1061,7 @@ export class BVTRecorder {
|
|
|
907
1061
|
..._s,
|
|
908
1062
|
keyword: step.keyword.trim(),
|
|
909
1063
|
};
|
|
1064
|
+
parseRouteFiles(this.projectDir, _step);
|
|
910
1065
|
steps.push(_step);
|
|
911
1066
|
}
|
|
912
1067
|
return {
|
|
@@ -946,7 +1101,7 @@ export class BVTRecorder {
|
|
|
946
1101
|
}
|
|
947
1102
|
return result;
|
|
948
1103
|
}
|
|
949
|
-
async cleanup() {
|
|
1104
|
+
async cleanup({ tags }) {
|
|
950
1105
|
const noopStep = {
|
|
951
1106
|
text: "Noop",
|
|
952
1107
|
isImplemented: true,
|
|
@@ -960,6 +1115,7 @@ export class BVTRecorder {
|
|
|
960
1115
|
{
|
|
961
1116
|
step: noopStep,
|
|
962
1117
|
parametersMap: {},
|
|
1118
|
+
tags: tags || [],
|
|
963
1119
|
},
|
|
964
1120
|
{
|
|
965
1121
|
skipAfter: false,
|
|
@@ -998,6 +1154,47 @@ export class BVTRecorder {
|
|
|
998
1154
|
return false;
|
|
999
1155
|
}
|
|
1000
1156
|
}
|
|
1157
|
+
async initExecution({ tags = [] }) {
|
|
1158
|
+
// run before hooks
|
|
1159
|
+
const noopStep = {
|
|
1160
|
+
text: "Noop",
|
|
1161
|
+
isImplemented: true,
|
|
1162
|
+
};
|
|
1163
|
+
await this.runStep(
|
|
1164
|
+
{
|
|
1165
|
+
step: noopStep,
|
|
1166
|
+
parametersMap: {},
|
|
1167
|
+
tags,
|
|
1168
|
+
},
|
|
1169
|
+
{
|
|
1170
|
+
skipBefore: false,
|
|
1171
|
+
skipAfter: true,
|
|
1172
|
+
}
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
async cleanupExecution({ tags = [] }) {
|
|
1176
|
+
// run after hooks
|
|
1177
|
+
const noopStep = {
|
|
1178
|
+
text: "Noop",
|
|
1179
|
+
isImplemented: true,
|
|
1180
|
+
};
|
|
1181
|
+
await this.runStep(
|
|
1182
|
+
{
|
|
1183
|
+
step: noopStep,
|
|
1184
|
+
parametersMap: {},
|
|
1185
|
+
tags,
|
|
1186
|
+
},
|
|
1187
|
+
{
|
|
1188
|
+
skipBefore: true,
|
|
1189
|
+
skipAfter: false,
|
|
1190
|
+
}
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
async resetExecution({ tags = [] }) {
|
|
1194
|
+
// run after hooks followed by before hooks
|
|
1195
|
+
await this.cleanupExecution({ tags });
|
|
1196
|
+
await this.initExecution({ tags });
|
|
1197
|
+
}
|
|
1001
1198
|
}
|
|
1002
1199
|
|
|
1003
1200
|
const parseFeatureFile = (featureFilePath) => {
|