@zohodesk/testinglibrary 0.1.8-exp-bdd-v1 → 0.1.8-exp.1

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 (97) hide show
  1. package/.babelrc +18 -18
  2. package/.eslintrc.js +31 -27
  3. package/.prettierrc +5 -5
  4. package/README.md +17 -17
  5. package/bin/cli.js +2 -2
  6. package/build/bdd-framework/cli/commands/env.js +4 -4
  7. package/build/bdd-framework/cli/commands/test.js +6 -2
  8. package/build/bdd-framework/cli/options.js +4 -4
  9. package/build/bdd-framework/cli/worker.js +3 -3
  10. package/build/bdd-framework/config/dir.js +6 -6
  11. package/build/bdd-framework/config/env.js +5 -4
  12. package/build/bdd-framework/config/index.js +2 -2
  13. package/build/bdd-framework/config/lang.js +14 -0
  14. package/build/bdd-framework/cucumber/buildStepDefinition.js +3 -3
  15. package/build/bdd-framework/cucumber/loadSnippetBuilder.js +3 -3
  16. package/build/bdd-framework/cucumber/loadSources.js +9 -9
  17. package/build/bdd-framework/cucumber/loadSteps.js +8 -3
  18. package/build/bdd-framework/decorators.js +2 -2
  19. package/build/bdd-framework/gen/fixtures.js +48 -0
  20. package/build/bdd-framework/gen/formatter.js +64 -17
  21. package/build/bdd-framework/gen/i18n.js +9 -5
  22. package/build/bdd-framework/gen/index.js +9 -8
  23. package/build/bdd-framework/gen/testFile.js +121 -55
  24. package/build/bdd-framework/gen/testNode.js +19 -6
  25. package/build/bdd-framework/gen/testPoms.js +49 -39
  26. package/build/bdd-framework/hooks/scenario.js +107 -0
  27. package/build/bdd-framework/hooks/worker.js +83 -0
  28. package/build/bdd-framework/playwright/fixtureParameterNames.js +27 -11
  29. package/build/bdd-framework/playwright/getLocationInFile.js +17 -11
  30. package/build/bdd-framework/playwright/loadConfig.js +3 -3
  31. package/build/bdd-framework/playwright/testTypeImpl.js +19 -15
  32. package/build/bdd-framework/playwright/transform.js +10 -6
  33. package/build/bdd-framework/playwright/utils.js +3 -6
  34. package/build/bdd-framework/run/StepInvoker.js +73 -0
  35. package/build/bdd-framework/run/bddFixtures.js +118 -55
  36. package/build/bdd-framework/run/bddWorld.js +24 -36
  37. package/build/bdd-framework/snippets/index.js +5 -3
  38. package/build/bdd-framework/snippets/snippetSyntax.js +3 -1
  39. package/build/bdd-framework/snippets/snippetSyntaxTs.js +4 -4
  40. package/build/bdd-framework/stepDefinitions/createBdd.js +30 -13
  41. package/build/bdd-framework/stepDefinitions/decorators/{poms.js → class.js} +13 -9
  42. package/build/bdd-framework/stepDefinitions/decorators/steps.js +14 -8
  43. package/build/bdd-framework/stepDefinitions/defineStep.js +5 -4
  44. package/build/bdd-framework/stepDefinitions/stepConfig.js +5 -5
  45. package/build/bdd-framework/utils/exit.js +26 -18
  46. package/build/bdd-framework/utils/index.js +30 -4
  47. package/build/bdd-framework/utils/jsStringWrap.js +9 -9
  48. package/build/bdd-framework/utils/logger.js +5 -3
  49. package/build/core/playwright/builtInFixtures/addTags.js +19 -0
  50. package/build/core/playwright/builtInFixtures/cacheLayer.js +13 -0
  51. package/build/core/playwright/builtInFixtures/context.js +15 -0
  52. package/build/core/playwright/builtInFixtures/index.js +26 -0
  53. package/build/core/playwright/builtInFixtures/page.js +51 -0
  54. package/build/core/playwright/clear-caches.js +29 -0
  55. package/build/core/playwright/custom-commands.js +1 -1
  56. package/build/core/playwright/index.js +6 -74
  57. package/build/core/playwright/readConfigFile.js +37 -30
  58. package/build/core/playwright/report-generator.js +2 -1
  59. package/build/core/playwright/setup/config-creator.js +43 -20
  60. package/build/core/playwright/setup/config-utils.js +30 -0
  61. package/build/core/playwright/setup/custom-reporter.js +109 -0
  62. package/build/core/playwright/tag-processor.js +68 -0
  63. package/build/core/playwright/test-runner.js +8 -12
  64. package/build/index.d.ts +60 -5
  65. package/build/index.js +18 -12
  66. package/build/lib/cli.js +10 -1
  67. package/build/parser/sample.feature +34 -34
  68. package/build/parser/sample.spec.js +18 -18
  69. package/build/setup-folder-structure/helper.js +35 -0
  70. package/build/setup-folder-structure/reportEnhancement/addonScript.html +25 -0
  71. package/build/setup-folder-structure/reportEnhancement/reportAlteration.js +25 -0
  72. package/build/setup-folder-structure/samples/auth-setup-sample.js +72 -72
  73. package/build/setup-folder-structure/samples/authUsers-sample.json +8 -8
  74. package/build/setup-folder-structure/samples/env-config-sample.json +20 -20
  75. package/build/setup-folder-structure/samples/git-ignore.sample.js +36 -32
  76. package/build/setup-folder-structure/samples/uat-config-sample.js +44 -43
  77. package/build/setup-folder-structure/setupProject.js +10 -5
  78. package/build/utils/cliArgsToObject.js +29 -25
  79. package/build/utils/fileUtils.js +15 -4
  80. package/changelog.md +137 -74
  81. package/jest.config.js +63 -63
  82. package/npm-shrinkwrap.json +6469 -7781
  83. package/package.json +55 -54
  84. package/playwright.config.js +112 -112
  85. package/build/bdd-framework/cucumber/gherkin.d.ts +0 -45
  86. package/build/bdd-framework/gen/poms.js +0 -46
  87. package/build/bdd-framework/stepDefinitions/createDecorators.js +0 -108
  88. package/build/bdd-poc/core-runner/exportMethods.js +0 -20
  89. package/build/bdd-poc/core-runner/stepDefinitions.js +0 -53
  90. package/build/bdd-poc/main.js +0 -10
  91. package/build/bdd-poc/runner.js +0 -19
  92. package/build/bdd-poc/test/cucumber/featureFileParer.js +0 -81
  93. package/build/bdd-poc/test/stepGenerate/stepFileGenerate.js +0 -36
  94. package/build/bdd-poc/test/stepGenerate/stepsnippets.js +0 -43
  95. package/build/bdd-poc/test/testDataMap.js +0 -98
  96. package/build/bdd-poc/test/testStructure.js +0 -83
  97. package/build/bdd-poc/utils/stringManipulation.js +0 -19
