codeceptjs 3.3.8-beta.1 → 3.4.0-beta.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.
- package/CHANGELOG.md +47 -0
- package/README.md +31 -32
- package/docs/advanced.md +48 -24
- package/docs/basics.md +115 -40
- package/docs/best.md +2 -2
- package/docs/build/ApiDataFactory.js +6 -6
- package/docs/build/Appium.js +2 -19
- package/docs/build/FileSystem.js +2 -2
- package/docs/build/GraphQLDataFactory.js +2 -2
- package/docs/build/Playwright.js +3 -2
- package/docs/build/TestCafe.js +4 -4
- package/docs/build/WebDriver.js +29 -164
- package/docs/helpers/ApiDataFactory.md +6 -6
- package/docs/helpers/FileSystem.md +2 -2
- package/docs/helpers/GraphQLDataFactory.md +2 -2
- package/docs/helpers/Playwright.md +2 -1
- package/docs/index.md +1 -1
- package/docs/plugins.md +73 -48
- package/docs/reports.md +0 -56
- package/docs/typescript.md +2 -8
- package/lib/actor.js +2 -1
- package/lib/cli.js +3 -3
- package/lib/codecept.js +2 -1
- package/lib/command/generate.js +3 -1
- package/lib/command/gherkin/snippets.js +8 -4
- package/lib/command/init.js +0 -8
- package/lib/command/run-workers.js +3 -6
- package/lib/command/utils.js +0 -10
- package/lib/command/workers/runTests.js +2 -2
- package/lib/config.js +5 -1
- package/lib/helper/ApiDataFactory.js +7 -7
- package/lib/helper/Appium.js +2 -19
- package/lib/helper/FileSystem.js +3 -3
- package/lib/helper/GraphQL.js +1 -1
- package/lib/helper/GraphQLDataFactory.js +3 -3
- package/lib/helper/JSONResponse.js +1 -1
- package/lib/helper/Mochawesome.js +1 -1
- package/lib/helper/Nightmare.js +1 -1
- package/lib/helper/Playwright.js +4 -3
- package/lib/helper/Protractor.js +1 -1
- package/lib/helper/Puppeteer.js +1 -1
- package/lib/helper/REST.js +1 -1
- package/lib/helper/TestCafe.js +5 -5
- package/lib/helper/WebDriver.js +30 -165
- package/lib/helper.js +0 -2
- package/lib/interfaces/bdd.js +1 -1
- package/lib/interfaces/featureConfig.js +1 -0
- package/lib/interfaces/gherkin.js +38 -25
- package/lib/listener/exit.js +2 -2
- package/lib/listener/retry.js +67 -0
- package/lib/listener/steps.js +1 -1
- package/lib/listener/timeout.js +47 -10
- package/lib/mochaFactory.js +3 -3
- package/lib/plugin/allure.js +14 -323
- package/lib/plugin/fakerTransform.js +2 -2
- package/lib/recorder.js +1 -1
- package/lib/scenario.js +25 -18
- package/lib/utils.js +6 -0
- package/lib/workers.js +4 -7
- package/package.json +13 -17
- package/typings/index.d.ts +66 -1
- package/typings/promiseBasedTypes.d.ts +12 -12
- package/typings/types.d.ts +95 -262
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const
|
|
1
|
+
const Gherkin = require('@cucumber/gherkin');
|
|
2
|
+
const Messages = require('@cucumber/messages');
|
|
2
3
|
const { Context, Suite, Test } = require('mocha');
|
|
3
4
|
|
|
4
5
|
const { matchStep } = require('./bdd');
|
|
@@ -8,7 +9,10 @@ const Step = require('../step');
|
|
|
8
9
|
const DataTableArgument = require('../data/dataTableArgument');
|
|
9
10
|
const transform = require('../transform');
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
+
const uuidFn = Messages.IdGenerator.uuid();
|
|
13
|
+
const builder = new Gherkin.AstBuilder(uuidFn);
|
|
14
|
+
const matcher = new Gherkin.GherkinClassicTokenMatcher();
|
|
15
|
+
const parser = new Gherkin.Parser(builder, matcher);
|
|
12
16
|
parser.stopAtFirstError = false;
|
|
13
17
|
|
|
14
18
|
module.exports = (text, file) => {
|
|
@@ -46,14 +50,20 @@ module.exports = (text, file) => {
|
|
|
46
50
|
step.metaStep = metaStep;
|
|
47
51
|
};
|
|
48
52
|
const fn = matchStep(step.text);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
|
|
54
|
+
if (step.dataTable) {
|
|
55
|
+
fn.params.push({
|
|
56
|
+
...step.dataTable,
|
|
57
|
+
parse: () => new DataTableArgument(step.dataTable),
|
|
58
|
+
});
|
|
59
|
+
metaStep.comment = `\n${transformTable(step.dataTable)}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (step.docString) {
|
|
63
|
+
fn.params.push(step.docString);
|
|
64
|
+
metaStep.comment = `\n"""\n${step.docString.content}\n"""`;
|
|
56
65
|
}
|
|
66
|
+
|
|
57
67
|
step.startTime = Date.now();
|
|
58
68
|
step.match = fn.line;
|
|
59
69
|
event.emit(event.bddStep.before, step);
|
|
@@ -74,15 +84,15 @@ module.exports = (text, file) => {
|
|
|
74
84
|
};
|
|
75
85
|
|
|
76
86
|
for (const child of ast.feature.children) {
|
|
77
|
-
if (child.
|
|
78
|
-
suite.beforeEach('Before', scenario.injected(async () => runSteps(child.steps), suite, 'before'));
|
|
87
|
+
if (child.background) {
|
|
88
|
+
suite.beforeEach('Before', scenario.injected(async () => runSteps(child.background.steps), suite, 'before'));
|
|
79
89
|
continue;
|
|
80
90
|
}
|
|
81
|
-
if (child.
|
|
82
|
-
for (const examples of child.examples) {
|
|
91
|
+
if (child.scenario && child.scenario.keyword === 'Scenario Outline') {
|
|
92
|
+
for (const examples of child.scenario.examples) {
|
|
83
93
|
const fields = examples.tableHeader.cells.map(c => c.value);
|
|
84
94
|
for (const example of examples.tableBody) {
|
|
85
|
-
let exampleSteps = [...child.steps];
|
|
95
|
+
let exampleSteps = [...child.scenario.steps];
|
|
86
96
|
const current = {};
|
|
87
97
|
for (const index in example.cells) {
|
|
88
98
|
const placeholder = fields[index];
|
|
@@ -95,8 +105,8 @@ module.exports = (text, file) => {
|
|
|
95
105
|
return step;
|
|
96
106
|
});
|
|
97
107
|
}
|
|
98
|
-
const tags = child.tags.map(t => t.name).concat(examples.tags.map(t => t.name));
|
|
99
|
-
const title = `${child.name} ${JSON.stringify(current)} ${tags.join(' ')}`.trim();
|
|
108
|
+
const tags = child.scenario.tags.map(t => t.name).concat(examples.tags.map(t => t.name));
|
|
109
|
+
const title = `${child.scenario.name} ${JSON.stringify(current)} ${tags.join(' ')}`.trim();
|
|
100
110
|
const test = new Test(title, async () => runSteps(addExampleInTable(exampleSteps, current)));
|
|
101
111
|
test.tags = suite.tags.concat(tags);
|
|
102
112
|
test.file = file;
|
|
@@ -105,12 +115,15 @@ module.exports = (text, file) => {
|
|
|
105
115
|
}
|
|
106
116
|
continue;
|
|
107
117
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
|
|
119
|
+
if (child.scenario) {
|
|
120
|
+
const tags = child.scenario.tags.map(t => t.name);
|
|
121
|
+
const title = `${child.scenario.name} ${tags.join(' ')}`.trim();
|
|
122
|
+
const test = new Test(title, async () => runSteps(child.scenario.steps));
|
|
123
|
+
test.tags = suite.tags.concat(tags);
|
|
124
|
+
test.file = file;
|
|
125
|
+
suite.addTest(scenario.test(test));
|
|
126
|
+
}
|
|
114
127
|
}
|
|
115
128
|
|
|
116
129
|
return suite;
|
|
@@ -130,9 +143,9 @@ function addExampleInTable(exampleSteps, placeholders) {
|
|
|
130
143
|
for (const placeholder in placeholders) {
|
|
131
144
|
steps.map((step) => {
|
|
132
145
|
step = { ...step };
|
|
133
|
-
if (step.
|
|
134
|
-
for (const id in step.
|
|
135
|
-
const cells = step.
|
|
146
|
+
if (step.dataTable) {
|
|
147
|
+
for (const id in step.dataTable.rows) {
|
|
148
|
+
const cells = step.dataTable.rows[id].cells;
|
|
136
149
|
cells.map(c => (c.value = c.value.replace(`<${placeholder}>`, placeholders[placeholder])));
|
|
137
150
|
}
|
|
138
151
|
}
|
package/lib/listener/exit.js
CHANGED
|
@@ -6,7 +6,7 @@ module.exports = function () {
|
|
|
6
6
|
event.dispatcher.on(event.test.failed, (testOrSuite) => {
|
|
7
7
|
// NOTE When an error happens in one of the hooks (BeforeAll/BeforeEach...) the event object
|
|
8
8
|
// is a suite and not a test
|
|
9
|
-
const id = testOrSuite.
|
|
9
|
+
const id = testOrSuite.uid || (testOrSuite.ctx && testOrSuite.ctx.test.uid) || 'empty';
|
|
10
10
|
failedTests.push(id);
|
|
11
11
|
});
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ module.exports = function () {
|
|
|
14
14
|
event.dispatcher.on(event.test.passed, (testOrSuite) => {
|
|
15
15
|
// NOTE When an error happens in one of the hooks (BeforeAll/BeforeEach...) the event object
|
|
16
16
|
// is a suite and not a test
|
|
17
|
-
const id = testOrSuite.
|
|
17
|
+
const id = testOrSuite.uid || (testOrSuite.ctx && testOrSuite.ctx.test.uid) || 'empty';
|
|
18
18
|
failedTests = failedTests.filter(failed => id !== failed);
|
|
19
19
|
});
|
|
20
20
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const event = require('../event');
|
|
2
|
+
const output = require('../output');
|
|
3
|
+
const Config = require('../config');
|
|
4
|
+
const { isNotSet } = require('../utils');
|
|
5
|
+
|
|
6
|
+
const hooks = ['Before', 'After', 'BeforeSuite', 'AfterSuite'];
|
|
7
|
+
|
|
8
|
+
module.exports = function () {
|
|
9
|
+
event.dispatcher.on(event.suite.before, (suite) => {
|
|
10
|
+
let retryConfig = Config.get('retry');
|
|
11
|
+
if (!retryConfig) return;
|
|
12
|
+
|
|
13
|
+
if (Number.isInteger(+retryConfig)) {
|
|
14
|
+
// is number
|
|
15
|
+
const retryNum = +retryConfig;
|
|
16
|
+
output.log(`Retries: ${retryNum}`);
|
|
17
|
+
suite.retries(retryNum);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!Array.isArray(retryConfig)) {
|
|
22
|
+
retryConfig = [retryConfig];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
for (const config of retryConfig) {
|
|
26
|
+
if (config.grep) {
|
|
27
|
+
if (!suite.title.includes(config.grep)) continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
hooks.filter(hook => !!config[hook]).forEach((hook) => {
|
|
31
|
+
if (isNotSet(suite.opts[`retry${hook}`])) suite.opts[`retry${hook}`] = config[hook];
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (config.Feature) {
|
|
35
|
+
if (isNotSet(suite.retries())) suite.retries(config.Feature);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
output.log(`Retries: ${JSON.stringify(config)}`);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
event.dispatcher.on(event.test.before, (test) => {
|
|
43
|
+
let retryConfig = Config.get('retry');
|
|
44
|
+
if (!retryConfig) return;
|
|
45
|
+
|
|
46
|
+
if (Number.isInteger(+retryConfig)) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!Array.isArray(retryConfig)) {
|
|
51
|
+
retryConfig = [retryConfig];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
retryConfig = retryConfig.filter(config => !!config.Scenario);
|
|
55
|
+
|
|
56
|
+
for (const config of retryConfig) {
|
|
57
|
+
if (config.grep) {
|
|
58
|
+
if (!test.fullTitle().includes(config.grep)) continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (config.Scenario) {
|
|
62
|
+
if (isNotSet(test.retries())) test.retries(config.Scenario);
|
|
63
|
+
output.log(`Retries: ${config.Scenario}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
};
|
package/lib/listener/steps.js
CHANGED
|
@@ -81,6 +81,6 @@ module.exports = function () {
|
|
|
81
81
|
if (store.debugMode) return;
|
|
82
82
|
step.finishedAt = +new Date();
|
|
83
83
|
if (step.startedAt) step.duration = step.finishedAt - step.startedAt;
|
|
84
|
-
debug(`Step '${step}' finished; Duration: ${step.duration}ms`);
|
|
84
|
+
debug(`Step '${step}' finished; Duration: ${step.duration || 0}ms`);
|
|
85
85
|
});
|
|
86
86
|
};
|
package/lib/listener/timeout.js
CHANGED
|
@@ -7,7 +7,7 @@ const TIMEOUT_ORDER = require('../step').TIMEOUT_ORDER;
|
|
|
7
7
|
|
|
8
8
|
module.exports = function () {
|
|
9
9
|
let timeout;
|
|
10
|
-
let
|
|
10
|
+
let suiteTimeout = [];
|
|
11
11
|
let currentTest;
|
|
12
12
|
let currentTimeout;
|
|
13
13
|
|
|
@@ -17,21 +17,52 @@ module.exports = function () {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
event.dispatcher.on(event.suite.before, (suite) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
suiteTimeout = [];
|
|
21
|
+
let timeoutConfig = Config.get('timeout');
|
|
22
|
+
|
|
23
|
+
if (timeoutConfig) {
|
|
24
|
+
if (!Number.isNaN(+timeoutConfig)) {
|
|
25
|
+
checkForSeconds(timeoutConfig);
|
|
26
|
+
suiteTimeout.push(timeoutConfig);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!Array.isArray(timeoutConfig)) {
|
|
30
|
+
timeoutConfig = [timeoutConfig];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for (const config of timeoutConfig.filter(c => !!c.Feature)) {
|
|
34
|
+
if (config.grep) {
|
|
35
|
+
if (!suite.title.includes(config.grep)) continue;
|
|
36
|
+
}
|
|
37
|
+
suiteTimeout.push(config.Feature);
|
|
25
38
|
}
|
|
26
|
-
timeoutStack.push(globalTimeout);
|
|
27
39
|
}
|
|
28
|
-
|
|
29
|
-
|
|
40
|
+
|
|
41
|
+
if (suite.totalTimeout) suiteTimeout.push(suite.totalTimeout);
|
|
42
|
+
output.log(`Timeouts: ${suiteTimeout}`);
|
|
30
43
|
});
|
|
31
44
|
|
|
32
45
|
event.dispatcher.on(event.test.before, (test) => {
|
|
33
46
|
currentTest = test;
|
|
34
|
-
|
|
47
|
+
let testTimeout = null;
|
|
48
|
+
|
|
49
|
+
let timeoutConfig = Config.get('timeout');
|
|
50
|
+
|
|
51
|
+
if (typeof timeoutConfig === 'object' || Array.isArray(timeoutConfig)) {
|
|
52
|
+
if (!Array.isArray(timeoutConfig)) {
|
|
53
|
+
timeoutConfig = [timeoutConfig];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
for (const config of timeoutConfig.filter(c => !!c.Scenario)) {
|
|
57
|
+
console.log('Test Timeout', config, test.title.includes(config.grep));
|
|
58
|
+
if (config.grep) {
|
|
59
|
+
if (!test.title.includes(config.grep)) continue;
|
|
60
|
+
}
|
|
61
|
+
testTimeout = config.Scenario;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
timeout = test.totalTimeout || testTimeout || suiteTimeout[suiteTimeout.length - 1];
|
|
35
66
|
if (!timeout) return;
|
|
36
67
|
currentTimeout = timeout;
|
|
37
68
|
output.debug(`Test Timeout: ${timeout}s`);
|
|
@@ -70,3 +101,9 @@ module.exports = function () {
|
|
|
70
101
|
}
|
|
71
102
|
});
|
|
72
103
|
};
|
|
104
|
+
|
|
105
|
+
function checkForSeconds(timeout) {
|
|
106
|
+
if (timeout >= 1000) {
|
|
107
|
+
console.log(`Warning: Timeout was set to ${timeout}secs.\nGlobal timeout should be specified in seconds.`);
|
|
108
|
+
}
|
|
109
|
+
}
|
package/lib/mochaFactory.js
CHANGED
|
@@ -47,13 +47,13 @@ class MochaFactory {
|
|
|
47
47
|
let missingFeatureInFile = [];
|
|
48
48
|
const seenTests = [];
|
|
49
49
|
mocha.suite.eachTest(test => {
|
|
50
|
-
test.
|
|
50
|
+
test.uid = genTestId(test);
|
|
51
51
|
|
|
52
52
|
const name = test.fullTitle();
|
|
53
|
-
if (seenTests.includes(test.
|
|
53
|
+
if (seenTests.includes(test.uid)) {
|
|
54
54
|
dupes.push(name);
|
|
55
55
|
}
|
|
56
|
-
seenTests.push(test.
|
|
56
|
+
seenTests.push(test.uid);
|
|
57
57
|
|
|
58
58
|
if (name.slice(0, name.indexOf(':')) === '') {
|
|
59
59
|
missingFeatureInFile.push(test.file);
|
package/lib/plugin/allure.js
CHANGED
|
@@ -1,324 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
* Enables Allure reporter.
|
|
17
|
-
*
|
|
18
|
-
* #### Usage
|
|
19
|
-
*
|
|
20
|
-
* To start please install `allure-commandline` package (which requires Java 8)
|
|
21
|
-
*
|
|
22
|
-
* ```
|
|
23
|
-
* npm install -g allure-commandline --save-dev
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* Add this plugin to config file:
|
|
27
|
-
*
|
|
28
|
-
* ```js
|
|
29
|
-
* "plugins": {
|
|
30
|
-
* "allure": {}
|
|
31
|
-
* }
|
|
32
|
-
* ```
|
|
33
|
-
*
|
|
34
|
-
* Run tests with allure plugin enabled:
|
|
35
|
-
*
|
|
36
|
-
* ```
|
|
37
|
-
* npx codeceptjs run --plugins allure
|
|
38
|
-
* ```
|
|
39
|
-
*
|
|
40
|
-
* By default, allure reports are saved to `output` directory.
|
|
41
|
-
* Launch Allure server and see the report like on a screenshot above:
|
|
42
|
-
*
|
|
43
|
-
* ```
|
|
44
|
-
* allure serve output
|
|
45
|
-
* ```
|
|
46
|
-
*
|
|
47
|
-
* #### Configuration
|
|
48
|
-
*
|
|
49
|
-
* * `outputDir` - a directory where allure reports should be stored. Standard output directory is set by default.
|
|
50
|
-
* * `enableScreenshotDiffPlugin` - a boolean flag for add screenshot diff to report.
|
|
51
|
-
* To attach, tou need to attach three files to the report - "diff.png", "actual.png", "expected.png".
|
|
52
|
-
* See [Allure Screenshot Plugin](https://github.com/allure-framework/allure2/blob/master/plugins/screen-diff-plugin/README.md)
|
|
53
|
-
*
|
|
54
|
-
* #### Public API
|
|
55
|
-
*
|
|
56
|
-
* There are few public API methods which can be accessed from other plugins.
|
|
57
|
-
*
|
|
58
|
-
* ```js
|
|
59
|
-
* const allure = codeceptjs.container.plugins('allure');
|
|
60
|
-
* ```
|
|
61
|
-
*
|
|
62
|
-
* `allure` object has following methods:
|
|
63
|
-
*
|
|
64
|
-
* * `addAttachment(name, buffer, type)` - add an attachment to current test / suite
|
|
65
|
-
* * `addLabel(name, value)` - adds a label to current test
|
|
66
|
-
* * `addParameter(kind, name, value)` - adds a parameter to current test
|
|
67
|
-
* * `createStep(name, stepFunc)` - create a step, stepFunc could consist an attachment
|
|
68
|
-
* Example of usage:
|
|
69
|
-
* ```js
|
|
70
|
-
* allure.createStep('New created step', () => {
|
|
71
|
-
* allure.addAttachment(
|
|
72
|
-
* 'Request params',
|
|
73
|
-
* '{"clientId":123, "name":"Tom", "age":29}',
|
|
74
|
-
* 'application/json'
|
|
75
|
-
* );
|
|
76
|
-
* });
|
|
77
|
-
* ```
|
|
78
|
-
* 
|
|
79
|
-
* * `severity(value)` - adds severity label
|
|
80
|
-
* * `epic(value)` - adds epic label
|
|
81
|
-
* * `feature(value)` - adds feature label
|
|
82
|
-
* * `story(value)` - adds story label
|
|
83
|
-
* * `issue(value)` - adds issue label
|
|
84
|
-
* * `setDescription(description, type)` - sets a description
|
|
85
|
-
*
|
|
86
|
-
*/
|
|
87
|
-
module.exports = (config) => {
|
|
88
|
-
defaultConfig.outputDir = global.output_dir;
|
|
89
|
-
config = Object.assign(defaultConfig, config);
|
|
90
|
-
|
|
91
|
-
const plugin = {};
|
|
92
|
-
|
|
93
|
-
const reporter = new Allure();
|
|
94
|
-
reporter.setOptions({ targetDir: config.outputDir });
|
|
95
|
-
|
|
96
|
-
let currentMetaStep = [];
|
|
97
|
-
let currentStep;
|
|
98
|
-
|
|
99
|
-
reporter.pendingCase = function (testName, timestamp, opts = {}) {
|
|
100
|
-
reporter.startCase(testName, timestamp);
|
|
101
|
-
|
|
102
|
-
if (opts.description) plugin.setDescription(opts.description);
|
|
103
|
-
if (opts.severity) plugin.severity(opts.severity);
|
|
104
|
-
if (opts.severity) plugin.addLabel('tag', opts.severity);
|
|
105
|
-
|
|
106
|
-
reporter.endCase('pending', { message: opts.message || 'Test ignored' }, timestamp);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
plugin.addAttachment = (name, buffer, type) => {
|
|
110
|
-
reporter.addAttachment(name, buffer, type);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
plugin.setDescription = (description, type) => {
|
|
114
|
-
const currentTest = reporter.getCurrentTest();
|
|
115
|
-
if (currentTest) {
|
|
116
|
-
currentTest.setDescription(description, type);
|
|
117
|
-
} else {
|
|
118
|
-
logger.error(`The test is not run. Please use "setDescription" for events:
|
|
119
|
-
"test.start", "test.before", "test.after", "test.passed", "test.failed", "test.finish"`);
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
plugin.createStep = (name, stepFunc = () => { }) => {
|
|
124
|
-
let result;
|
|
125
|
-
let status = 'passed';
|
|
126
|
-
reporter.startStep(name);
|
|
127
|
-
try {
|
|
128
|
-
result = stepFunc(this.arguments);
|
|
129
|
-
} catch (error) {
|
|
130
|
-
status = 'broken';
|
|
131
|
-
throw error;
|
|
132
|
-
} finally {
|
|
133
|
-
if (!!result
|
|
134
|
-
&& (typeof result === 'object' || typeof result === 'function')
|
|
135
|
-
&& typeof result.then === 'function'
|
|
136
|
-
) {
|
|
137
|
-
result.then(() => reporter.endStep('passed'), () => reporter.endStep('broken'));
|
|
138
|
-
} else {
|
|
139
|
-
reporter.endStep(status);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return result;
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
plugin.createAttachment = (name, content, type) => {
|
|
146
|
-
if (typeof content === 'function') {
|
|
147
|
-
const attachmentName = name;
|
|
148
|
-
const buffer = content.apply(this, arguments);
|
|
149
|
-
return createAttachment(attachmentName, buffer, type);
|
|
150
|
-
} reporter.addAttachment(name, content, type);
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
plugin.severity = (severity) => {
|
|
154
|
-
plugin.addLabel('severity', severity);
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
plugin.epic = (epic) => {
|
|
158
|
-
plugin.addLabel('epic', epic);
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
plugin.feature = (feature) => {
|
|
162
|
-
plugin.addLabel('feature', feature);
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
plugin.story = (story) => {
|
|
166
|
-
plugin.addLabel('story', story);
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
plugin.issue = (issue) => {
|
|
170
|
-
plugin.addLabel('issue', issue);
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
plugin.addLabel = (name, value) => {
|
|
174
|
-
const currentTest = reporter.getCurrentTest();
|
|
175
|
-
if (currentTest) {
|
|
176
|
-
currentTest.addLabel(name, value);
|
|
177
|
-
} else {
|
|
178
|
-
logger.error(`The test is not run. Please use "addLabel" for events:
|
|
179
|
-
"test.start", "test.before", "test.after", "test.passed", "test.failed", "test.finish"`);
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
plugin.addParameter = (kind, name, value) => {
|
|
184
|
-
const currentTest = reporter.getCurrentTest();
|
|
185
|
-
if (currentTest) {
|
|
186
|
-
currentTest.addParameter(kind, name, value);
|
|
187
|
-
} else {
|
|
188
|
-
logger.error(`The test is not run. Please use "addParameter" for events:
|
|
189
|
-
"test.start", "test.before", "test.after", "test.passed", "test.failed", "test.finish"`);
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
event.dispatcher.on(event.suite.before, (suite) => {
|
|
194
|
-
reporter.startSuite(suite.fullTitle());
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
event.dispatcher.on(event.suite.before, (suite) => {
|
|
198
|
-
for (const test of suite.tests) {
|
|
199
|
-
if (test.pending) {
|
|
200
|
-
reporter.pendingCase(test.title, null, test.opts.skipInfo);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
event.dispatcher.on(event.suite.after, () => {
|
|
206
|
-
reporter.endSuite();
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
event.dispatcher.on(event.test.before, (test) => {
|
|
210
|
-
reporter.startCase(test.title);
|
|
211
|
-
if (config.enableScreenshotDiffPlugin) {
|
|
212
|
-
const currentTest = reporter.getCurrentTest();
|
|
213
|
-
currentTest.addLabel('testType', 'screenshotDiff');
|
|
214
|
-
}
|
|
215
|
-
currentStep = null;
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
event.dispatcher.on(event.test.started, (test) => {
|
|
219
|
-
const currentTest = reporter.getCurrentTest();
|
|
220
|
-
for (const tag of test.tags) {
|
|
221
|
-
currentTest.addLabel('tag', tag);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
event.dispatcher.on(event.test.failed, (test, err) => {
|
|
226
|
-
if (currentStep) reporter.endStep('failed');
|
|
227
|
-
if (currentMetaStep.length) {
|
|
228
|
-
currentMetaStep.forEach(() => reporter.endStep('failed'));
|
|
229
|
-
currentMetaStep = [];
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
err.message = err.message.replace(ansiRegExp(), '');
|
|
233
|
-
if (reporter.getCurrentTest()) {
|
|
234
|
-
reporter.endCase('failed', err);
|
|
235
|
-
} else {
|
|
236
|
-
// this means before suite failed, we should report this.
|
|
237
|
-
reporter.startCase(`BeforeSuite of suite ${reporter.getCurrentSuite().name} failed.`);
|
|
238
|
-
reporter.endCase('failed', err);
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
event.dispatcher.on(event.test.passed, () => {
|
|
243
|
-
if (currentStep) reporter.endStep('passed');
|
|
244
|
-
if (currentMetaStep.length) {
|
|
245
|
-
currentMetaStep.forEach(() => reporter.endStep('passed'));
|
|
246
|
-
currentMetaStep = [];
|
|
247
|
-
}
|
|
248
|
-
reporter.endCase('passed');
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
event.dispatcher.on(event.test.skipped, (test) => {
|
|
252
|
-
let loaded = true;
|
|
253
|
-
if (test.opts.skipInfo.isFastSkipped) {
|
|
254
|
-
loaded = false;
|
|
255
|
-
reporter.startSuite(test.parent.fullTitle());
|
|
256
|
-
}
|
|
257
|
-
reporter.pendingCase(test.title, null, test.opts.skipInfo);
|
|
258
|
-
if (!loaded) {
|
|
259
|
-
reporter.endSuite();
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
event.dispatcher.on(event.step.started, (step) => {
|
|
264
|
-
startMetaStep(step.metaStep);
|
|
265
|
-
if (currentStep !== step) {
|
|
266
|
-
// In multi-session scenarios, actors' names will be highlighted with ANSI
|
|
267
|
-
// escape sequences which are invalid XML values
|
|
268
|
-
step.actor = step.actor.replace(ansiRegExp(), '');
|
|
269
|
-
reporter.startStep(step.toString());
|
|
270
|
-
currentStep = step;
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
event.dispatcher.on(event.step.comment, (step) => {
|
|
275
|
-
reporter.startStep(step.toString());
|
|
276
|
-
currentStep = step;
|
|
277
|
-
reporter.endStep('passed');
|
|
278
|
-
currentStep = null;
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
event.dispatcher.on(event.step.passed, (step) => {
|
|
282
|
-
if (currentStep === step) {
|
|
283
|
-
reporter.endStep('passed');
|
|
284
|
-
currentStep = null;
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
event.dispatcher.on(event.step.failed, (step) => {
|
|
289
|
-
if (currentStep === step) {
|
|
290
|
-
reporter.endStep('failed');
|
|
291
|
-
currentStep = null;
|
|
292
|
-
}
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
let maxLevel;
|
|
296
|
-
function finishMetastep(level) {
|
|
297
|
-
const metaStepsToFinish = currentMetaStep.splice(maxLevel - level);
|
|
298
|
-
metaStepsToFinish.forEach(() => {
|
|
299
|
-
// only if the current step is of type Step, end it.
|
|
300
|
-
if (reporter.suites && reporter.suites.length && reporter.suites[0].currentStep && reporter.suites[0].currentStep.constructor.name === 'Step') {
|
|
301
|
-
reporter.endStep('passed');
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function startMetaStep(metaStep, level = 0) {
|
|
307
|
-
maxLevel = level;
|
|
308
|
-
if (!metaStep) {
|
|
309
|
-
finishMetastep(0);
|
|
310
|
-
maxLevel--;
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
startMetaStep(metaStep.metaStep, level + 1);
|
|
315
|
-
|
|
316
|
-
if (metaStep.toString() !== currentMetaStep[maxLevel - level]) {
|
|
317
|
-
finishMetastep(level);
|
|
318
|
-
currentMetaStep.push(metaStep.toString());
|
|
319
|
-
reporter.startStep(metaStep.toString());
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return plugin;
|
|
1
|
+
module.exports = () => {
|
|
2
|
+
console.log('Allure plugin was moved to @codeceptjs/allure-legacy. Please install it and update your config');
|
|
3
|
+
console.log();
|
|
4
|
+
console.log('npm install @codeceptjs/allure-legacy --save-dev');
|
|
5
|
+
console.log();
|
|
6
|
+
console.log('Then update your config to use it:');
|
|
7
|
+
console.log();
|
|
8
|
+
console.log('plugins: {');
|
|
9
|
+
console.log(' allure: {');
|
|
10
|
+
console.log(' enabled: true,');
|
|
11
|
+
console.log(' require: \'@codeceptjs/allure-legacy\',');
|
|
12
|
+
console.log(' }');
|
|
13
|
+
console.log('}');
|
|
14
|
+
console.log();
|
|
324
15
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const faker = require('@faker-js/faker');
|
|
1
|
+
const { faker } = require('@faker-js/faker');
|
|
2
2
|
const transform = require('../transform');
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -44,7 +44,7 @@ const transform = require('../transform');
|
|
|
44
44
|
module.exports = function (config) {
|
|
45
45
|
transform.addTransformerBeforeAll('gherkin.examples', (value) => {
|
|
46
46
|
if (typeof value === 'string' && value.length > 0) {
|
|
47
|
-
return faker.fake(value);
|
|
47
|
+
return faker.helpers.fake(value);
|
|
48
48
|
}
|
|
49
49
|
return value;
|
|
50
50
|
});
|