@dev-blinq/cucumber_client 1.0.1340-dev → 1.0.1340-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 (53) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +110 -110
  2. package/bin/assets/preload/css_gen.js +10 -10
  3. package/bin/assets/preload/recorderv3.js +3 -1
  4. package/bin/assets/preload/toolbar.js +27 -29
  5. package/bin/assets/preload/unique_locators.js +1 -1
  6. package/bin/assets/preload/yaml.js +288 -275
  7. package/bin/assets/scripts/aria_snapshot.js +223 -220
  8. package/bin/assets/scripts/dom_attr.js +329 -329
  9. package/bin/assets/scripts/dom_parent.js +169 -174
  10. package/bin/assets/scripts/event_utils.js +94 -94
  11. package/bin/assets/scripts/pw.js +2050 -1949
  12. package/bin/assets/scripts/recorder.js +5 -17
  13. package/bin/assets/scripts/snapshot_capturer.js +153 -146
  14. package/bin/assets/scripts/unique_locators.js +940 -815
  15. package/bin/assets/scripts/yaml.js +796 -783
  16. package/bin/assets/templates/_hooks_template.txt +41 -0
  17. package/bin/assets/templates/utils_template.txt +2 -45
  18. package/bin/client/apiTest/apiTest.js +6 -0
  19. package/bin/client/cli_helpers.js +11 -13
  20. package/bin/client/code_cleanup/utils.js +5 -1
  21. package/bin/client/code_gen/api_codegen.js +2 -2
  22. package/bin/client/code_gen/code_inversion.js +112 -4
  23. package/bin/client/code_gen/page_reflection.js +839 -906
  24. package/bin/client/code_gen/playwright_codeget.js +26 -18
  25. package/bin/client/cucumber/feature.js +89 -27
  26. package/bin/client/cucumber/feature_data.js +2 -2
  27. package/bin/client/cucumber/project_to_document.js +9 -3
  28. package/bin/client/cucumber/steps_definitions.js +6 -3
  29. package/bin/client/cucumber_selector.js +17 -1
  30. package/bin/client/local_agent.js +6 -5
  31. package/bin/client/parse_feature_file.js +23 -26
  32. package/bin/client/playground/projects/env.json +2 -2
  33. package/bin/client/project.js +186 -196
  34. package/bin/client/recorderv3/bvt_recorder.js +136 -81
  35. package/bin/client/recorderv3/implemented_steps.js +24 -14
  36. package/bin/client/recorderv3/index.js +59 -54
  37. package/bin/client/recorderv3/network.js +22 -5
  38. package/bin/client/recorderv3/scriptTest.js +1 -1
  39. package/bin/client/recorderv3/services.js +4 -16
  40. package/bin/client/recorderv3/step_runner.js +318 -209
  41. package/bin/client/recorderv3/step_utils.js +476 -17
  42. package/bin/client/recorderv3/update_feature.js +32 -30
  43. package/bin/client/recording.js +1 -0
  44. package/bin/client/run_cucumber.js +1 -1
  45. package/bin/client/scenario_report.js +0 -5
  46. package/bin/client/test_scenario.js +0 -1
  47. package/bin/client/upload-service.js +3 -2
  48. package/bin/client/utils/socket_logger.js +132 -0
  49. package/bin/index.js +1 -0
  50. package/bin/logger.js +3 -2
  51. package/bin/min/consoleApi.min.cjs +2 -3
  52. package/bin/min/injectedScript.min.cjs +16 -16
  53. package/package.json +21 -12
@@ -12,11 +12,11 @@ import { updateFeatureFile } from "./update_feature.js";
12
12
  import { parseStepTextParameters } from "../cucumber/utils.js";
13
13
  import { AstBuilder, GherkinClassicTokenMatcher, Parser } from "@cucumber/gherkin";
14
14
  import chokidar from "chokidar";
15
- import logger from "../../logger.js";
16
15
  import { unEscapeNonPrintables } from "../cucumber/utils.js";
