@dev-blinq/cucumber_client 1.0.1196-dev → 1.0.1196-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 (40) 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/recorderv3.js +75 -5
  4. package/bin/assets/preload/unique_locators.js +24 -3
  5. package/bin/assets/scripts/aria_snapshot.js +235 -0
  6. package/bin/assets/scripts/dom_attr.js +372 -0
  7. package/bin/assets/scripts/dom_element.js +0 -0
  8. package/bin/assets/scripts/dom_parent.js +185 -0
  9. package/bin/assets/scripts/event_utils.js +105 -0
  10. package/bin/assets/scripts/pw.js +7886 -0
  11. package/bin/assets/scripts/recorder.js +1147 -0
  12. package/bin/assets/scripts/snapshot_capturer.js +155 -0
  13. package/bin/assets/scripts/unique_locators.js +841 -0
  14. package/bin/assets/scripts/yaml.js +4770 -0
  15. package/bin/assets/templates/page_template.txt +2 -16
  16. package/bin/assets/templates/utils_template.txt +59 -7
  17. package/bin/client/cli_helpers.js +11 -13
  18. package/bin/client/code_cleanup/utils.js +42 -14
  19. package/bin/client/code_gen/code_inversion.js +48 -11
  20. package/bin/client/code_gen/index.js +3 -0
  21. package/bin/client/code_gen/page_reflection.js +37 -20
  22. package/bin/client/code_gen/playwright_codeget.js +153 -25
  23. package/bin/client/cucumber/feature.js +108 -28
  24. package/bin/client/cucumber/project_to_document.js +8 -7
  25. package/bin/client/cucumber/steps_definitions.js +118 -85
  26. package/bin/client/local_agent.js +6 -2
  27. package/bin/client/project.js +6 -2
  28. package/bin/client/recorderv3/bvt_recorder.js +272 -76
  29. package/bin/client/recorderv3/implemented_steps.js +69 -14
  30. package/bin/client/recorderv3/index.js +49 -7
  31. package/bin/client/recorderv3/network.js +299 -0
  32. package/bin/client/recorderv3/step_runner.js +183 -13
  33. package/bin/client/recorderv3/step_utils.js +155 -8
  34. package/bin/client/recorderv3/update_feature.js +58 -30
  35. package/bin/client/recording.js +7 -0
  36. package/bin/client/run_cucumber.js +16 -2
  37. package/bin/client/scenario_report.js +35 -8
  38. package/bin/client/test_scenario.js +0 -1
  39. package/bin/index.js +1 -0
  40. package/package.json +15 -8
@@ -47,21 +47,30 @@ const _isCodeGenerationStep = (step) => {
47
47
  step.type === Types.SELECT ||
48
48
  step.type === Types.HOVER ||
49
49
  step.type === Types.EXTRACT_ATTRIBUTE ||
50
+ step.type === Types.EXTRACT_PROPERTY ||
50
51
  step.type === Types.SET_DATE_TIME ||
51
52
  step.type === Types.CHECK ||
52
53
  step.type === Types.PRESS ||
53
54
  step.type === Types.SET_INPUT ||
54
55
  step.type === Types.FILL_UNKNOWN ||
55
- step.type === "context_click" ||
56
- step.type === "parameterized_click" ||
56
+ step.type === Types.CONTEXT_CLICK ||
57
+ step.type === Types.PARAMETERIZED_CLICK ||
57
58
  step.type === Types.VERIFY_ATTRIBUTE ||
59
+ step.type === Types.VERIFY_PROPERTY ||
58
60
  step.type === Types.SET_INPUT_FILES ||
59
- step.type === Types.VERIFY_PAGE_SNAPSHOT
61
+ step.type === Types.VERIFY_PAGE_SNAPSHOT ||
62
+ step.type === Types.CONDITIONAL_WAIT
60
63
  ) {
61
64
  return true;
62
65
  }
63
66
  return false;
64
67
  };
