@zohodesk/testinglibrary 0.1.6 → 0.1.7
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.
- package/.eslintrc.js +5 -1
- package/build/bdd-framework/cli/commands/env.js +1 -1
- package/build/bdd-framework/cli/commands/test.js +9 -3
- package/build/bdd-framework/config/env.js +2 -1
- package/build/bdd-framework/config/lang.js +14 -0
- package/build/bdd-framework/cucumber/loadSteps.js +8 -3
- package/build/bdd-framework/decorators.js +2 -2
- package/build/bdd-framework/gen/fixtures.js +48 -0
- package/build/bdd-framework/gen/formatter.js +57 -10
- package/build/bdd-framework/gen/i18n.js +6 -2
- package/build/bdd-framework/gen/index.js +7 -6
- package/build/bdd-framework/gen/testFile.js +105 -39
- package/build/bdd-framework/gen/testNode.js +16 -3
- package/build/bdd-framework/gen/testPoms.js +18 -8
- package/build/bdd-framework/hooks/scenario.js +107 -0
- package/build/bdd-framework/hooks/worker.js +83 -0
- package/build/bdd-framework/playwright/fixtureParameterNames.js +24 -8
- package/build/bdd-framework/playwright/getLocationInFile.js +13 -7
- package/build/bdd-framework/playwright/testTypeImpl.js +11 -7
- package/build/bdd-framework/playwright/transform.js +6 -2
- package/build/bdd-framework/run/StepInvoker.js +73 -0
- package/build/bdd-framework/run/bddFixtures.js +118 -55
- package/build/bdd-framework/run/bddWorld.js +24 -36
- package/build/bdd-framework/snippets/index.js +3 -1
- package/build/bdd-framework/snippets/snippetSyntax.js +3 -1
- package/build/bdd-framework/stepDefinitions/createBdd.js +28 -11
- package/build/bdd-framework/stepDefinitions/decorators/{poms.js → class.js} +7 -3
- package/build/bdd-framework/stepDefinitions/decorators/steps.js +8 -2
- package/build/bdd-framework/stepDefinitions/defineStep.js +2 -1
- package/build/bdd-framework/utils/exit.js +14 -4
- package/build/bdd-framework/utils/index.js +27 -1
- package/build/bdd-framework/utils/logger.js +3 -1
- package/build/core/playwright/index.js +12 -3
- package/build/core/playwright/report-generator.js +2 -1
- package/build/core/playwright/setup/config-creator.js +5 -0
- package/build/core/playwright/tag-processor.js +6 -2
- package/build/setup-folder-structure/reportEnhancement/addonScript.html +25 -0
- package/build/setup-folder-structure/reportEnhancement/reportAlteration.js +25 -0
- package/changelog.md +10 -0
- package/npm-shrinkwrap.json +1 -1
- package/package.json +1 -1
- package/build/bdd-framework/cucumber/gherkin.d.ts +0 -45
- package/build/bdd-framework/gen/poms.js +0 -46
- package/build/bdd-framework/stepDefinitions/createDecorators.js +0 -108
package/.eslintrc.js
CHANGED
|
@@ -22,6 +22,10 @@ module.exports = {
|
|
|
22
22
|
"sourceType": "module"
|
|
23
23
|
},
|
|
24
24
|
"rules": {
|
|
25
|
-
"indent": ["error", 2, { "SwitchCase": 1 }]
|
|
25
|
+
"indent": ["error", 2, { "SwitchCase": 1 }],
|
|
26
|
+
"no-empty-pattern": "off",
|
|
27
|
+
"comma-dangle": ["error", "never"],
|
|
28
|
+
"curly": ["error"],
|
|
29
|
+
"brace-style": "error"
|
|
26
30
|
}
|
|
27
31
|
}
|
|
@@ -33,7 +33,7 @@ function showPackageVersion(packageName) {
|
|
|
33
33
|
* to aneble using directly from /dist in tests.
|
|
34
34
|
*/
|
|
35
35
|
function getOwnVersion() {
|
|
36
|
-
return '5.
|
|
36
|
+
return '5.6.0';
|
|
37
37
|
}
|
|
38
38
|
function showPlaywrightConfigPath(cliConfigPath) {
|
|
39
39
|
const resolvedConfigFile = (0, _loadConfig.resolveConfigFile)(cliConfigPath);
|
|
@@ -30,8 +30,12 @@ function readConfigsFromEnv() {
|
|
|
30
30
|
}
|
|
31
31
|
function mergeCliOptions(configs, opts) {
|
|
32
32
|
configs.forEach(config => {
|
|
33
|
-
if ('tags' in opts)
|
|
34
|
-
|
|
33
|
+
if ('tags' in opts) {
|
|
34
|
+
config.tags = opts.tags;
|
|
35
|
+
}
|
|
36
|
+
if ('verbose' in opts) {
|
|
37
|
+
config.verbose = Boolean(opts.verbose);
|
|
38
|
+
}
|
|
35
39
|
});
|
|
36
40
|
}
|
|
37
41
|
function assertConfigsCount(configs) {
|
|
@@ -54,5 +58,7 @@ async function runInWorker(config) {
|
|
|
54
58
|
}
|
|
55
59
|
});
|
|
56
60
|
const [exitCode] = await (0, _events.once)(worker, 'exit');
|
|
57
|
-
if (exitCode)
|
|
61
|
+
if (exitCode) {
|
|
62
|
+
(0, _exit.exit)();
|
|
63
|
+
}
|
|
58
64
|
}
|
|
@@ -34,7 +34,8 @@ function getConfigFromEnv(outputDir) {
|
|
|
34
34
|
outputDir = _path.default.resolve(outputDir);
|
|
35
35
|
const config = envConfigs[outputDir];
|
|
36
36
|
if (!config) {
|
|
37
|
-
|
|
37
|
+
// exit(`Config not found for outputDir: "${outputDir}".`, `Available dirs: ${Object.keys(envConfigs).join('\n')}`);
|
|
38
|
+
return {};
|
|
38
39
|
}
|
|
39
40
|
return config;
|
|
40
41
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.LANG_EN = void 0;
|
|
7
|
+
exports.isEnglish = isEnglish;
|
|
8
|
+
/**
|
|
9
|
+
* Helpers for Cucumber language option.
|
|
10
|
+
*/
|
|
11
|
+
const LANG_EN = exports.LANG_EN = 'en';
|
|
12
|
+
function isEnglish(lang) {
|
|
13
|
+
return !lang || lang === LANG_EN;
|
|
14
|
+
}
|
|
@@ -25,9 +25,14 @@ function findStepDefinition(supportCodeLibrary, stepText, file) {
|
|
|
25
25
|
const matchedSteps = supportCodeLibrary.stepDefinitions.filter(step => {
|
|
26
26
|
return step.matchesStepName(stepText);
|
|
27
27
|
});
|
|
28
|
-
if (matchedSteps.length === 0)
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
if (matchedSteps.length === 0) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (matchedSteps.length > 1) {
|
|
32
|
+
(0, _exit.exit)([`Multiple step definitions matched for text: "${stepText}" (${file})`,
|
|
33
|
+
// todo: print location of every step definition (as in cucumber)
|
|
34
|
+
...matchedSteps.map(s => ` ${s.pattern}`)].join('\n'));
|
|
35
|
+
}
|
|
31
36
|
return matchedSteps[0];
|
|
32
37
|
}
|
|
33
38
|
function hasTsNodeRegister(runConfiguration) {
|
|
@@ -6,11 +6,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
Object.defineProperty(exports, "Fixture", {
|
|
7
7
|
enumerable: true,
|
|
8
8
|
get: function () {
|
|
9
|
-
return
|
|
9
|
+
return _class.Fixture;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
12
|
exports.When = exports.Then = exports.Step = exports.Given = void 0;
|
|
13
|
-
var
|
|
13
|
+
var _class = require("./stepDefinitions/decorators/class");
|
|
14
14
|
var _steps = require("./stepDefinitions/decorators/steps");
|
|
15
15
|
const Given = exports.Given = (0, _steps.createStepDecorator)('Given');
|
|
16
16
|
const When = exports.When = (0, _steps.createStepDecorator)('When');
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.extractFixtureNames = extractFixtureNames;
|
|
7
|
+
exports.extractFixtureNamesFromFnBodyMemo = extractFixtureNamesFromFnBodyMemo;
|
|
8
|
+
var _fixtureParameterNames = require("../playwright/fixtureParameterNames");
|
|
9
|
+
var _bddFixtures = require("../run/bddFixtures");
|
|
10
|
+
var _exit = require("../utils/exit");
|
|
11
|
+
const bodyFixturesSymbol = Symbol('bodyFixtures');
|
|
12
|
+
/**
|
|
13
|
+
* This function is used for playwright-style steps and decorators.
|
|
14
|
+
* It extracts fixtures names from first parameter of function
|
|
15
|
+
* using Playwright's helper.
|
|
16
|
+
*/
|
|
17
|
+
function extractFixtureNames(fn) {
|
|
18
|
+
return (0, _fixtureParameterNames.fixtureParameterNames)(fn).filter(name => !(0, _bddFixtures.isBddAutoInjectFixture)(name));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* This function is used for cucumber-style steps.
|
|
22
|
+
* It looks for `this.useFixture('xxx')` entries in function body
|
|
23
|
+
* and extracts fixtures names from it.
|
|
24
|
+
*/
|
|
25
|
+
function extractFixtureNamesFromFnBodyMemo(fn) {
|
|
26
|
+
if (typeof fn !== 'function') {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
const fnWithFixtures = fn;
|
|
30
|
+
if (!fnWithFixtures[bodyFixturesSymbol]) {
|
|
31
|
+
fnWithFixtures[bodyFixturesSymbol] = extractFixtureNamesFromFnBody(fn).filter(name => !(0, _bddFixtures.isBddAutoInjectFixture)(name));
|
|
32
|
+
}
|
|
33
|
+
return fnWithFixtures[bodyFixturesSymbol];
|
|
34
|
+
}
|
|
35
|
+
function extractFixtureNamesFromFnBody(fn) {
|
|
36
|
+
const matches = fn.toString().matchAll(/this\.useFixture\((.+)\)/gi) || [];
|
|
37
|
+
return [...matches].map(match => getFixtureName(match[1]));
|
|
38
|
+
}
|
|
39
|
+
function getFixtureName(arg) {
|
|
40
|
+
if (!/^['"`]/.test(arg)) {
|
|
41
|
+
// todo: log file location with incorrect useFixture
|
|
42
|
+
(0, _exit.exit)('this.useFixture() can accept only static string as an argument.');
|
|
43
|
+
}
|
|
44
|
+
if (arg.startsWith('`') && arg.includes('${')) {
|
|
45
|
+
(0, _exit.exit)('this.useFixture() can accept only static string as an argument.');
|
|
46
|
+
}
|
|
47
|
+
return arg.replace(/['"`]/g, '');
|
|
48
|
+
}
|
|
@@ -18,14 +18,20 @@ class Formatter {
|
|
|
18
18
|
fileHeader(uri, importTestFrom) {
|
|
19
19
|
const file = (importTestFrom === null || importTestFrom === void 0 ? void 0 : importTestFrom.file) || '@zohodesk/testinglibrary';
|
|
20
20
|
let varName = (importTestFrom === null || importTestFrom === void 0 ? void 0 : importTestFrom.varName) || 'test';
|
|
21
|
-
if (varName !== 'test')
|
|
21
|
+
if (varName !== 'test') {
|
|
22
|
+
varName = `${varName} as test`;
|
|
23
|
+
}
|
|
22
24
|
return [`/** Generated from: ${uri} */`,
|
|
25
|
+
// prettier-ignore
|
|
23
26
|
// this.quoted() is not possible for 'import from' as backticks not parsed
|
|
24
27
|
`import { ${varName} } from ${JSON.stringify(file)};`, ''];
|
|
25
28
|
}
|
|
26
29
|
suite(node, children) {
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
const firstLine = `test.describe${this.getSubFn(node)}(${this.quoted(node.title)}, () => {`;
|
|
31
|
+
if (!children.length) {
|
|
32
|
+
return [`${firstLine}});`, ''];
|
|
33
|
+
}
|
|
34
|
+
return [firstLine, '', ...children.map(indent), `});`, ''];
|
|
29
35
|
}
|
|
30
36
|
beforeEach(fixtures, children) {
|
|
31
37
|
const fixturesStr = [...fixtures].join(', ');
|
|
@@ -34,8 +40,12 @@ class Formatter {
|
|
|
34
40
|
}
|
|
35
41
|
test(node, fixtures, children) {
|
|
36
42
|
const fixturesStr = [...fixtures].join(', ');
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
const title = this.quoted([node.title, ...node.tags].join(' '));
|
|
44
|
+
const firstLine = `test${this.getSubFn(node)}(${title}, async ({ ${fixturesStr} }) => {`;
|
|
45
|
+
if (!children.length) {
|
|
46
|
+
return [`${firstLine}});`, ''];
|
|
47
|
+
}
|
|
48
|
+
return [firstLine, ...children.map(indent), `});`, ''];
|
|
39
49
|
}
|
|
40
50
|
// eslint-disable-next-line max-params
|
|
41
51
|
step(keyword, text, argument, fixtureNames = []) {
|
|
@@ -49,25 +59,62 @@ class Formatter {
|
|
|
49
59
|
return `// missing step: ${keyword}(${this.quoted(text)});`;
|
|
50
60
|
}
|
|
51
61
|
useFixtures(fixtures) {
|
|
52
|
-
return fixtures.length > 0 ? ['// == technical section ==',
|
|
62
|
+
return fixtures.length > 0 ? ['// == technical section ==',
|
|
63
|
+
// prettier-ignore
|
|
64
|
+
'', 'test.use({', ...fixtures.map(indent), '});'] : [];
|
|
53
65
|
}
|
|
54
66
|
testFixture() {
|
|
55
67
|
return ['$test: ({}, use) => use(test),'];
|
|
56
68
|
}
|
|
69
|
+
bddWorldFixtures() {
|
|
70
|
+
const fixturesObj = {
|
|
71
|
+
page: null,
|
|
72
|
+
context: null,
|
|
73
|
+
browser: null,
|
|
74
|
+
browserName: null,
|
|
75
|
+
request: null
|
|
76
|
+
};
|
|
77
|
+
const fixtures = Object.keys(fixturesObj).join(', ');
|
|
78
|
+
return [`$bddWorldFixtures: ({ ${fixtures} }, use) => use({ ${fixtures} }),`];
|
|
79
|
+
}
|
|
57
80
|
tagsFixture(testNodes) {
|
|
58
81
|
const lines = testNodes.filter(node => node.tags.length).map(node => {
|
|
59
82
|
// remove first parent as it is the same for all tests: root suite
|
|
60
|
-
const key = node.titlePath.slice(1).join(TAGS_FIXTURE_TEST_KEY_SEPARATOR)
|
|
83
|
+
const key = `${node.titlePath.slice(1).join(TAGS_FIXTURE_TEST_KEY_SEPARATOR)} ${node.tags.join(" ")}`;
|
|
61
84
|
return `${JSON.stringify(key)}: ${JSON.stringify(node.tags)},`;
|
|
62
85
|
});
|
|
63
86
|
return lines.length > 0 ? ['$tags: ({}, use, testInfo) => use({', ...lines.map(indent),
|
|
64
87
|
// .slice(2) -> b/c we remove filename and root suite title
|
|
65
88
|
`}[testInfo.titlePath.slice(2).join(${JSON.stringify(TAGS_FIXTURE_TEST_KEY_SEPARATOR)})] || []),`] : [];
|
|
66
89
|
}
|
|
90
|
+
scenarioHookFixtures(fixtureNames) {
|
|
91
|
+
if (!fixtureNames.length) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
const fixtures = fixtureNames.join(', ');
|
|
95
|
+
return [`$scenarioHookFixtures: ({ ${fixtures} }, use) => use({ ${fixtures} }),`];
|
|
96
|
+
}
|
|
97
|
+
workerHookFixtures(fixtureNames) {
|
|
98
|
+
if (!fixtureNames.length) {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
const fixtures = fixtureNames.join(', ');
|
|
102
|
+
const scope = this.quoted('worker');
|
|
103
|
+
return [`$workerHookFixtures: [({ ${fixtures} }, use) => use({ ${fixtures} }), { scope: ${scope} }],`];
|
|
104
|
+
}
|
|
105
|
+
langFixture(lang) {
|
|
106
|
+
return [`$lang: ({}, use) => use(${this.quoted(lang)}),`];
|
|
107
|
+
}
|
|
67
108
|
getSubFn(node) {
|
|
68
|
-
if (node.flags.only)
|
|
69
|
-
|
|
70
|
-
|
|
109
|
+
if (node.flags.only) {
|
|
110
|
+
return '.only';
|
|
111
|
+
}
|
|
112
|
+
if (node.flags.skip) {
|
|
113
|
+
return '.skip';
|
|
114
|
+
}
|
|
115
|
+
if (node.flags.fixme) {
|
|
116
|
+
return '.fixme';
|
|
117
|
+
}
|
|
71
118
|
return '';
|
|
72
119
|
}
|
|
73
120
|
/**
|
|
@@ -23,10 +23,14 @@ function getKeywordsMap(language) {
|
|
|
23
23
|
function handleKeyword(enKeyword, origMap, targetMap) {
|
|
24
24
|
const nativeKeywords = origMap[enKeyword];
|
|
25
25
|
// Array.isArray converts to any[]
|
|
26
|
-
if (typeof nativeKeywords === 'string')
|
|
26
|
+
if (typeof nativeKeywords === 'string') {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
27
29
|
nativeKeywords.forEach(nativeKeyword => {
|
|
28
30
|
nativeKeyword = nativeKeyword.trim();
|
|
29
|
-
if (!nativeKeyword || nativeKeyword === '*')
|
|
31
|
+
if (!nativeKeyword || nativeKeyword === '*') {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
30
34
|
targetMap.set(nativeKeyword, capitalizeFirstLetter(enKeyword));
|
|
31
35
|
});
|
|
32
36
|
}
|
|
@@ -20,6 +20,7 @@ var _dir = require("../config/dir");
|
|
|
20
20
|
var _logger = require("../utils/logger");
|
|
21
21
|
var _tagExpressions = _interopRequireDefault(require("@cucumber/tag-expressions"));
|
|
22
22
|
var _exit = require("../utils/exit");
|
|
23
|
+
var _createBdd = require("../stepDefinitions/createBdd");
|
|
23
24
|
/**
|
|
24
25
|
* Generate playwright test files from Gherkin documents.
|
|
25
26
|
*/
|
|
@@ -38,7 +39,9 @@ class TestFilesGenerator {
|
|
|
38
39
|
this.logger = new _logger.Logger({
|
|
39
40
|
verbose: config.verbose
|
|
40
41
|
});
|
|
41
|
-
if (config.tags)
|
|
42
|
+
if (config.tags) {
|
|
43
|
+
this.tagsExpression = (0, _tagExpressions.default)(config.tags);
|
|
44
|
+
}
|
|
42
45
|
}
|
|
43
46
|
async generate() {
|
|
44
47
|
await (0, _exit.withExitHandler)(async () => {
|
|
@@ -46,7 +49,7 @@ class TestFilesGenerator {
|
|
|
46
49
|
await Promise.all([this.loadFeatures(), this.loadSteps()]);
|
|
47
50
|
this.buildFiles();
|
|
48
51
|
await this.checkUndefinedSteps();
|
|
49
|
-
this.
|
|
52
|
+
this.checkImportTestFrom();
|
|
50
53
|
await this.clearOutputDir();
|
|
51
54
|
await this.saveFiles();
|
|
52
55
|
});
|
|
@@ -133,10 +136,8 @@ class TestFilesGenerator {
|
|
|
133
136
|
(0, _exit.exit)();
|
|
134
137
|
}
|
|
135
138
|
}
|
|
136
|
-
|
|
137
|
-
if (this.config.importTestFrom)
|
|
138
|
-
const hasCustomTest = this.files.some(file => file.hasCustomTest);
|
|
139
|
-
if (hasCustomTest) {
|
|
139
|
+
checkImportTestFrom() {
|
|
140
|
+
if (_createBdd.hasCustomTest && !this.config.importTestFrom) {
|
|
140
141
|
(0, _exit.exit)(`When using custom "test" function in createBdd() you should`, `set "importTestFrom" config option that points to file exporting custom test.`);
|
|
141
142
|
}
|
|
142
143
|
}
|
|
@@ -10,13 +10,16 @@ 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");
|
|
19
|
+
var _fixtures = require("./fixtures");
|
|
20
|
+
var _scenario = require("../hooks/scenario");
|
|
21
|
+
var _worker = require("../hooks/worker");
|
|
22
|
+
var _lang = require("../config/lang");
|
|
20
23
|
/**
|
|
21
24
|
* Generate test code.
|
|
22
25
|
*/
|
|
@@ -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)
|
|
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) ||
|
|
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(),
|
|
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))
|
|
64
|
-
|
|
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.
|
|
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)
|
|
94
|
+
if (!importTestFrom) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
82
97
|
const {
|
|
83
98
|
file,
|
|
84
99
|
varName
|
|
@@ -90,13 +105,15 @@ 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)
|
|
114
|
+
if (!feature) {
|
|
115
|
+
throw new Error(`Document without feature.`);
|
|
116
|
+
}
|
|
100
117
|
return this.getSuite(feature);
|
|
101
118
|
}
|
|
102
119
|
/**
|
|
@@ -104,16 +121,23 @@ class TestFile {
|
|
|
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)
|
|
115
|
-
|
|
116
|
-
|
|
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) {
|
|
@@ -138,10 +162,13 @@ class TestFile {
|
|
|
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);
|
|
@@ -159,7 +186,12 @@ class TestFile {
|
|
|
159
186
|
name: title,
|
|
160
187
|
tags: examples.tags
|
|
161
188
|
}, parent);
|
|
162
|
-
if (this.skipByTagsExpression(node))
|
|
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,
|
|
@@ -172,7 +204,12 @@ class TestFile {
|
|
|
172
204
|
*/
|
|
173
205
|
getTest(scenario, parent) {
|
|
174
206
|
const node = new _testNode.TestNode(scenario, parent);
|
|
175
|
-
if (this.skipByTagsExpression(node))
|
|
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,
|
|
@@ -242,26 +279,27 @@ class TestFile {
|
|
|
242
279
|
language: this.language,
|
|
243
280
|
previousKeywordType
|
|
244
281
|
});
|
|
245
|
-
|
|
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(
|
|
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)
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (!(0, _stepConfig.isPlaywrightStyle)(stepConfig))
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const
|
|
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)
|
|
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
|
-
|
|
296
|
-
const
|
|
297
|
-
const enKeyword =
|
|
298
|
-
if (!enKeyword)
|
|
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)
|
|
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() :
|
|
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
|
-
|
|
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);
|
|
@@ -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
|
-
|
|
38
|
-
if (tag === '@
|
|
39
|
-
|
|
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;
|