17
16
  import { findAvailablePort } from "../utils/index.js";
18
- import { Step } from "../cucumber/feature.js";
19
-
17
+ import socketLogger from "../utils/socket_logger.js";
18
+ import { tmpdir } from "os";
19
+ import { faker } from "@faker-js/faker";
20
20
  const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
21
21
 
22
22
  const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -45,15 +45,15 @@ async function evaluate(frame, script) {
45
45
  async function findNestedFrameSelector(frame, obj) {
46
46
  try {
47
47
  const parent = frame.parentFrame();
48
- if (parent) console.log(`Parent frame: ${JSON.stringify(parent)}`);
49
48
  if (!parent) return { children: obj };
50
49
  const frameElement = await frame.frameElement();
51
50
  if (!frameElement) return;
52
51
  const selectors = await parent.evaluate((element) => {
53
- return window.getPWLocators(element);
52
+ return window.__bvt_Recorder.locatorGenerator.getElementLocators(element, { excludeText: true }).locators;
54
53
  }, frameElement);
55
54
  return findNestedFrameSelector(parent, { children: obj, selectors });
56
55
  } catch (e) {
56
+ socketLogger.error(`Error in findNestedFrameSelector: ${e}`);
57
57
  console.error(e);
58
58
  }
59
59
  }
@@ -150,6 +150,7 @@ const transformAction = (action, el, isVerify, isPopupCloseClick, isInHoverMode,
150
150
  };
151
151
  }
152
152
  default: {
153
+ socketLogger.error(`Action not supported: ${action.name}`);
153
154
  console.log("action not supported", action);
154
155
  throw new Error("action not supported");
155
156
  }