@@ -10,15 +10,18 @@ var _path = _interopRequireDefault(require("path"));
10
10
  var _formatter = require("./formatter");
11
11
  var _i18n = require("./i18n");
12
12
  var _loadSteps = require("../cucumber/loadSteps");
13
- var _createBdd = require("../stepDefinitions/createBdd");
14
13
  var _index = require("@cucumber/cucumber/lib/formatter/helpers/index");
15
14
  var _utils = require("../utils");
16
15
  var _testPoms = require("./testPoms");
17
16
  var _testNode = require("./testNode");
18
17
  var _stepConfig = require("../stepDefinitions/stepConfig");
19
18
  var _exit = require("../utils/exit");
20
- /**
21
- * Generate test code.
19
+ var _fixtures = require("./fixtures");
20
+ var _scenario = require("../hooks/scenario");
21
+ var _worker = require("../hooks/worker");
22
+ var _lang = require("../config/lang");
23
+ /**
24
+ * Generate test code.
22
25
  */
23
26
 
24
27
  class TestFile {
@@ -26,6 +29,7 @@ class TestFile {
26
29
  lines = [];
27
30
  i18nKeywordsMap;
28
31
  formatter;
32
+ hasCucumberStyle = false;
29
33
  testNodes = [];
30
34
  hasCustomTest = false;
31
35
  undefinedSteps = [];
@@ -37,7 +41,9 @@ class TestFile {
37
41
  const {
38
42
  uri
39
43
  } = this.options.doc;
40
- if (!uri) throw new Error(`Document without uri`);
44
+ if (!uri) {
45
+ throw new Error(`Document without uri`);
46
+ }
41
47
  return uri;
42
48
  }
43
49
  get content() {
@@ -45,7 +51,10 @@ class TestFile {
45
51
  }
46
52
  get language() {
47
53
  var _this$options$doc$fea;
48
- return ((_this$options$doc$fea = this.options.doc.feature) === null || _this$options$doc$fea === void 0 ? void 0 : _this$options$doc$fea.language) || 'en';
54
+ return ((_this$options$doc$fea = this.options.doc.feature) === null || _this$options$doc$fea === void 0 ? void 0 : _this$options$doc$fea.language) || _lang.LANG_EN;
55
+ }
56
+ get isEnglish() {
57
+ return (0, _lang.isEnglish)(this.language);
49
58
  }
50
59
  get config() {
51
60
  return this.options.config;
@@ -55,14 +64,18 @@ class TestFile {
55
64
  }
56
65
  build() {
57
66
  this.loadI18nKeywords();
58
- this.lines = [...this.getFileHeader(), ...this.getRootSuite(), ...this.getFileFixtures()];
67
+ this.lines = [...this.getFileHeader(),
68
+ // prettier-ignore
69
+ ...this.getRootSuite(), ...this.getFileFixtures()];
59
70
  return this;
60
71
  }
61
72
  save() {
62
73
  const dir = _path.default.dirname(this.outputPath);
63
- if (!_fs.default.existsSync(dir)) _fs.default.mkdirSync(dir, {
64
- recursive: true
65
- });
74
+ if (!_fs.default.existsSync(dir)) {
75
+ _fs.default.mkdirSync(dir, {
76
+ recursive: true
77
+ });
78
+ }
66
79
  _fs.default.writeFileSync(this.outputPath, this.content);
67
80
  }
68
81
  getFileHeader() {
@@ -70,7 +83,7 @@ class TestFile {
70
83
  return this.formatter.fileHeader(this.sourceFile, importTestFrom);
71
84
  }
72
85
  loadI18nKeywords() {
73
- if (this.language !== 'en') {
86
+ if (!this.isEnglish) {
74
87
  this.i18nKeywordsMap = (0, _i18n.getKeywordsMap)(this.language);
75
88
  }
76
89
  }
@@ -78,7 +91,9 @@ class TestFile {
78
91
  const {
79
92
  importTestFrom
80
93
  } = this.config;
81
- if (!importTestFrom) return;
94
+ if (!importTestFrom) {
95
+ return;
96
+ }
82
97
  const {
83
98
  file,
84
99
  varName
@@ -90,37 +105,46 @@ class TestFile {
90
105
  };
91
106
  }
92
107
  getFileFixtures() {
93
- return this.formatter.useFixtures([...this.formatter.testFixture(), ...this.formatter.tagsFixture(this.testNodes)]);
108
+ return this.formatter.useFixtures([...this.formatter.testFixture(), ...(!this.isEnglish ? this.formatter.langFixture(this.language) : []), ...((0, _scenario.hasScenarioHooks)() || this.hasCucumberStyle ? this.formatter.bddWorldFixtures() : []), ...this.formatter.scenarioHookFixtures((0, _scenario.getScenarioHooksFixtures)()), ...this.formatter.workerHookFixtures((0, _worker.getWorkerHooksFixtures)()), ...this.formatter.tagsFixture(this.testNodes)]);
94
109
  }
95
110
  getRootSuite() {
96
111
  const {
97
112
  feature
98
113
  } = this.options.doc;
99
- if (!feature) throw new Error(`Document without feature.`);
114
+ if (!feature) {
115
+ throw new Error(`Document without feature.`);
116
+ }
100
117
  return this.getSuite(feature);
101
118
  }
102
- /**
103
- * Generate test.describe suite for root Feature or Rule
119
+ /**
120
+ * Generate test.describe suite for root Feature or Rule
104
121
  */
105
122
  getSuite(feature, parent) {
106
123
  const node = new _testNode.TestNode(feature, parent);
124
+ if (node.isSkipped()) {
125
+ return this.formatter.suite(node, []);
126
+ }
107
127
  const lines = [];
108
- // const { backgrounds, rules, scenarios } =
109
- // bgFixtures, bgTags - used as fixture hints for decorator steps
110
128
  feature.children.forEach(child => lines.push(...this.getSuiteChild(child, node)));
111
129
  return this.formatter.suite(node, lines);
112
130
  }
113
131
  getSuiteChild(child, parent) {
114
- if ('rule' in child && child.rule) return this.getSuite(child.rule, parent);
115
- if (child.background) return this.getBeforeEach(child.background, parent);
116
- if (child.scenario) return this.getScenarioLines(child.scenario, parent);
132
+ if ('rule' in child && child.rule) {
133
+ return this.getSuite(child.rule, parent);
134
+ }
135
+ if (child.background) {
136
+ return this.getBeforeEach(child.background, parent);
137
+ }
138
+ if (child.scenario) {
139
+ return this.getScenarioLines(child.scenario, parent);
140
+ }
117
141
  throw new Error(`Empty child: ${JSON.stringify(child)}`);
118
142
  }
119
143
  getScenarioLines(scenario, parent) {
120
144
  return this.isOutline(scenario) ? this.getOutlineSuite(scenario, parent) : this.getTest(scenario, parent);
121
145
  }
122
- /**
123
- * Generate test.beforeEach for Background
146
+ /**
147
+ * Generate test.beforeEach for Background
124
148
  */
125
149
  getBeforeEach(bg, parent) {
126
150
  const node = new _testNode.TestNode({
@@ -133,15 +157,18 @@ class TestFile {
133
157
  } = this.getSteps(bg, node.tags);
134
158
  return this.formatter.beforeEach(fixtures, lines);
135
159
  }
136
- /**
137
- * Generate test.describe suite for Scenario Outline
160
+ /**
161
+ * Generate test.describe suite for Scenario Outline
138
162
  */
139
163
  getOutlineSuite(scenario, parent) {
140
164
  const node = new _testNode.TestNode(scenario, parent);
165
+ if (node.isSkipped()) {
166
+ return this.formatter.suite(node, []);
167
+ }
141
168
  const lines = [];
142
169
  let exampleIndex = 0;
143
170
  scenario.examples.forEach(examples => {
144
- const titleFormat = this.getExamplesTitleFormat(examples);
171
+ const titleFormat = this.getExamplesTitleFormat(scenario, examples);
145
172
  examples.tableBody.forEach(exampleRow => {
146
173
  const testTitle = this.getOutlineTestTitle(titleFormat, examples, exampleRow, ++exampleIndex);
147
174
  const testLines = this.getOutlineTest(scenario, examples, exampleRow, testTitle, node);
@@ -150,8 +177,8 @@ class TestFile {
150
177
  });
151
178
  return this.formatter.suite(node, lines);
152
179
  }
153
- /**
154
- * Generate test from Examples row of Scenario Outline
180
+ /**
181
+ * Generate test from Examples row of Scenario Outline
155
182
  */
156
183
  // eslint-disable-next-line max-params
157
184
  getOutlineTest(scenario, examples, exampleRow, title, parent) {
@@ -159,7 +186,12 @@ class TestFile {
159
186
  name: title,
160
187
  tags: examples.tags
161
188
  }, parent);
162
- if (this.skipByTagsExpression(node)) return [];
189
+ if (this.skipByTagsExpression(node)) {
190
+ return [];
191
+ }
192
+ if (node.isSkipped()) {
193
+ return this.formatter.test(node, new Set(), []);
194
+ }
163
195
  this.testNodes.push(node);
164
196
  const {
165
197
  fixtures,
@@ -167,12 +199,17 @@ class TestFile {
167
199
  } = this.getSteps(scenario, node.tags, exampleRow.id);
168
200
  return this.formatter.test(node, fixtures, lines);
169
201
  }
170
- /**
171
- * Generate test from Scenario
202
+ /**
203
+ * Generate test from Scenario
172
204
  */
173
205
  getTest(scenario, parent) {
174
206
  const node = new _testNode.TestNode(scenario, parent);
175
- if (this.skipByTagsExpression(node)) return [];
207
+ if (this.skipByTagsExpression(node)) {
208
+ return [];
209
+ }
210
+ if (node.isSkipped()) {
211
+ return this.formatter.test(node, new Set(), []);
212
+ }
176
213
  this.testNodes.push(node);
177
214
  const {
178
215
  fixtures,
@@ -180,8 +217,8 @@ class TestFile {
180
217
  } = this.getSteps(scenario, node.tags);
181
218
  return this.formatter.test(node, fixtures, lines);
182
219
  }
183
- /**
184
- * Generate test steps
220
+ /**
221
+ * Generate test steps
185
222
  */
186
223
  getSteps(scenario, tags, outlineExampleRowId) {
187
224
  const testFixtureNames = new Set();
@@ -230,8 +267,8 @@ class TestFile {
230
267
  lines
231
268
  };
232
269
  }
233
- /**
234
- * Generate step for Given, When, Then
270
+ /**
271
+ * Generate step for Given, When, Then
235
272
  */
236
273
  // eslint-disable-next-line max-statements, complexity
237
274
  getStep(step, previousKeywordType, outlineExampleRowId) {
@@ -242,26 +279,27 @@ class TestFile {
242
279
  language: this.language,
243
280
  previousKeywordType
244
281
  });
245
- let keyword = this.getStepKeyword(step);
282
+ const enKeyword = this.getStepEnglishKeyword(step);
246
283
  if (!stepDefinition) {
247
284
  this.undefinedSteps.push({
248
285
  keywordType,
249
286
  step,
250
287
  pickleStep
251
288
  });
252
- return this.getMissingStep(keyword, keywordType, pickleStep);
289
+ return this.getMissingStep(enKeyword, keywordType, pickleStep);
253
290
  }
254
291
  // for cucumber-style stepConfig is undefined
255
292
  const stepConfig = (0, _stepConfig.getStepConfig)(stepDefinition);
256
- if (stepConfig !== null && stepConfig !== void 0 && stepConfig.hasCustomTest) this.hasCustomTest = true;
257
- // for cucumber-style transform Given/When/Then -> Given_/When_/Then_
258
- // to use own bddWorld (containing PW built-in fixtures)
259
- if (!(0, _stepConfig.isPlaywrightStyle)(stepConfig)) keyword = `${keyword}_`;
260
- // for decorator steps fixtureNames are defined later in second pass
261
- const fixtureNames = (0, _stepConfig.isDecorator)(stepConfig) ? [] : (0, _createBdd.extractFixtureNames)(stepConfig === null || stepConfig === void 0 ? void 0 : stepConfig.fn);
262
- const line = (0, _stepConfig.isDecorator)(stepConfig) ? '' : this.formatter.step(keyword, pickleStep.text, pickleStep.argument, fixtureNames);
293
+ if (stepConfig !== null && stepConfig !== void 0 && stepConfig.hasCustomTest) {
294
+ this.hasCustomTest = true;
295
+ }
296
+ if (!(0, _stepConfig.isPlaywrightStyle)(stepConfig)) {
297
+ this.hasCucumberStyle = true;
298
+ }
299
+ const fixtureNames = this.getStepFixtureNames(stepDefinition);
300
+ const line = (0, _stepConfig.isDecorator)(stepConfig) ? '' : this.formatter.step(enKeyword, pickleStep.text, pickleStep.argument, fixtureNames);
263
301
  return {
264
- keyword,
302
+ keyword: enKeyword,
265
303
  keywordType,
266
304
  fixtureNames,
267
305
  line,
@@ -288,16 +326,29 @@ class TestFile {
288
326
  const hasRowId = !outlineExampleRowId || astNodeIds.includes(outlineExampleRowId);
289
327
  return hasStepId && hasRowId;
290
328
  });
291
- if (pickleStep) return pickleStep;
329
+ if (pickleStep) {
330
+ return pickleStep;
331
+ }
292
332
  }
293
333
  throw new Error(`Pickle step not found for step: ${step.text}`);
294
334
  }
295
- getStepKeyword(step) {
296
- const origKeyword = step.keyword.trim();
297
- const enKeyword = origKeyword === '*' ? 'And' : this.getEnglishKeyword(origKeyword);
298
- if (!enKeyword) throw new Error(`Keyword not found: ${origKeyword}`);
335
+ getStepEnglishKeyword(step) {
336
+ const nativeKeyword = step.keyword.trim();
337
+ const enKeyword = nativeKeyword === '*' ? 'And' : this.getEnglishKeyword(nativeKeyword);
338
+ if (!enKeyword) {
339
+ throw new Error(`Keyword not found: ${nativeKeyword}`);
340
+ }
299
341
  return enKeyword;
300
342
  }
343
+ getStepFixtureNames(stepDefinition) {
344
+ const stepConfig = (0, _stepConfig.getStepConfig)(stepDefinition);
345
+ if ((0, _stepConfig.isPlaywrightStyle)(stepConfig)) {
346
+ // for decorator steps fixtureNames are defined later in second pass
347
+ return (0, _stepConfig.isDecorator)(stepConfig) ? [] : (0, _fixtures.extractFixtureNames)(stepConfig.fn);
348
+ } else {
349
+ return (0, _fixtures.extractFixtureNamesFromFnBodyMemo)(stepDefinition.code);
350
+ }
351
+ }
301
352
  getDecoratorStep(step, testPoms) {
302
353
  const {
303
354
  keyword,
@@ -323,11 +374,16 @@ class TestFile {
323
374
  exampleRow.cells.forEach((cell, index) => {
324
375
  var _examples$tableHeader;
325
376
  const colName = (_examples$tableHeader = examples.tableHeader) === null || _examples$tableHeader === void 0 || (_examples$tableHeader = _examples$tableHeader.cells[index]) === null || _examples$tableHeader === void 0 ? void 0 : _examples$tableHeader.value;
326
- if (colName) params[colName] = cell.value;
377
+ if (colName) {
378
+ params[colName] = cell.value;
379
+ }
327
380
  });
328
381
  return (0, _utils.template)(titleFormat, params);
329
382
  }
330
- getExamplesTitleFormat(examples) {
383
+ getExamplesTitleFormat(scenario, examples) {
384
+ return this.getExamplesTitleFormatFromComment(examples) || this.getExamplesTitleFormatFromScenarioName(scenario, examples) || this.config.examplesTitleFormat;
385
+ }
386
+ getExamplesTitleFormatFromComment(examples) {
331
387
  var _comment$text;
332
388
  const {
333
389
  line
@@ -338,12 +394,22 @@ class TestFile {
338
394
  });
339
395
  const commentText = comment === null || comment === void 0 || (_comment$text = comment.text) === null || _comment$text === void 0 ? void 0 : _comment$text.trim();
340
396
  const prefix = '# title-format:';
341
- return commentText !== null && commentText !== void 0 && commentText.startsWith(prefix) ? commentText.replace(prefix, '').trim() : this.config.examplesTitleFormat;
397
+ return commentText !== null && commentText !== void 0 && commentText.startsWith(prefix) ? commentText.replace(prefix, '').trim() : '';
398
+ }
399
+ getExamplesTitleFormatFromScenarioName(scenario, examples) {
400
+ var _examples$tableHeader2;
401
+ const columnsInScenarioName = (0, _utils.extractTemplateParams)(scenario.name);
402
+ const hasColumnsFromExamples = columnsInScenarioName.length && ((_examples$tableHeader2 = examples.tableHeader) === null || _examples$tableHeader2 === void 0 || (_examples$tableHeader2 = _examples$tableHeader2.cells) === null || _examples$tableHeader2 === void 0 ? void 0 : _examples$tableHeader2.some(cell => {
403
+ return cell.value && columnsInScenarioName.includes(cell.value);
404
+ }));
405
+ return hasColumnsFromExamples ? scenario.name : '';
342
406
  }
343
407
  skipByTagsExpression(node) {
344
- var _this$options$tagsExp;
345
408
  // see: https://github.com/cucumber/tag-expressions/tree/main/javascript
346
- return ((_this$options$tagsExp = this.options.tagsExpression) === null || _this$options$tagsExp === void 0 ? void 0 : _this$options$tagsExp.evaluate(node.tags)) === false;
409
+ const {
410
+ tagsExpression
411
+ } = this.options;
412
+ return tagsExpression && !tagsExpression.evaluate(node.tags);
347
413
  }
348
414
  isOutline(scenario) {
349
415
  const keyword = this.getEnglishKeyword(scenario.keyword);
@@ -5,9 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.TestNode = void 0;
7
7
  var _utils = require("../utils");
8
- /**
9
- * Universal TestNode class of parent-child relations in test file structure.
10
- * Holds tags and titles path.
8
+ /**
9
+ * Universal TestNode class of parent-child relations in test file structure.
10
+ * Holds tags and titles path.
11
11
  */
12
12
 
13
13
  const SPECIAL_TAGS = ['@only', '@skip', '@fixme'];
@@ -23,6 +23,9 @@ class TestNode {
23
23
  this.title = gherkinNode.name;
24
24
  this.titlePath = ((parent === null || parent === void 0 ? void 0 : parent.titlePath) || []).concat([this.title]);
25
25
  }
26
+ isSkipped() {
27
+ return this.flags.skip || this.flags.fixme;
28
+ }
26
29
  initOwnTags(gherkinNode) {
27
30
  const tagNames = (0, _utils.removeDuplicates)(getTagNames(gherkinNode.tags));
28
31
  tagNames.forEach(tag => {
@@ -33,10 +36,20 @@ class TestNode {
33
36
  }
34
37
  });
35
38
  }
39
+ // eslint-disable-next-line complexity
36
40
  setFlag(tag) {
37
- if (tag === '@only') this.flags.only = true;
38
- if (tag === '@skip') this.flags.skip = true;
39
- if (tag === '@fixme') this.flags.fixme = true;
41
+ // in case of several system tags, @only takes precendence
42
+ if (tag === '@only') {
43
+ this.flags = {
44
+ only: true
45
+ };
46
+ }
47
+ if (tag === '@skip' && !this.flags.only) {
48
+ this.flags.skip = true;
49
+ }
50
+ if (tag === '@fixme' && !this.flags.only) {
51
+ this.flags.fixme = true;
52
+ }
40
53
  }
41
54
  }
42
55
  exports.TestNode = TestNode;
@@ -5,29 +5,29 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.TestPoms = void 0;
7
7
  exports.buildFixtureTag = buildFixtureTag;
8
- var _poms = require("../stepDefinitions/decorators/poms");
8
+ var _class = require("../stepDefinitions/decorators/class");
9
9
  var _exit = require("../utils/exit");
10
- /**
11
- * Track PomNodes used in the particular test.
12
- * To select correct fixture for decorator steps.
13
- *
14
- * Idea: try to use the deepest child fixture for parent steps.
15
- *
16
- * Example inheritance tree:
17
- * A
18
- * / \
19
- * B C
20
- * / \ \
21
- * D E F
22
- *
23
- * If test uses steps from classes A and D:
24
- * -> resolved fixture will be D, even for steps from A.
25
- *
26
- * If test uses steps from classes A, D and C:
27
- * -> error, b/c A has 2 possible fixtures.
28
- *
29
- * If test uses steps from classes A and C, but @fixture tag is D:
30
- * -> error, b/c A has 2 possible fixtures.
10
+ /**
11
+ * Track PomNodes used in the particular test.
12
+ * To select correct fixture for decorator steps.
13
+ *
14
+ * Idea: try to use the deepest child fixture for parent steps.
15
+ *
16
+ * Example inheritance tree:
17
+ * A
18
+ * / \
19
+ * B C
20
+ * / \ \
21
+ * D E F
22
+ *
23
+ * If test uses steps from classes A and D:
24
+ * -> resolved fixture will be D, even for steps from A.
25
+ *
26
+ * If test uses steps from classes A, D and C:
27
+ * -> error, b/c A has 2 possible fixtures.
28
+ *
29
+ * If test uses steps from classes A and C, but @fixture tag is D:
30
+ * -> error, b/c A has 2 possible fixtures.
31
31
  */
32
32
 
33
33
  const FIXTURE_TAG_PREFIX = '@fixture:';
@@ -44,7 +44,7 @@ class TestPoms {
44
44
  });
45
45
  }
46
46
  addByFixtureName(fixtureName) {
47
- const pomNode = (0, _poms.getPomNodeByFixtureName)(fixtureName);
47
+ const pomNode = (0, _class.getPomNodeByFixtureName)(fixtureName);
48
48
  this.addUsedPom(pomNode, {
49
49
  byTag: false
50
50
  });
@@ -52,31 +52,35 @@ class TestPoms {
52
52
  addByTag(tag) {
53
53
  const fixtureName = extractFixtureName(tag);
54
54
  if (fixtureName) {
55
- const pomNode = (0, _poms.getPomNodeByFixtureName)(fixtureName);
55
+ const pomNode = (0, _class.getPomNodeByFixtureName)(fixtureName);
56
56
  this.addUsedPom(pomNode, {
57
57
  byTag: true
58
58
  });
59
59
  }
60
60
  }
61
- /**
62
- * Resolve all used pomNodes to fixtures.
63
- * This is needed to handle @fixture: tagged pomNodes
64
- * that does not have steps in the test, but should be considered.
61
+ /**
62
+ * Resolve all used pomNodes to fixtures.
63
+ * This is needed to handle @fixture: tagged pomNodes
64
+ * that does not have steps in the test, but should be considered.
65
65
  */
66
66
  resolveFixtures() {
67
67
  this.usedPoms.forEach((_, pomNode) => {
68
68
  this.getResolvedFixtures(pomNode);
69
69
  });
70
70
  }
71
- /**
72
- * Returns fixtures suitable for particular pomNode (actually for step)
71
+ /**
72
+ * Returns fixtures suitable for particular pomNode (actually for step)
73
73
  */
74
74
  getResolvedFixtures(pomNode) {
75
75
  const usedPom = this.usedPoms.get(pomNode);
76
- if (usedPom !== null && usedPom !== void 0 && usedPom.fixtures) return usedPom.fixtures;
76
+ if (usedPom !== null && usedPom !== void 0 && usedPom.fixtures) {
77
+ return usedPom.fixtures;
78
+ }
77
79
  // Recursively resolve children fixtures, used in test.
78
80
  let childFixtures = [...pomNode.children].map(child => this.getResolvedFixtures(child)).flat();
79
- if (!usedPom) return childFixtures;
81
+ if (!usedPom) {
82
+ return childFixtures;
83
+ }
80
84
  if (childFixtures.length) {
81
85
  this.verifyChildFixtures(pomNode, usedPom, childFixtures);
82
86
  usedPom.fixtures = childFixtures;
@@ -91,23 +95,29 @@ class TestPoms {
91
95
  addUsedPom(pomNode, {
92
96
  byTag
93
97
  }) {
94
- if (!pomNode) return;
98
+ if (!pomNode) {
99
+ return;
100
+ }
95
101
  const usedPom = this.usedPoms.get(pomNode);
96
102
  if (usedPom) {
97
- if (byTag && !usedPom.byTag) usedPom.byTag = true;
103
+ if (byTag && !usedPom.byTag) {
104
+ usedPom.byTag = true;
105
+ }
98
106
  } else {
99
107
  this.usedPoms.set(pomNode, {
100
108
  byTag
101
109
  });
102
110
  }
103
111
  }
104
- /**
105
- * For scenarios with @fixture:xxx tags verify that there are no steps from fixtures,
106
- * deeper than xxx.
107
- * @fixture:xxx tag provides maximum fixture that can be used in the scenario.
112
+ /**
113
+ * For scenarios with @fixture:xxx tags verify that there are no steps from fixtures,
114
+ * deeper than xxx.
115
+ * @fixture:xxx tag provides maximum fixture that can be used in the scenario.
108
116
  */
109
117
  verifyChildFixtures(pomNode, usedPom, childFixtures) {
110
- if (!usedPom.byTag) return;
118
+ if (!usedPom.byTag) {
119
+ return;
120
+ }
111
121
  const childFixturesBySteps = childFixtures.filter(f => !f.byTag);
112
122
  if (childFixturesBySteps.length) {
113
123
  (0, _exit.exit)(`Scenario "${this.title}" contains ${childFixturesBySteps.length} step(s)`, `not compatible with required fixture "${pomNode.fixtureName}"`);
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getScenarioHooksFixtures = getScenarioHooksFixtures;
8
+ exports.hasScenarioHooks = hasScenarioHooks;
9
+ exports.runScenarioHooks = runScenarioHooks;
10
+ exports.scenarioHookFactory = scenarioHookFactory;
11
+ var _tagExpressions = _interopRequireDefault(require("@cucumber/tag-expressions"));
12
+ var _fixtureParameterNames = require("../playwright/fixtureParameterNames");
13
+ var _utils = require("../utils");
14
+ /**
15
+ * Scenario level hooks: Before / After.
16
+ *
17
+ * before(async ({ page }) => {})
18
+ */
19
+
20
+ const scenarioHooks = [];
21
+ let scenarioHooksFixtures;
22
+ /**
23
+ * Returns Before() / After() functions.
24
+ */
25
+ function scenarioHookFactory(type) {
26
+ return (...args) => {
27
+ addHook({
28
+ type,
29
+ options: getOptionsFromArgs(args),
30
+ fn: getFnFromArgs(args)
31
+ });
32
+ };
33
+ }
34
+ function hasScenarioHooks() {
35
+ return scenarioHooks.length > 0;
36
+ }
37
+ // eslint-disable-next-line complexity
38
+ async function runScenarioHooks(type, fixtures) {
39
+ let error;
40
+ for (const hook of scenarioHooks) {
41
+ if (hook.type !== type) {
42
+ continue;
43
+ }
44
+ if (hook.tagsExpression && !hook.tagsExpression.evaluate(fixtures.$tags)) {
45
+ continue;
46
+ }
47
+ const {
48
+ timeout
49
+ } = hook.options;
50
+ try {
51
+ await (0, _utils.callWithTimeout)(() => hook.fn.call(fixtures.$bddWorld, fixtures), timeout, `${type} hook timeout (${timeout} ms)`);
52
+ } catch (e) {
53
+ if (type === 'before') {
54
+ throw e;
55
+ }
56
+ if (!error) {
57
+ error = e;
58
+ }
59
+ }
60
+ }
61
+ if (error) {
62
+ throw error;
63
+ }
64
+ }
65
+ function getScenarioHooksFixtures() {
66
+ if (!scenarioHooksFixtures) {
67
+ const fixturesFakeObj = {
68
+ $bddWorld: null,
69
+ $tags: null,
70
+ $testInfo: null
71
+ };
72
+ const set = new Set();
73
+ scenarioHooks.forEach(hook => {
74
+ (0, _fixtureParameterNames.fixtureParameterNames)(hook.fn).filter(fixtureName => !Object.prototype.hasOwnProperty.call(fixturesFakeObj, fixtureName)).forEach(fixtureName => set.add(fixtureName));
75
+ });
76
+ scenarioHooksFixtures = [...set];
77
+ }
78
+ return scenarioHooksFixtures;
79
+ }
80
+ function getOptionsFromArgs(args) {
81
+ if (typeof args[0] === 'string') {
82
+ return {
83
+ tags: args[0]
84
+ };
85
+ }
86
+ if (typeof args[0] === 'object') {
87
+ return args[0];
88
+ }
89
+ return {};
90
+ }
91
+ function getFnFromArgs(args) {
92
+ return args.length === 1 ? args[0] : args[1];
93
+ }
94
+ function setTagsExpression(hook) {
95
+ if (hook.options.tags) {
96
+ hook.tagsExpression = (0, _tagExpressions.default)(hook.options.tags);
97
+ }
98
+ }
99
+ function addHook(hook) {
100
+ setTagsExpression(hook);
101
+ if (hook.type === 'before') {
102
+ scenarioHooks.push(hook);
103
+ } else {
104
+ // 'after' hooks run in reverse order
105
+ scenarioHooks.unshift(hook);
106
+ }
107
+ }