68
+ // Note: this function is used to exclude a key from an object
69
+ // Please move it to utils and use it as a reusable function ...
70
+ function excludeKey(obj, keyToRemove) {
71
+ const { [keyToRemove]: _, ...rest } = obj;
72
+ return rest;
73
+ }
65
74
  const splitToLocatorsGroups = (locators) => {
66
75
  const no_text = locators.locators.filter((locator) => locator.mode === "NO_TEXT");
67
76
  const ignore_digit = locators.locators.filter((locator) => locator.mode === "IGNORE_DIGIT");
@@ -131,7 +140,8 @@ const _generateCodeFromCommand = (step, elements, userData) => {
131
140
  if (!elementIdentifier) {
132
141
  elementIdentifier = findElementIdentifier(node, step, userData, elements);
133
142
  }
134
- elements[elementIdentifier] = locatorObject;
143
+ const withoutAllStrategyLocators = excludeKey(locatorObject, "allStrategyLocators");
144
+ elements[elementIdentifier] = withoutAllStrategyLocators;
135
145
  elementsChanged = true;
136
146
  }
137
147
  let optionElement = null;
@@ -157,6 +167,7 @@ const _generateCodeFromCommand = (step, elements, userData) => {
157
167
  let variable = null;
158
168
  let format = null;
159
169
  let options = null;
170
+ let property = null;
160
171
  switch (step.type) {
161
172
  case Types.SET_INPUT:
162
173
  line = `await context.web.setInputValue(elements["${elementIdentifier}"], `;
@@ -181,19 +192,51 @@ const _generateCodeFromCommand = (step, elements, userData) => {
181
192
  line = `await context.web.setCheck(elements["${elementIdentifier}"], ${step.check}, _params, null, this);`;
182
193
  codeLines.push(line);
183
194
  } else {
184
- if (element_name) {
185
- comment = `// Click on ${element_name}`;
186
- codeLines.push(escapeNonPrintables(comment));
195
+ switch (step.count) {
196
+ case 1:
197
+ if (element_name) {
198
+ comment = `// Click on ${element_name}`;
199
+ codeLines.push(escapeNonPrintables(comment));
200
+ }
201
+ line = `await context.web.click(elements["${elementIdentifier}"], _params, null, this);`;
202
+ codeLines.push(line);
203
+ break;
204
+ case 2:
205
+ if (element_name) {
206
+ comment = `// Double click on ${element_name}`;
207
+ codeLines.push(escapeNonPrintables(comment));
208
+ }
209
+ line = `await context.web.click(elements["${elementIdentifier}"], _params, {clickCount:2}, this);`;
210
+ codeLines.push(line);
211
+ break;
212
+ default:
213
+ if (element_name) {
214
+ comment = `// Click on ${element_name}`;
215
+ codeLines.push(escapeNonPrintables(comment));
216
+ }
217
+ line = `await context.web.click(elements["${elementIdentifier}"], _params, null, this);`;
218
+ codeLines.push(line);
219
+ break;
187
220
  }
188
-
189
- line = `await context.web.click(elements["${elementIdentifier}"], _params, null, this);`;
190
- codeLines.push(line);
191
221
  }
192
222
  break;
193
- case "parameterized_click":
194
- comment = `// Parameterized click on ${step.value}`;
195
- codeLines.push(escapeNonPrintables(comment));
196
- line = `await context.web.click(elements["${elementIdentifier}"], _params, null, this);`;
223
+ case Types.PARAMETERIZED_CLICK:
224
+ switch (step.count) {
225
+ case 1:
226
+ comment = `// Parameterized click on ${step.value}`;
227
+ codeLines.push(escapeNonPrintables(comment));
228
+ line = `await context.web.click(elements["${elementIdentifier}"], _params, null, this);`;
229
+ break;
230
+ case 2:
231
+ comment = `// Parameterized double click on ${step.value}`;
232
+ codeLines.push(escapeNonPrintables(comment));
233
+ line = `await context.web.click(elements["${elementIdentifier}"], _params, {clickCount:2}, this);`;
234
+ break;
235
+ default:
236
+ comment = `// Parameterized click on ${step.value}`;
237
+ codeLines.push(escapeNonPrintables(comment));
238
+ line = `await context.web.click(elements["${elementIdentifier}"], _params, null, this);`;
239
+ }
197
240
  codeLines.push(line);
198
241
  break;
199
242
  case Types.SET_DATE_TIME:
@@ -286,6 +329,30 @@ const _generateCodeFromCommand = (step, elements, userData) => {
286
329
  codeLines.push(line);
287
330
  break;
288
331
  }
332
+ case Types.EXTRACT_PROPERTY: {
333
+ property = escapeNonPrintables(step.parameters[0]);
334
+ variable = escapeNonPrintables(step.parameters[1]);
335
+ input = `"${variable}"`;
336
+ if (step.dataSource === "userData" || step.dataSource === "parameters") {
337
+ input = "_" + step.dataKey;
338
+ }
339
+ let options = "null";
340
+ if (step.regex !== "") {
341
+ options = `{regex: ${JSON.stringify(step.regex)},trimSpaces: ${step.trimSpaces}}`;
342
+ } else if (step.trimSpaces) {
343
+ options = `{trimSpaces: ${step.trimSpaces}}`;
344
+ } else {
345
+ options = "null";
346
+ }
347
+ line = `await context.web.extractProperty(elements["${elementIdentifier}"], "${property}", ${input}, _params,${options}, this);`;
348
+
349
+ if (element_name) {
350
+ comment = `// Extract property ${property} from ${element_name} to ${variable}`;
351
+ codeLines.push(escapeNonPrintables(comment));
352
+ }
353
+ codeLines.push(line);
354
+ break;
355
+ }
289
356
  case Types.VERIFY_PAGE_SNAPSHOT:
290
357
  comment = step.nestFrmLoc
291
358
  ? `// Verify page snapshot ${step.parameters[0]} in the frame ${step.selectors.iframe_src}`
@@ -507,15 +574,39 @@ const _generateCodeFromCommand = (step, elements, userData) => {
507
574
  line = `await context.web.clickType( elements["${elementIdentifier}"] ,"${step.key}",null, _params, {"press":true}, this);`;
508
575
  codeLines.push(line);
509
576
  break;
510
- case "context_click":
511
- comment = `// Click on ${elementIdentifier ? elementIdentifier : step.label} in the context of ${escapeNonPrintables(step.value)}`;
512
- codeLines.push(escapeNonPrintables(comment));
513
- input = `"${escapeNonPrintables(step.value)}"`;
514
- if (step.dataSource === "userData" || step.dataSource === "parameters") {
515
- input = "_" + step.dataKey;
577
+ case Types.CONTEXT_CLICK:
578
+ switch (step.count) {
579
+ case 1:
580
+ comment = `// Click on ${elementIdentifier ? elementIdentifier : step.label} in the context of ${escapeNonPrintables(step.value)}`;
581
+ codeLines.push(escapeNonPrintables(comment));
582
+ input = `"${escapeNonPrintables(step.value.replaceAll('"', '\\"'))}"`;
583
+ if (step.dataSource === "userData" || step.dataSource === "parameters") {
584
+ input = "_" + step.dataKey;
585
+ }
586
+ line = `await context.web.click(elements["${elementIdentifier}"], _params, {"context": ${input}}, this);`;
587
+ codeLines.push(line);
588
+ break;
589
+ case 2:
590
+ comment = `// Double click on ${elementIdentifier ? elementIdentifier : step.label} in the context of ${escapeNonPrintables(step.value)}`;
591
+ codeLines.push(escapeNonPrintables(comment));
592
+ input = `"${escapeNonPrintables(step.value.replaceAll('"', '\\"'))}"`;
593
+ if (step.dataSource === "userData" || step.dataSource === "parameters") {
594
+ input = "_" + step.dataKey;
595
+ }
596
+ line = `await context.web.click(elements["${elementIdentifier}"], _params, {"context": ${input}, clickCount:2}, this);`;
597
+ codeLines.push(line);
598
+ break;
599
+ default:
600
+ comment = `// Click on ${elementIdentifier ? elementIdentifier : step.label} in the context of ${escapeNonPrintables(step.value)}`;
601
+ codeLines.push(escapeNonPrintables(comment));
602
+ input = `"${escapeNonPrintables(step.value.replaceAll('"', '\\"'))}"`;
603
+ if (step.dataSource === "userData" || step.dataSource === "parameters") {
604
+ input = "_" + step.dataKey;
605
+ }
606
+ line = `await context.web.click(elements["${elementIdentifier}"], _params, {"context": ${input}}, this);`;
607
+ codeLines.push(line);
608
+ break;
516
609
  }
517
- line = `await context.web.click(elements["${elementIdentifier}"], _params, {"context": ${input}}, this);`;
518
- codeLines.push(line);
519
610
  break;
520
611
  case "popup_close":
521
612
  break;
@@ -541,6 +632,23 @@ const _generateCodeFromCommand = (step, elements, userData) => {
541
632
  codeLines.push(line);
542
633
  break;
543
634
  }
635
+ case Types.VERIFY_PROPERTY: {
636
+ line = `await context.web.verifyProperty(elements["${elementIdentifier}"], `;
637
+ input = "_param_0";
638
+ if (step.dataSource === "userData" || step.dataSource === "parameters") {
639
+ input = "_" + step.dataKey;
640
+ }
641
+ line += `"${step.parameters[0]}", ${input}, _params, null, this);`;
642
+ codeLines.push(line);
643
+ break;
644
+ }
645
+ case Types.CONDITIONAL_WAIT: {
646
+ line = `await context.web.conditionalWait(elements["${elementIdentifier}"], `;
647
+ input = "_param_0";
648
+ line += `"${step.parameters[1]}", ${input}, _params, null, this);`;
649
+ codeLines.push(line);
650
+ break;
651
+ }
544
652
  case Types.SET_INPUT_FILES: {
545
653
  line = `await context.web.setInputFiles(elements["${elementIdentifier}"], `;
546
654
  let files = step.parameters[0];
@@ -566,6 +674,22 @@ const _generateCodeFromCommand = (step, elements, userData) => {
566
674
  return { codeLines, elements: elementsChanged ? elements : null, elementIdentifier, allStrategyLocators };
567
675
  };
568
676
 
677
+ /**
678
+ * Generates a report command based on the given position.
679
+ * @param {"start"|"end"} position
680
+ */
681
+ const generateReportCommand = (position, cmdId) => {
682
+ const codeLines = [];
683
+ if (position === "start") {
684
+ const line = `await context.web.addCommandToReport("${cmdId}", "PASSED", '{"status":"start","cmdId":"${cmdId}"}', {type:"cmdReport"},this);`;
685
+ codeLines.push(line);
686
+ } else if (position === "end") {
687
+ const line = `await context.web.addCommandToReport("${cmdId}", "PASSED", '{"status":"end","cmdId":"${cmdId}"}', {type:"cmdReport"},this);`;
688
+ codeLines.push(line);
689
+ }
690
+ return codeLines;
691
+ };
692
+
569
693
  const generateCode = (recording, codePage, userData, projectDir, methodName) => {
570
694
  const stepsDefinitions = new StepsDefinitions(projectDir);
571
695
  stepsDefinitions.load(false);
@@ -606,12 +730,16 @@ const generateCode = (recording, codePage, userData, projectDir, methodName) =>
606
730
  if (recordingStep.type === Types.COMPLETE) {
607
731
  return;
608
732
  }
609
- // if (!recordingStep.element) {
610
- // logger.info(`Step ${recordingStep.type} doesn't have an element, ignoring`);
611
- // return;
733
+
734
+ // if (process.env.TEMP_RUN === "true") {
735
+ // codeLines.push(...generateReportCommand("start", recordingStep.cmdId));
612
736
  // }
613
737
  const result = _generateCodeFromCommand(recordingStep, elements, userData);
738
+
614
739
  codeLines.push(...result.codeLines);
740
+ // if (process.env.TEMP_RUN === "true") {
741
+ // codeLines.push(...generateReportCommand("end", recordingStep.cmdId));
742
+ // }
615
743
  if (result.elements) {
616
744
  elements = result.elements;
617
745
  }
@@ -1,11 +1,13 @@
1
+ import { IdGenerator } from "@cucumber/messages";
2
+ import { AstBuilder, GherkinClassicTokenMatcher, Parser, compile } from "@cucumber/gherkin";
1
3
  import { loadConfiguration, loadSupport, runCucumber } from "@dev-blinq/cucumber-js/api";
2
4
  import fs from "fs";
3
-
5
+ import os from "os";
6
+ import path from "path";
4
7
  import { parseStepTextParameters, toCucumberExpression, unEscapeNonPrintables } from "./utils.js";
5
- import { AstBuilder, GherkinClassicTokenMatcher, Parser, compile } from "@cucumber/gherkin";
6
- import { IdGenerator } from "@cucumber/messages";
8
+ import stream from "stream";
7
9
  import { testStringForRegex } from "../recorderv3/update_feature.js";
8
-
10
+ import { generateTestData } from "./feature_data.js";
9
11
  class DataTable {
10
12
  constructor(dataTableDocument) {
11
13
  if (!dataTableDocument) {
@@ -289,7 +291,7 @@ class Feature {
289
291
  }
290
292
  return scenarios;
291
293
  }
292
- generateStracture(stepsDefinitions, fileName, scenarioName = null) {
294
+ generateStracture(stepsDefinitions, fileName, scenarioName = null, errorsInParsing = [], parseFailedFiles = false) {
293
295
  const document = {};
294
296
  document.featureName = this.feature.name;
295
297
  document.fileName = fileName;
@@ -317,6 +319,28 @@ class Feature {
317
319
  stepInfo.functionName = stepDef.functionName;
318
320
  stepInfo.implemented_at = stepDef.implemented_at;
319
321
  }
322
+ if (!stepDef && parseFailedFiles) {
323
+ //Check if the stepName exists in one of the failedToParseFiles
324
+ try {
325
+ const stepName = stepsDefinitions._stepNameToTemplate(stepInfo.template);
326
+ if (errorsInParsing && errorsInParsing.length > 0) {
327
+ for (let k = 0; k < errorsInParsing.length; k++) {
328
+ const failedFile = errorsInParsing[k].file;
329
+ //Read File content, and check if the stepName exists in the file
330
+ const fileContent = fs.readFileSync(failedFile, "utf8");
331
+ if (fileContent.includes(stepName)) {
332
+ stepInfo.implemented = true;
333
+ stepInfo.mjsFile = failedFile.slice(path.normalize(failedFile).indexOf("features/step_definitions"));
334
+ stepInfo.functionName = stepName;
335
+ stepInfo.error = errorsInParsing[k].error;
336
+ break;
337
+ }
338
+ }
339
+ }
340
+ } catch (e) {
341
+ console.error(`Error while checking step ${stepInfo.template} in failed files:`, e);
342
+ }
343
+ }
320
344
  }
321
345
  document.scenarios.push(scenarioInfo);
322
346
  }
@@ -350,6 +374,11 @@ class Examples {
350
374
  return null;
351
375
  }
352
376
  let value = this.tableBody[0].cells[parameterIndex].value;
377
+ if (!value) {
378
+ console.warn(`Parameter ${parameterName} not found in examples table body, or it is empty`);
379
+ return null;
380
+ }
381
+
353
382
  return unEscapeNonPrintables(value); // While editing in recorder, we need to remove backslashes
354
383
  }
355
384
  }
@@ -427,29 +456,7 @@ class Scenario {
427
456
  return this.scenarioText;
428
457
  }
429
458
  }
430
- const scenarioResolution = async (featureFilePath) => {
431
- if (!fs.existsSync(featureFilePath)) {
432
- throw new Error(`Feature file ${featureFilePath} does not exist`);
433
- }
434
- const newId = IdGenerator.uuid();
435
- const builder = new AstBuilder(newId);
436
- const matcher = new GherkinClassicTokenMatcher();
437
-
438
- const parser = new Parser(builder, matcher);
439
-
440
- // normalize the path to start with featuers/ if it's not cut the featureFielPath to only the part after features/
441
- let uri = featureFilePath.startsWith("features/")
442
- ? featureFilePath
443
- : "features/" + featureFilePath.split("features/")[1];
444
-
445
- const featureFileContent = fs.readFileSync(featureFilePath, "utf8");
446
- const gherkinDocument = parser.parse(featureFileContent, newId);
447
459
 
448
- const feature = new Feature(gherkinDocument, featureFileContent);
449
- //const scenario = feature.getScenario(scenarioName);
450
- //return scenario;
451
- return feature;
452
- };
453
460
  const getDocumentAndPickel = (featureName, featureContent, scenarioName) => {
454
461
  const newId = IdGenerator.uuid();
455
462
  const builder = new AstBuilder(newId);
@@ -462,12 +469,85 @@ const getDocumentAndPickel = (featureName, featureContent, scenarioName) => {
462
469
 
463
470
  const gherkinDocument = parser.parse(featureContent, newId);
464
471
  const pickles = compile(gherkinDocument, uri, newId);
465
-
466
472
  // Step 3: Find the specific scenario Pickle
467
473
  const pickle = pickles.find((pickle) => {
468
474
  return pickle.name === scenarioName;
469
475
  });
470
476
  return { gherkinDocument, pickle };
471
477
  };
478
+ const scenarioResolution = async (featureFilePath) => {
479
+ if (!fs.existsSync(featureFilePath)) {
480
+ throw new Error(`Feature file ${featureFilePath} does not exist`);
481
+ }
482
+ const featureFileContent = fs.readFileSync(featureFilePath, "utf8");
483
+ let tmpDir = null;
484
+ try {
485
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "ai-qa"));
486
+ const tmpFeaturePath = path.join(tmpDir, "features");
487
+ fs.mkdirSync(tmpFeaturePath);
488
+ const tmpFeatureFilePath = path.join(tmpFeaturePath, path.basename(featureFilePath));
489
+ let result = generateTestData(featureFilePath);
490
+ if (result.changed) {
491
+ fs.writeFileSync(tmpFeatureFilePath, result.newContent);
492
+ console.log("Fake data was generated for this scenario");
493
+ console.log("Variables:");
494
+ for (let key in result.variables) {
495
+ console.log(`${key}: ${result.variables[key].fake}`);
496
+ }
497
+ console.log("Other fake data:");
498
+ for (let i = 0; i < result.otherFakeData.length; i++) {
499
+ console.log(`${result.otherFakeData[i].var}: ${result.otherFakeData[i].fake}`);
500
+ }
501
+ } else {
502
+ fs.copyFileSync(featureFilePath, tmpFeatureFilePath);
503
+ }
504
+ const writable = new stream.Writable({
505
+ write: function (chunk, encoding, next) {
506
+ //console.log(chunk.toString());
507
+ next();
508
+ },
509
+ });
510
+ const environment = { cwd: tmpDir, stdout: writable, stderr: writable };
511
+ // load configuration from a particular file, and override a specific option
512
+ const provided = {
513
+ default: "--publish-quiet",
514
+ require: [tmpDir],
515
+ failFast: false,
516
+ };
472
517
 
518
+ let gherkinDocument = null;
519
+ const { runConfiguration } = await loadConfiguration({ provided }, environment);
520
+ // load the support code upfront
521
+ const support = await loadSupport(runConfiguration, environment);
522
+ // run cucumber, using the support code we loaded already
523
+ await runCucumber({ ...runConfiguration, support }, environment, function (event) {
524
+ // if (event.source) {
525
+ // scenarioInfo.source = event.source.data;
526
+ // }
527
+ // if (event.pickle && event.pickle.name === scenarioName) {
528
+ // scenarioInfo.pickle = event.pickle;
529
+ // }
530
+ if (event.gherkinDocument) {
531
+ gherkinDocument = event.gherkinDocument;
532
+ }
533
+ //console.log(event);
534
+ //console.log(JSON.stringify(event, null, 2));
535
+ // console.log("");
536
+ });
537
+ const feature = new Feature(gherkinDocument, featureFileContent);
538
+ //const scenario = feature.getScenario(scenarioName);
539
+ //return scenario;
540
+ return feature;
541
+ } finally {
542
+ try {
543
+ if (tmpDir) {
544
+ fs.rmSync(tmpDir, { recursive: true });
545
+ }
546
+ } catch (e) {
547
+ console.error(
548
+ `An error has occurred while removing the temp folder at ${tmpDir}. Please remove it manually. Error: ${e}`
549
+ );
550
+ }
551
+ }
552
+ };
473
553
  export { Feature, Scenario, Step, DataTable, Examples, scenarioResolution, getDocumentAndPickel };
@@ -4,14 +4,14 @@ import { AstBuilder, GherkinClassicTokenMatcher, Parser } from "@cucumber/gherki
4
4
  import { Feature } from "./feature.js";
5
5
  import { StepsDefinitions } from "./steps_definitions.js";
6
6
 
7
- export const projectDocument = (folder, featureName = null, scenarioName = null) => {
7
+ export const projectDocument = (folder, featureName = null, scenarioName = null, supressErrors = false, errors = []) => {
8
8
  const uuidFn = () => (23212).toString(16);
9
9
  const builder = new AstBuilder(uuidFn);
10
10
  const matcher = new GherkinClassicTokenMatcher();
11
11
  const parser = new Parser(builder, matcher);
12
- const stepDefinition = new StepsDefinitions(folder);
13
- stepDefinition.load(false);
14
-
12
+ // load the step definitions from the project folder under steps folder
13
+ const stepDefinition = new StepsDefinitions(folder, false);
14
+ stepDefinition.load(false, supressErrors, errors);
15
15
  // read all the feature files in the project folder under features folder
16
16
  let featureFiles = [];
17
17
  const featuresDir = path.join(folder, "features");
@@ -27,7 +27,7 @@ export const projectDocument = (folder, featureName = null, scenarioName = null)
27
27
  if (featureName && feature.feature.name !== featureName && featureFile !== featureName) {
28
28
  continue;
29
29
  }
30
- const document = feature.generateStracture(stepDefinition, featureFile, scenarioName);
30
+ const document = feature.generateStracture(stepDefinition, featureFile, scenarioName, errors, supressErrors);
31
31
  if (scenarioName && document.scenarios.length === 0) {
32
32
  continue;
33
33
  }
@@ -55,7 +55,8 @@ export const projectDocument = (folder, featureName = null, scenarioName = null)
55
55
  // scenarioName = arg.substring(9);
56
56
  // }
57
57
  // }
58
- // const documents = projectDocument(projectDir, featureName, scenarioName);
58
+ // let errors = [];
59
+ // const documents = projectDocument(projectDir, featureName, scenarioName, true, errors);
59
60
  // const args = process.argv.slice(2);
60
61
 
61
- // console.log(JSON.stringify(projectDocument(args[0])));
62
+ // console.log(JSON.stringify(documents));