@@ -161,6 +162,7 @@ const transformAction = (action, el, isVerify, isPopupCloseClick, isInHoverMode,
161
162
  * @property {string} projectDir
162
163
  * @property {string} TOKEN
163
164
  * @property {(name:string, data:any)=> void} sendEvent
165
+ * @property {Object} logger
164
166
  */
165
167
  export class BVTRecorder {
166
168
  #currentURL = "";
@@ -174,7 +176,6 @@ export class BVTRecorder {
174
176
  */
175
177
  constructor(initialState) {
176
178
  Object.assign(this, initialState);
177
- this.logger = logger;
178
179
  this.screenshotMap = new Map();
179
180
  this.snapshotMap = new Map();
180
181
  this.scenariosStepsMap = new Map();
@@ -184,40 +185,16 @@ export class BVTRecorder {
184
185
  projectDir: this.projectDir,
185
186
  logger: this.logger,
186
187
  });
187
- this.stepRunner = new BVTStepRunner({
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
- },
214
- });
215
188
  this.pageSet = new Set();
189
+ this.pageMetaDataSet = new Set();
216
190
  this.lastKnownUrlPath = "";
217
- // TODO: what is world?
218
191
  this.world = { attach: () => {} };
219
192
  this.shouldTakeScreenshot = true;
220
193
  this.watcher = null;
194
+ this.networkEventsFolder = path.join(tmpdir(), "blinq_network_events");
195
+ if (existsSync(this.networkEventsFolder)) {
196
+ rmSync(this.networkEventsFolder, { recursive: true, force: true });
197
+ }
221
198
  }
222
199
  events = {
223
200
  onFrameNavigate: "BVTRecorder.onFrameNavigate",
@@ -237,7 +214,7 @@ export class BVTRecorder {
237
214
  __bvt_recordCommand: async ({ frame, page, context }, event) => {
238
215
  this.#activeFrame = frame;
239
216
  const nestFrmLoc = await findNestedFrameSelector(frame);
240
- console.log(`Time taken for action: ${event.statistics.time}`);
217
+ this.logger.info(`Time taken for action: ${event.statistics.time}`);
241
218
  await this.onAction({ ...event, nestFrmLoc });
242
219
  },
243
220
  __bvt_getMode: async () => {
@@ -256,8 +233,7 @@ export class BVTRecorder {
256
233
  await this.onClosePopup();
257
234
  },
258
235
  __bvt_log: async (src, message) => {
259
- // this.logger.info(message);
260
- console.log(`Inside Browser: ${message}`);
236
+ this.logger.info(`Inside Browser: ${message}`);
261
237
  },
262
238
  __bvt_getObject: (_src, obj) => {
263
239
  this.processObject(obj);
@@ -269,7 +245,6 @@ export class BVTRecorder {
269
245
  const locator = await this.web.page.locator(selector);
270
246
  const snapshot = await locator.ariaSnapshot();
271
247
  return snapshot;
272
- // Triggering workflow
273
248
  };
274
249
 
275
250
  processObject = async ({ type, action, value }) => {
@@ -320,10 +295,11 @@ export class BVTRecorder {
320
295
  }
321
296
 
322
297
  async _initBrowser({ url }) {
298
+ socketLogger.info("Only present in 1.0.1293-stage");
323
299
  this.#remoteDebuggerPort = await findAvailablePort();
324
300
  process.env.CDP_LISTEN_PORT = this.#remoteDebuggerPort;
325
301
 
326
- this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
302
+ // this.stepRunner.setRemoteDebugPort(this.#remoteDebuggerPort);
327
303
  this.world = { attach: () => {} };
328
304
 
329
305
  const ai_config_file = path.join(this.projectDir, "ai_config.json");
@@ -332,9 +308,10 @@ export class BVTRecorder {
332
308
  try {
333
309
  ai_config = JSON.parse(readFileSync(ai_config_file, "utf8"));
334
310
  } catch (error) {
335
- console.error("Error reading ai_config.json", error);
311
+ this.logger.error("Error reading ai_config.json", error);
336
312
  }
337
313
  }
314
+ this.config = ai_config;
338
315
  const initScripts = {
339
316
  // recorderCjs: injectedScriptSource,
340
317
  scripts: [
@@ -343,16 +320,37 @@ export class BVTRecorder {
343
320
  ],
344
321
  };
345
322
 
346
- let startTime = Date.now();
347
323
  const bvtContext = await initContext(url, false, false, this.world, 450, initScripts, this.envName);
348
- let stopTime = Date.now();
349
- this.logger.info(`Browser launched in ${(stopTime - startTime) / 1000} s`);
350
324
  this.bvtContext = bvtContext;
325
+ this.stepRunner = new BVTStepRunner({
326
+ projectDir: this.projectDir,
327
+ sendExecutionStatus: (data) => {
328
+ if (data && data.type) {
329
+ switch (data.type) {
330
+ case "cmdExecutionStart":
331
+ this.sendEvent(this.events.cmdExecutionStart, data);
332
+ break;
333
+ case "cmdExecutionSuccess":
334
+ this.sendEvent(this.events.cmdExecutionSuccess, data);
335
+ break;
336
+ case "cmdExecutionError":
337
+ this.sendEvent(this.events.cmdExecutionError, data);
338
+ break;
339
+ case "interceptResults":
340
+ this.sendEvent(this.events.interceptResults, data);
341
+ break;
342
+ default:
343
+ break;
344
+ }
345
+ }
346
+ },
347
+ bvtContext: this.bvtContext,
348
+ });
351
349
  const context = bvtContext.playContext;
352
350
  this.context = context;
353
351
  this.web = bvtContext.stable || bvtContext.web;
352
+ this.web.tryAllStrategies = true;
354
353
  this.page = bvtContext.page;
355
-
356
354
  this.pageSet.add(this.page);
357
355
  this.lastKnownUrlPath = this._updateUrlPath();
358
356
  const browser = await this.context.browser();
@@ -380,13 +378,15 @@ export class BVTRecorder {
380
378
  }
381
379
  return;
382
380
  } catch (error) {
383
- console.error("Error evaluting in context:", error);
381
+ // console.error("Error evaluting in context:", error);
382
+ this.logger.error("Error evaluating in context:", error);
384
383
  }
385
384
  }
386
385
  }
387
386
 
388
387
  getMode() {
389
- console.log("getMode", this.#mode);
388
+ // console.log("getMode", this.#mode);
389
+ this.logger.info("Current mode:", this.#mode);
390
390
  return this.#mode;
391
391
  }
392
392
 
@@ -428,6 +428,8 @@ export class BVTRecorder {
428
428
  this.sendEvent(this.events.onBrowserClose);
429
429
  }
430
430
  } catch (error) {
431
+ this.logger.error("Error in page close event");
432
+ this.logger.error(error);
431
433
  console.error("Error in page close event");
432
434
  console.error(error);
433
435
  }
@@ -438,8 +440,10 @@ export class BVTRecorder {
438
440
  if (frame !== page.mainFrame()) return;
439
441
  this.handlePageTransition();
440
442
  } catch (error) {
443
+ this.logger.error("Error in handlePageTransition event");
444
+ this.logger.error(error);
441
445
  console.error("Error in handlePageTransition event");
442
- // console.error(error);
446
+ console.error(error);
443
447
  }
444
448
  try {
445
449
  if (frame !== this.#activeFrame) return;
@@ -458,6 +462,8 @@ export class BVTRecorder {
458
462
  // await this._setRecordingMode(frame);
459
463
  // await this._initPage(page);
460
464
  } catch (error) {
465
+ this.logger.error("Error in frame navigate event");
466
+ this.logger.error(error);
461
467
  console.error("Error in frame navigate event");
462
468
  // console.error(error);
463
469
  }
@@ -540,13 +546,9 @@ export class BVTRecorder {
540
546
 
541
547
  try {
542
548
  const result = await client.send("Page.getNavigationHistory");
543
- // console.log("Navigation History:", result);
544
549
  const entries = result.entries;
545
550
  const currentIndex = result.currentIndex;
546
551
 
547
- // ignore if currentIndex is not the last entry
548
- // if (currentIndex !== entries.length - 1) return;
549
-
550
552
  const currentEntry = entries[currentIndex];
551
553
  const transitionInfo = this.analyzeTransitionType(entries, currentIndex, currentEntry);
552
554
  this.previousIndex = currentIndex;
@@ -559,6 +561,8 @@ export class BVTRecorder {
559
561
  navigationAction: transitionInfo.action,
560
562
  };
561
563
  } catch (error) {
564
+ this.logger.error("Error in getCurrentTransition event");
565
+ this.logger.error(error);
562
566
  console.error("Error in getTransistionType event", error);
563
567
  } finally {
564
568
  await client.detach();
@@ -623,9 +627,12 @@ export class BVTRecorder {
623
627
  this.pageSet.add(page);
624
628
 
625
629
  await page.waitForLoadState("domcontentloaded");
630
+
626
631
  // add listener for frame navigation on new tab
627
632
  this._addFrameNavigateListener(page);
628
633
  } catch (error) {
634
+ this.logger.error("Error in page event");
635
+ this.logger.error(error);
629
636
  console.error("Error in page event");
630
637
  console.error(error);
631
638
  }
@@ -667,6 +674,7 @@ export class BVTRecorder {
667
674
  const { data } = await client.send("Page.captureScreenshot", { format: "png" });
668
675
  return data;
669
676
  } catch (error) {
677
+ this.logger.error("Error in taking browser screenshot");
670
678
  console.error("Error in taking browser screenshot", error);
671
679
  } finally {
672
680
  await client.detach();
@@ -712,7 +720,6 @@ export class BVTRecorder {
712
720
  if (this.shouldTakeScreenshot) {
713
721
  await this.storeScreenshot(event);
714
722
  }
715
-
716
723
  this.sendEvent(this.events.onNewCommand, cmdEvent);
717
724
  this._updateUrlPath();
718
725
  }
@@ -788,7 +795,6 @@ export class BVTRecorder {
788
795
  }
789
796
 
790
797
  async startRecordingInput() {
791
- console.log("startRecordingInput");
792
798
  await this.setMode("recordingInput");
793
799
  }
794
800
  async stopRecordingInput() {
@@ -812,9 +818,17 @@ export class BVTRecorder {
812
818
  }
813
819
 
814
820
  async abortExecution() {
815
- this.bvtContext.web.abortedExecution = true;
816
821
  await this.stepRunner.abortExecution();
817
822
  }
823
+
824
+ async pauseExecution({ cmdId }) {
825
+ await this.stepRunner.pauseExecution(cmdId);
826
+ }
827
+
828
+ async resumeExecution({ cmdId }) {
829
+ await this.stepRunner.resumeExecution(cmdId);
830
+ }
831
+
818
832
  async dealyedRevertMode() {
819
833
  const timerId = setTimeout(async () => {
820
834
  await this.revertMode();
@@ -828,13 +842,15 @@ export class BVTRecorder {
828
842
  TEMP_RUN: true,
829
843
  REPORT_FOLDER: this.bvtContext.reportFolder,
830
844
  BLINQ_ENV: this.envName,
831
- STORE_DETAILED_NETWORK_DATA: listenNetwork ? "true" : "false",
832
- CURRENT_STEP_ID: step.id,
833
845
  };
834
846
 
835
847
  this.bvtContext.navigate = true;
836
848
  this.bvtContext.loadedRoutes = null;
837
- this.bvtContext.web.abortedExecution = false;
849
+ if (listenNetwork) {
850
+ this.bvtContext.STORE_DETAILED_NETWORK_DATA = true;
851
+ } else {
852
+ this.bvtContext.STORE_DETAILED_NETWORK_DATA = false;
853
+ }
838
854
  for (const [key, value] of Object.entries(_env)) {
839
855
  process.env[key] = value;
840
856
  }
@@ -852,6 +868,7 @@ export class BVTRecorder {
852
868
  parametersMap,
853
869
  envPath: this.envName,
854
870
  tags,
871
+ config: this.config,
855
872
  },
856
873
  this.bvtContext,
857
874
  {
@@ -906,6 +923,7 @@ export class BVTRecorder {
906
923
  // map: this.scenariosStepsMap,
907
924
  // });
908
925
  }
926
+
909
927
  async generateStepName({ commands, stepsNames, parameters, map }) {
910
928
  return await this.namesService.generateStepName({ commands, stepsNames, parameters, map });
911
929
  }
@@ -957,10 +975,11 @@ export class BVTRecorder {
957
975
  if (existsSync(_getDataFile(this.world, this.bvtContext, this.web))) {
958
976
  try {
959
977
  const testData = JSON.parse(readFileSync(_getDataFile(this.world, this.bvtContext, this.web), "utf8"));
960
- this.logger.info("Test data", testData);
978
+ // this.logger.info("Test data", testData);
961
979
  this.sendEvent(this.events.getTestData, testData);
962
980
  } catch (e) {
963
- this.logger.error("Error reading test data file", e);
981
+ // this.logger.error("Error reading test data file", e);
982
+ console.log("Error reading test data file", e);
964
983
  }
965
984
  }
966
985
 
@@ -969,10 +988,12 @@ export class BVTRecorder {
969
988
  this.watcher.on("all", async (event, path) => {
970
989
  try {
971
990
  const testData = JSON.parse(await readFile(_getDataFile(this.world, this.bvtContext, this.web), "utf8"));
972
- this.logger.info("Test data", testData);
991
+ // this.logger.info("Test data", testData);
992
+ console.log("Test data changed", testData);
973
993
  this.sendEvent(this.events.getTestData, testData);
974
994
  } catch (e) {
975
- this.logger.error("Error reading test data file", e);
995
+ // this.logger.error("Error reading test data file", e);
996
+ console.log("Error reading test data file", e);
976
997
  }
977
998
  });
978
999
  }
@@ -1005,7 +1026,7 @@ export class BVTRecorder {
1005
1026
  .filter((file) => file.endsWith(".feature"))
1006
1027
  .map((file) => path.join(this.projectDir, "features", file));
1007
1028
  try {
1008
- const parsedFiles = featureFiles.map((file) => parseFeatureFile(file));
1029
+ const parsedFiles = featureFiles.map((file) => this.parseFeatureFile(file));
1009
1030
  const output = {};
1010
1031
  parsedFiles.forEach((file) => {
1011
1032
  if (!file.feature) return;
@@ -1033,7 +1054,7 @@ export class BVTRecorder {
1033
1054
  loadExistingScenario({ featureName, scenarioName }) {
1034
1055
  const step_definitions = loadStepDefinitions(this.projectDir);
1035
1056
  const featureFilePath = path.join(this.projectDir, "features", featureName);
1036
- const gherkinDoc = parseFeatureFile(featureFilePath);
1057
+ const gherkinDoc = this.parseFeatureFile(featureFilePath);
1037
1058
  const scenario = gherkinDoc.feature.children.find((child) => child.scenario.name === scenarioName)?.scenario;
1038
1059
 
1039
1060
  const steps = [];
@@ -1189,23 +1210,57 @@ export class BVTRecorder {
1189
1210
  }
1190
1211
  async resetExecution({ tags = [] }) {
1191
1212
  // run after hooks followed by before hooks
1192
- await this.runAfterHooks({ tags });
1193
- await this.runBeforeHooks({ tags });
1213
+ await this.cleanupExecution({ tags });
1214
+ await this.initExecution({ tags });
1194
1215
  }
1195
- }
1196
1216
 
1197
- const parseFeatureFile = (featureFilePath) => {
1198
- try {
1199
- let id = 0;
1200
- const uuidFn = () => (++id).toString(16);
1201
- const builder = new AstBuilder(uuidFn);
1202
- const matcher = new GherkinClassicTokenMatcher();
1203
- const parser = new Parser(builder, matcher);
1204
- const source = readFileSync(featureFilePath, "utf8");
1205
- const gherkinDocument = parser.parse(source);
1206
- return gherkinDocument;
1207
- } catch (e) {
1208
- console.log(e);
1217
+ parseFeatureFile(featureFilePath) {
1218
+ try {
1219
+ let id = 0;
1220
+ const uuidFn = () => (++id).toString(16);
1221
+ const builder = new AstBuilder(uuidFn);
1222
+ const matcher = new GherkinClassicTokenMatcher();
1223
+ const parser = new Parser(builder, matcher);
1224
+ const source = readFileSync(featureFilePath, "utf8");
1225
+ const gherkinDocument = parser.parse(source);
1226
+ return gherkinDocument;
1227
+ } catch (e) {
1228
+ this.logger.error(`Error parsing feature file: ${featureFilePath}`);
1229
+ console.log(e);
1230
+ }
1231
+ return {};
1209
1232
  }
1210
- return {};
1211
- };
1233
+
1234
+ stopRecordingNetwork(input) {
1235
+ if (this.bvtContext) {
1236
+ this.bvtContext.STORE_DETAILED_NETWORK_DATA = false;
1237
+ }
1238
+ }
1239
+
1240
+ async fakeParams(params) {
1241
+ const newFakeParams = {};
1242
+ Object.keys(params).forEach((key) => {
1243
+ if (!params[key].startsWith("{{") || !params[key].endsWith("}}")) {
1244
+ newFakeParams[key] = params[key];
1245
+ return;
1246
+ }
1247
+
1248
+ try {
1249
+ const value = params[key].substring(2, params[key].length - 2).trim();
1250
+ const faking = value.split("(")[0].split(".");
1251
+ let argument = value.substring(value.indexOf("(") + 1, value.lastIndexOf(")"));
1252
+ argument = isNaN(Number(argument)) || argument === "" ? argument : Number(argument);
1253
+ let fakeFunc = faker;
1254
+ faking.forEach((f) => {
1255
+ fakeFunc = fakeFunc[f];
1256
+ });
1257
+ const newValue = fakeFunc(argument);
1258
+ newFakeParams[key] = newValue;
1259
+ } catch (error) {
1260
+ newFakeParams[key] = params[key];
1261
+ }
1262
+ });
1263
+
1264
+ return newFakeParams;
1265
+ }
1266
+ }
@@ -13,7 +13,6 @@ const uuidFn = () => (++id).toString(16);
13
13
  const builder = new AstBuilder(uuidFn);
14
14
  const matcher = new GherkinClassicTokenMatcher();
15
15
  const parser = new Parser(builder, matcher);
16
-
17
16
  let i = 0;
18
17
  const getImplId = () => {
19
18
  return `I-${i++}`;
@@ -61,6 +60,11 @@ export function parseRouteFiles(projectDir, step) {
61
60
  const routeFolder = path.join(projectDir, "data", "routes");
62
61
  const templateRouteMap = new Map();
63
62
 
63
+ if (!existsSync(routeFolder)) {
64
+ step.routeItems = null;
65
+ return;
66
+ }
67
+
64
68
  // Go over all the files in the route folder and parse them
65
69
  const routeFiles = readdirSync(routeFolder).filter((file) => file.endsWith(".json"));
66
70
  for (const file of routeFiles) {
@@ -87,8 +91,8 @@ export function parseRouteFiles(projectDir, step) {
87
91
  const filters = item.filters || {};
88
92
  const queryParams = filters?.queryParams || {};
89
93
  const queryParamsArray = Object.keys(queryParams).map((key) => ({
90
- paramKey: key,
91
- paramValue: queryParams[key],
94
+ key: key,
95
+ value: queryParams[key],
92
96
  }));
93
97
  filters.queryParams = queryParamsArray || [];
94
98
  });
@@ -112,6 +116,12 @@ export const getImplementedSteps = async (projectDir) => {
112
116
  const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
113
117
  //console.log({ utilsContent });
114
118
  writeFileSync(utilsFilePath, utilsContent, "utf8");
119
+ const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
120
+ if (existsSync(hooksTemplateFilePath)) {
121
+ const hooksFilePath = path.join(stepDefinitionFolderPath, "_hooks.mjs");
122
+ const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
123
+ writeFileSync(hooksFilePath, hooksContent, "utf8");
124
+ }
115
125
  } catch (error) {
116
126
  foundErrors.push({ error });
117
127
  }
@@ -284,17 +294,17 @@ export const getImplementedSteps = async (projectDir) => {
284
294
  for (const tag of scenario.tags) {
285
295
  delete tag.location;
286
296
  }
287
- // for (const scenario of scenarios) {
288
- // for (const step of scenario.steps) {
289
- // if (step.templateIndex === undefined) {
290
- // const cleanStepName = stepsDefinitions._stepNameToTemplate(step.text);
291
- // const index = implementedSteps.findIndex((istep) => {
292
- // return cleanStepName === istep.pattern;
293
- // });
294
- // step.templateIndex = index;
295
- // }
296
- // }
297
- // }
297
+ for (const scenario of scenarios) {
298
+ for (const step of scenario.steps) {
299
+ if (step.templateIndex === undefined) {
300
+ const cleanStepName = stepsDefinitions._stepNameToTemplate(step.text);
301
+ const index = implementedSteps.findIndex((istep) => {
302
+ return cleanStepName === istep.pattern;
303
+ });
304
+ step.templateIndex = index;
305
+ }
306
+ }
307
+ }
298
308
  }
299
309
  if (foundErrors.length > 0) {
300
310
  console.log("foundErrors", foundErrors);