@dev-blinq/cucumber_client 1.0.1184-dev → 1.0.1184-stage

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