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

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