@dev-blinq/cucumber_client 1.0.1224-dev → 1.0.1224-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 +68 -5
- package/bin/assets/preload/unique_locators.js +1 -1
- 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 +68 -10
- 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 +84 -76
- package/bin/client/local_agent.js +7 -3
- package/bin/client/project.js +7 -1
- package/bin/client/recorderv3/bvt_recorder.js +267 -80
- package/bin/client/recorderv3/implemented_steps.js +74 -12
- package/bin/client/recorderv3/index.js +58 -8
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/step_runner.js +319 -67
- 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 +4 -8
- 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) {
|
|
@@ -205,11 +184,8 @@ export class BVTRecorder {
|
|
|
205
184
|
projectDir: this.projectDir,
|
|
206
185
|
logger: this.logger,
|
|
207
186
|
});
|
|
208
|
-
this.stepRunner = new BVTStepRunner({
|
|
209
|
-
projectDir: this.projectDir,
|
|
210
|
-
});
|
|
211
187
|
this.pageSet = new Set();
|
|
212
|
-
|
|
188
|
+
this.pageMetaDataSet = new Set();
|
|
213
189
|
this.lastKnownUrlPath = "";
|
|
214
190
|
// TODO: what is world?
|
|
215
191
|
this.world = { attach: () => {} };
|
|
@@ -225,6 +201,10 @@ export class BVTRecorder {
|
|
|
225
201
|
onStepDetails: "BVTRecorder.onStepDetails",
|
|
226
202
|
getTestData: "BVTRecorder.getTestData",
|
|
227
203
|
onGoto: "BVTRecorder.onGoto",
|
|
204
|
+
cmdExecutionStart: "BVTRecorder.cmdExecutionStart",
|
|
205
|
+
cmdExecutionSuccess: "BVTRecorder.cmdExecutionSuccess",
|
|
206
|
+
cmdExecutionError: "BVTRecorder.cmdExecutionError",
|
|
207
|
+
interceptResults: "BVTRecorder.interceptResults",
|
|
228
208
|
};
|
|
229
209
|
bindings = {
|
|
230
210
|
__bvt_recordCommand: async ({ frame, page, context }, event) => {
|
|
@@ -300,29 +280,22 @@ export class BVTRecorder {
|
|
|
300
280
|
return result;
|
|
301
281
|
}
|
|
302
282
|
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;
|
|
283
|
+
return getInitScript(config, {
|
|
284
|
+
sdkLanguage: "javascript",
|
|
285
|
+
testIdAttributeName: "blinq-test-id",
|
|
286
|
+
stableRafCount: 0,
|
|
287
|
+
browserName: this.browser?.browserType().name(),
|
|
288
|
+
inputFileRoleTextbox: false,
|
|
289
|
+
customEngines: [],
|
|
290
|
+
isUnderTest: true,
|
|
291
|
+
});
|
|
319
292
|
}
|
|
320
293
|
|
|
321
294
|
async _initBrowser({ url }) {
|
|
322
295
|
this.#remoteDebuggerPort = await findAvailablePort();
|
|
323
296
|
process.env.CDP_LISTEN_PORT = this.#remoteDebuggerPort;
|
|
324
297
|
|
|
325
|
-
this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
|
|
298
|
+
// this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
|
|
326
299
|
this.world = { attach: () => {} };
|
|
327
300
|
|
|
328
301
|
const ai_config_file = path.join(this.projectDir, "ai_config.json");
|
|
@@ -334,8 +307,9 @@ export class BVTRecorder {
|
|
|
334
307
|
console.error("Error reading ai_config.json", error);
|
|
335
308
|
}
|
|
336
309
|
}
|
|
310
|
+
this.config = ai_config;
|
|
337
311
|
const initScripts = {
|
|
338
|
-
recorderCjs: injectedScriptSource,
|
|
312
|
+
// recorderCjs: injectedScriptSource,
|
|
339
313
|
scripts: [
|
|
340
314
|
this.getInitScripts(ai_config),
|
|
341
315
|
`\ndelete Object.getPrototypeOf(navigator).webdriver;${process.env.WINDOW_DEBUGGER ? "window.debug=true;\n" : ""}`,
|
|
@@ -347,11 +321,40 @@ export class BVTRecorder {
|
|
|
347
321
|
let stopTime = Date.now();
|
|
348
322
|
this.logger.info(`Browser launched in ${(stopTime - startTime) / 1000} s`);
|
|
349
323
|
this.bvtContext = bvtContext;
|
|
324
|
+
this.stepRunner = new BVTStepRunner({
|
|
325
|
+
projectDir: this.projectDir,
|
|
326
|
+
sendExecutionStatus: (data) => {
|
|
327
|
+
if (data && data.type) {
|
|
328
|
+
switch (data.type) {
|
|
329
|
+
case "cmdExecutionStart":
|
|
330
|
+
console.log("Sending cmdExecutionStart event for cmdId:", data);
|
|
331
|
+
this.sendEvent(this.events.cmdExecutionStart, data);
|
|
332
|
+
break;
|
|
333
|
+
case "cmdExecutionSuccess":
|
|
334
|
+
console.log("Sending cmdExecutionSuccess event for cmdId:", data);
|
|
335
|
+
this.sendEvent(this.events.cmdExecutionSuccess, data);
|
|
336
|
+
break;
|
|
337
|
+
case "cmdExecutionError":
|
|
338
|
+
console.log("Sending cmdExecutionError event for cmdId:", data);
|
|
339
|
+
this.sendEvent(this.events.cmdExecutionError, data);
|
|
340
|
+
break;
|
|
341
|
+
case "interceptResults":
|
|
342
|
+
console.log("Sending interceptResults event");
|
|
343
|
+
this.sendEvent(this.events.interceptResults, data);
|
|
344
|
+
break;
|
|
345
|
+
default:
|
|
346
|
+
console.warn("Unknown command execution status type:", data.type);
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
bvtContext: this.bvtContext,
|
|
352
|
+
});
|
|
350
353
|
const context = bvtContext.playContext;
|
|
351
354
|
this.context = context;
|
|
352
355
|
this.web = bvtContext.stable || bvtContext.web;
|
|
356
|
+
this.web.tryAllStrategies = true;
|
|
353
357
|
this.page = bvtContext.page;
|
|
354
|
-
|
|
355
358
|
this.pageSet.add(this.page);
|
|
356
359
|
this.lastKnownUrlPath = this._updateUrlPath();
|
|
357
360
|
const browser = await this.context.browser();
|
|
@@ -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
|
|
|
@@ -621,6 +734,11 @@ export class BVTRecorder {
|
|
|
621
734
|
delete process.env.TEMP_RUN;
|
|
622
735
|
await this.watcher.close().then(() => {});
|
|
623
736
|
this.watcher = null;
|
|
737
|
+
this.previousIndex = null;
|
|
738
|
+
this.previousHistoryLength = null;
|
|
739
|
+
this.previousUrl = null;
|
|
740
|
+
this.previousEntries = null;
|
|
741
|
+
|
|
624
742
|
await closeContext();
|
|
625
743
|
this.pageSet.clear();
|
|
626
744
|
}
|
|
@@ -697,40 +815,61 @@ export class BVTRecorder {
|
|
|
697
815
|
async abortExecution() {
|
|
698
816
|
await this.stepRunner.abortExecution();
|
|
699
817
|
}
|
|
818
|
+
|
|
819
|
+
async pauseExecution({ cmdId }) {
|
|
820
|
+
await this.stepRunner.pauseExecution(cmdId);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
async resumeExecution({ cmdId }) {
|
|
824
|
+
await this.stepRunner.resumeExecution(cmdId);
|
|
825
|
+
}
|
|
826
|
+
|
|
700
827
|
async dealyedRevertMode() {
|
|
701
828
|
const timerId = setTimeout(async () => {
|
|
702
829
|
await this.revertMode();
|
|
703
830
|
}, 100);
|
|
704
831
|
this.timerId = timerId;
|
|
705
832
|
}
|
|
706
|
-
async runStep({ step, parametersMap }, options) {
|
|
833
|
+
async runStep({ step, parametersMap, tags, isFirstStep, listenNetwork }, options) {
|
|
834
|
+
const { skipAfter = true, skipBefore = !isFirstStep } = options || {};
|
|
707
835
|
const _env = {
|
|
708
836
|
TOKEN: this.TOKEN,
|
|
709
837
|
TEMP_RUN: true,
|
|
710
838
|
REPORT_FOLDER: this.bvtContext.reportFolder,
|
|
711
839
|
BLINQ_ENV: this.envName,
|
|
840
|
+
STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
|
|
841
|
+
CURRENT_STEP_ID: step.id,
|
|
712
842
|
};
|
|
713
843
|
|
|
714
844
|
this.bvtContext.navigate = true;
|
|
845
|
+
this.bvtContext.loadedRoutes = null;
|
|
715
846
|
for (const [key, value] of Object.entries(_env)) {
|
|
716
847
|
process.env[key] = value;
|
|
717
848
|
}
|
|
849
|
+
|
|
718
850
|
if (this.timerId) {
|
|
719
851
|
clearTimeout(this.timerId);
|
|
720
852
|
this.timerId = null;
|
|
721
853
|
}
|
|
722
854
|
await this.setMode("running");
|
|
855
|
+
|
|
723
856
|
try {
|
|
724
|
-
await this.stepRunner.runStep(
|
|
857
|
+
const { result, info } = await this.stepRunner.runStep(
|
|
725
858
|
{
|
|
726
859
|
step,
|
|
727
860
|
parametersMap,
|
|
728
861
|
envPath: this.envName,
|
|
862
|
+
tags,
|
|
863
|
+
config: this.config,
|
|
729
864
|
},
|
|
730
865
|
this.bvtContext,
|
|
731
|
-
|
|
866
|
+
{
|
|
867
|
+
skipAfter,
|
|
868
|
+
skipBefore,
|
|
869
|
+
}
|
|
732
870
|
);
|
|
733
871
|
await this.revertMode();
|
|
872
|
+
return { info };
|
|
734
873
|
} catch (error) {
|
|
735
874
|
await this.revertMode();
|
|
736
875
|
throw error;
|
|
@@ -741,15 +880,10 @@ export class BVTRecorder {
|
|
|
741
880
|
this.bvtContext.navigate = false;
|
|
742
881
|
}
|
|
743
882
|
}
|
|
744
|
-
async runScenario({ steps, parametersMap }) {
|
|
745
|
-
for (const step of steps) {
|
|
746
|
-
await this.runStep({ step, parametersMap });
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
883
|
async saveScenario({ scenario, featureName, override, isSingleStep }) {
|
|
750
884
|
await updateStepDefinitions({ scenario, featureName, projectDir: this.projectDir }); // updates mjs files
|
|
751
885
|
if (!isSingleStep) await updateFeatureFile({ featureName, scenario, override, projectDir: this.projectDir }); // updates gherkin files
|
|
752
|
-
await this.cleanup();
|
|
886
|
+
await this.cleanup({ tags: scenario.tags });
|
|
753
887
|
}
|
|
754
888
|
async getImplementedSteps() {
|
|
755
889
|
const stepsAndScenarios = await getImplementedSteps(this.projectDir);
|
|
@@ -765,7 +899,15 @@ export class BVTRecorder {
|
|
|
765
899
|
};
|
|
766
900
|
}
|
|
767
901
|
async getStepsAndCommandsForScenario({ name, featureName }) {
|
|
768
|
-
|
|
902
|
+
const steps = this.scenariosStepsMap.get(name) || [];
|
|
903
|
+
for (const step of steps) {
|
|
904
|
+
if (step.isImplemented) {
|
|
905
|
+
step.commands = this.getCommandsForImplementedStep({ stepName: step.text });
|
|
906
|
+
} else {
|
|
907
|
+
step.commands = [];
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
return steps;
|
|
769
911
|
// return getStepsAndCommandsForScenario({
|
|
770
912
|
// name,
|
|
771
913
|
// featureName,
|
|
@@ -773,6 +915,7 @@ export class BVTRecorder {
|
|
|
773
915
|
// map: this.scenariosStepsMap,
|
|
774
916
|
// });
|
|
775
917
|
}
|
|
918
|
+
|
|
776
919
|
async generateStepName({ commands, stepsNames, parameters, map }) {
|
|
777
920
|
return await this.namesService.generateStepName({ commands, stepsNames, parameters, map });
|
|
778
921
|
}
|
|
@@ -855,9 +998,9 @@ export class BVTRecorder {
|
|
|
855
998
|
}
|
|
856
999
|
}
|
|
857
1000
|
|
|
858
|
-
async discardTestData() {
|
|
1001
|
+
async discardTestData({ tags }) {
|
|
859
1002
|
resetTestData(this.envName, this.world);
|
|
860
|
-
await this.cleanup();
|
|
1003
|
+
await this.cleanup({ tags });
|
|
861
1004
|
}
|
|
862
1005
|
async addToTestData(obj) {
|
|
863
1006
|
if (!existsSync(_getDataFile(this.world, this.bvtContext, this.web))) {
|
|
@@ -896,6 +1039,7 @@ export class BVTRecorder {
|
|
|
896
1039
|
const stepParams = parseStepTextParameters(stepName);
|
|
897
1040
|
return getCommandsForImplementedStep(stepName, step_definitions, stepParams).commands;
|
|
898
1041
|
}
|
|
1042
|
+
|
|
899
1043
|
loadExistingScenario({ featureName, scenarioName }) {
|
|
900
1044
|
const step_definitions = loadStepDefinitions(this.projectDir);
|
|
901
1045
|
const featureFilePath = path.join(this.projectDir, "features", featureName);
|
|
@@ -924,6 +1068,7 @@ export class BVTRecorder {
|
|
|
924
1068
|
..._s,
|
|
925
1069
|
keyword: step.keyword.trim(),
|
|
926
1070
|
};
|
|
1071
|
+
parseRouteFiles(this.projectDir, _step);
|
|
927
1072
|
steps.push(_step);
|
|
928
1073
|
}
|
|
929
1074
|
return {
|
|
@@ -963,7 +1108,7 @@ export class BVTRecorder {
|
|
|
963
1108
|
}
|
|
964
1109
|
return result;
|
|
965
1110
|
}
|
|
966
|
-
async cleanup() {
|
|
1111
|
+
async cleanup({ tags }) {
|
|
967
1112
|
const noopStep = {
|
|
968
1113
|
text: "Noop",
|
|
969
1114
|
isImplemented: true,
|
|
@@ -977,6 +1122,7 @@ export class BVTRecorder {
|
|
|
977
1122
|
{
|
|
978
1123
|
step: noopStep,
|
|
979
1124
|
parametersMap: {},
|
|
1125
|
+
tags: tags || [],
|
|
980
1126
|
},
|
|
981
1127
|
{
|
|
982
1128
|
skipAfter: false,
|
|
@@ -1015,6 +1161,47 @@ export class BVTRecorder {
|
|
|
1015
1161
|
return false;
|
|
1016
1162
|
}
|
|
1017
1163
|
}
|
|
1164
|
+
async initExecution({ tags = [] }) {
|
|
1165
|
+
// run before hooks
|
|
1166
|
+
const noopStep = {
|
|
1167
|
+
text: "Noop",
|
|
1168
|
+
isImplemented: true,
|
|
1169
|
+
};
|
|
1170
|
+
await this.runStep(
|
|
1171
|
+
{
|
|
1172
|
+
step: noopStep,
|
|
1173
|
+
parametersMap: {},
|
|
1174
|
+
tags,
|
|
1175
|
+
},
|
|
1176
|
+
{
|
|
1177
|
+
skipBefore: false,
|
|
1178
|
+
skipAfter: true,
|
|
1179
|
+
}
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
async cleanupExecution({ tags = [] }) {
|
|
1183
|
+
// run after hooks
|
|
1184
|
+
const noopStep = {
|
|
1185
|
+
text: "Noop",
|
|
1186
|
+
isImplemented: true,
|
|
1187
|
+
};
|
|
1188
|
+
await this.runStep(
|
|
1189
|
+
{
|
|
1190
|
+
step: noopStep,
|
|
1191
|
+
parametersMap: {},
|
|
1192
|
+
tags,
|
|
1193
|
+
},
|
|
1194
|
+
{
|
|
1195
|
+
skipBefore: true,
|
|
1196
|
+
skipAfter: false,
|
|
1197
|
+
}
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
async resetExecution({ tags = [] }) {
|
|
1201
|
+
// run after hooks followed by before hooks
|
|
1202
|
+
await this.cleanupExecution({ tags });
|
|
1203
|
+
await this.initExecution({ tags });
|
|
1204
|
+
}
|
|
1018
1205
|
}
|
|
1019
1206
|
|
|
1020
1207
|
const parseFeatureFile = (featureFilePath) => {
|