codeceptjs 3.3.8-beta.1 → 3.4.0
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 +14 -9
- package/docs/build/Appium.js +2 -19
- package/docs/build/FileSystem.js +3 -3
- package/docs/build/GraphQL.js +1 -1
- package/docs/build/GraphQLDataFactory.js +3 -3
- package/docs/build/JSONResponse.js +1 -1
- package/docs/build/Mochawesome.js +1 -1
- package/docs/build/Nightmare.js +1 -1
- package/docs/build/Playwright.js +4 -3
- package/docs/build/Protractor.js +1 -1
- package/docs/build/Puppeteer.js +1 -1
- package/docs/build/REST.js +1 -1
- package/docs/build/TestCafe.js +5 -5
- package/docs/build/WebDriver.js +30 -165
- package/docs/changelog.md +49 -2
- 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 +42 -125
- package/docs/reports.md +0 -56
- package/docs/tutorial.md +271 -0
- 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 +14 -9
- 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 +14 -18
- package/typings/index.d.ts +76 -1
- package/typings/promiseBasedTypes.d.ts +12 -12
- package/typings/types.d.ts +95 -262
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
|
});
|
package/lib/recorder.js
CHANGED
package/lib/scenario.js
CHANGED
|
@@ -2,7 +2,7 @@ const promiseRetry = require('promise-retry');
|
|
|
2
2
|
const event = require('./event');
|
|
3
3
|
const recorder = require('./recorder');
|
|
4
4
|
const assertThrown = require('./assert/throws');
|
|
5
|
-
const { isAsyncFunction } = require('./utils');
|
|
5
|
+
const { ucfirst, isAsyncFunction } = require('./utils');
|
|
6
6
|
const parser = require('./parser');
|
|
7
7
|
|
|
8
8
|
const injectHook = function (inject, suite) {
|
|
@@ -107,7 +107,7 @@ module.exports.test = (test) => {
|
|
|
107
107
|
/**
|
|
108
108
|
* Injects arguments to function from controller
|
|
109
109
|
*/
|
|
110
|
-
module.exports.injected = function (fn, suite, hookName) {
|
|
110
|
+
module.exports.injected = function (fn, suite, hookName) {
|
|
111
111
|
return function (done) {
|
|
112
112
|
const errHandler = (err) => {
|
|
113
113
|
recorder.session.start('teardown');
|
|
@@ -125,35 +125,42 @@ module.exports.injected = function (fn, suite, hookName) {
|
|
|
125
125
|
if (!fn) throw new Error('fn is not defined');
|
|
126
126
|
|
|
127
127
|
event.emit(event.hook.started, suite);
|
|
128
|
+
|
|
129
|
+
this.test.body = fn.toString();
|
|
130
|
+
|
|
128
131
|
if (!recorder.isRunning()) {
|
|
129
|
-
recorder.start();
|
|
130
132
|
recorder.errHandler((err) => {
|
|
131
133
|
errHandler(err);
|
|
132
134
|
});
|
|
133
135
|
}
|
|
134
136
|
|
|
135
|
-
|
|
137
|
+
const opts = suite.opts || {};
|
|
138
|
+
const retries = opts[`retry${ucfirst(hookName)}`] || 0;
|
|
136
139
|
|
|
137
|
-
recorder.retry(suite.retries());
|
|
138
140
|
promiseRetry(async (retry) => {
|
|
139
141
|
try {
|
|
140
|
-
|
|
142
|
+
recorder.startUnlessRunning();
|
|
143
|
+
await fn.call(this, getInjectedArguments(fn));
|
|
144
|
+
await recorder.promise();
|
|
141
145
|
} catch (err) {
|
|
142
146
|
retry(err);
|
|
147
|
+
} finally {
|
|
148
|
+
recorder.stop();
|
|
149
|
+
recorder.start();
|
|
143
150
|
}
|
|
144
|
-
}, { retries
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
}, { retries })
|
|
152
|
+
.then(() => {
|
|
153
|
+
recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite));
|
|
154
|
+
recorder.add(`finish ${hookName} hook`, () => done());
|
|
155
|
+
recorder.catch();
|
|
156
|
+
}).catch((e) => {
|
|
157
|
+
recorder.throw(e);
|
|
158
|
+
recorder.catch((e) => {
|
|
159
|
+
const err = (recorder.getAsyncErr() === null) ? e : recorder.getAsyncErr();
|
|
160
|
+
errHandler(err);
|
|
161
|
+
});
|
|
162
|
+
recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e));
|
|
154
163
|
});
|
|
155
|
-
recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e));
|
|
156
|
-
});
|
|
157
164
|
};
|
|
158
165
|
};
|
|
159
166
|
|
package/lib/utils.js
CHANGED
|
@@ -449,3 +449,9 @@ module.exports.requireWithFallback = function (...packages) {
|
|
|
449
449
|
|
|
450
450
|
throw new Error(`Cannot find modules ${packages.join(',')}`);
|
|
451
451
|
};
|
|
452
|
+
|
|
453
|
+
module.exports.isNotSet = function (obj) {
|
|
454
|
+
if (obj === null) return true;
|
|
455
|
+
if (obj === undefined) return true;
|
|
456
|
+
return false;
|
|
457
|
+
};
|
package/lib/workers.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* eslint-disable max-classes-per-file */
|
|
2
|
-
const { EventEmitter } = require('events');
|
|
3
2
|
const path = require('path');
|
|
4
3
|
const mkdirp = require('mkdirp');
|
|
5
4
|
const { Worker } = require('worker_threads');
|
|
6
5
|
const { Suite, Test, reporters: { Base } } = require('mocha');
|
|
6
|
+
const { EventEmitter } = require('events');
|
|
7
7
|
const ms = require('ms');
|
|
8
8
|
const Codecept = require('./codecept');
|
|
9
9
|
const MochaFactory = require('./mochaFactory');
|
|
@@ -107,8 +107,7 @@ const convertToMochaTests = (testGroup) => {
|
|
|
107
107
|
mocha.files = testGroup;
|
|
108
108
|
mocha.loadFiles();
|
|
109
109
|
mocha.suite.eachTest((test) => {
|
|
110
|
-
|
|
111
|
-
group.push(id);
|
|
110
|
+
group.push(test.uid);
|
|
112
111
|
});
|
|
113
112
|
mocha.unloadFiles();
|
|
114
113
|
}
|
|
@@ -242,8 +241,7 @@ class Workers extends EventEmitter {
|
|
|
242
241
|
mocha.suite.eachTest((test) => {
|
|
243
242
|
const i = groupCounter % groups.length;
|
|
244
243
|
if (test) {
|
|
245
|
-
|
|
246
|
-
groups[i].push(id);
|
|
244
|
+
groups[i].push(test.uid);
|
|
247
245
|
groupCounter++;
|
|
248
246
|
}
|
|
249
247
|
});
|
|
@@ -264,8 +262,7 @@ class Workers extends EventEmitter {
|
|
|
264
262
|
const i = indexOfSmallestElement(groups);
|
|
265
263
|
suite.tests.forEach((test) => {
|
|
266
264
|
if (test) {
|
|
267
|
-
|
|
268
|
-
groups[i].push(id);
|
|
265
|
+
groups[i].push(test.uid);
|
|
269
266
|
}
|
|
270
267
|
});
|
|
271
268
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeceptjs",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "Supercharged End 2 End Testing Framework for NodeJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acceptance",
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
},
|
|
36
36
|
"repository": "Codeception/codeceptjs",
|
|
37
37
|
"scripts": {
|
|
38
|
-
"build": "tsc -p ./",
|
|
39
38
|
"json-server": "./node_modules/json-server/bin/index.js test/data/rest/db.json -p 8010 --watch -m test/data/rest/headers.js",
|
|
40
39
|
"json-server:graphql": "node test/data/graphql/index.js",
|
|
41
40
|
"lint": "eslint bin/ examples/ lib/ test/ translations/ runok.js",
|
|
@@ -56,23 +55,23 @@
|
|
|
56
55
|
"dependencies": {
|
|
57
56
|
"@codeceptjs/configure": "^0.8.0",
|
|
58
57
|
"@codeceptjs/helper": "^1.0.2",
|
|
58
|
+
"@cucumber/cucumber-expressions": "^16",
|
|
59
|
+
"@cucumber/gherkin": "^26",
|
|
60
|
+
"@cucumber/messages": "^21.0.1",
|
|
59
61
|
"acorn": "^7.4.1",
|
|
60
|
-
"allure-js-commons": "^1.3.2",
|
|
61
62
|
"arrify": "^2.0.1",
|
|
62
|
-
"axios": "^
|
|
63
|
+
"axios": "^1.3.3",
|
|
63
64
|
"chai": "^4.3.6",
|
|
64
65
|
"chai-deep-match": "^1.2.1",
|
|
65
66
|
"chalk": "^4.1.2",
|
|
66
67
|
"commander": "^2.20.3",
|
|
67
68
|
"cross-spawn": "^7.0.3",
|
|
68
69
|
"css-to-xpath": "^0.1.0",
|
|
69
|
-
"cucumber-expressions": "^6.6.2",
|
|
70
70
|
"envinfo": "^7.8.1",
|
|
71
71
|
"escape-string-regexp": "^1.0.3",
|
|
72
72
|
"figures": "^3.2.0",
|
|
73
73
|
"fn-args": "^4.0.0",
|
|
74
74
|
"fs-extra": "^8.1.0",
|
|
75
|
-
"gherkin": "^5.1.0",
|
|
76
75
|
"glob": "^6.0.1",
|
|
77
76
|
"inquirer": "^6.5.2",
|
|
78
77
|
"joi": "^17.6.0",
|
|
@@ -80,21 +79,19 @@
|
|
|
80
79
|
"lodash.clonedeep": "^4.5.0",
|
|
81
80
|
"lodash.merge": "^4.6.2",
|
|
82
81
|
"mkdirp": "^1.0.4",
|
|
83
|
-
"mocha": "8.
|
|
84
|
-
"mocha-junit-reporter": "1.23.
|
|
82
|
+
"mocha": "^8.2.0",
|
|
83
|
+
"mocha-junit-reporter": "^1.23.3",
|
|
85
84
|
"ms": "^2.1.3",
|
|
86
85
|
"parse-function": "^5.6.4",
|
|
87
86
|
"promise-retry": "^1.1.1",
|
|
88
|
-
"requireg": "^0.2.2",
|
|
89
87
|
"resq": "^1.10.2",
|
|
90
|
-
"semver": "^6.3.0",
|
|
91
88
|
"sprintf-js": "^1.1.1",
|
|
92
|
-
"uuid": "^
|
|
89
|
+
"uuid": "^9.0"
|
|
93
90
|
},
|
|
94
91
|
"devDependencies": {
|
|
95
92
|
"@codeceptjs/detox-helper": "^1.0.2",
|
|
96
93
|
"@codeceptjs/mock-request": "^0.3.1",
|
|
97
|
-
"@faker-js/faker": "^
|
|
94
|
+
"@faker-js/faker": "^7.6.0",
|
|
98
95
|
"@pollyjs/adapter-puppeteer": "^5.1.0",
|
|
99
96
|
"@pollyjs/core": "^5.1.0",
|
|
100
97
|
"@types/inquirer": "^0.0.35",
|
|
@@ -118,10 +115,10 @@
|
|
|
118
115
|
"form-data": "^3.0.1",
|
|
119
116
|
"graphql": "^14.6.0",
|
|
120
117
|
"husky": "^8.0.1",
|
|
118
|
+
"inquirer-test": "^2.0.1",
|
|
121
119
|
"jsdoc": "^3.6.10",
|
|
122
120
|
"jsdoc-typeof-plugin": "^1.0.0",
|
|
123
121
|
"json-server": "^0.10.1",
|
|
124
|
-
"mocha-parallel-tests": "^2.3.0",
|
|
125
122
|
"nightmare": "^3.0.2",
|
|
126
123
|
"nodemon": "^1.19.4",
|
|
127
124
|
"playwright": "^1.23.2",
|
|
@@ -131,19 +128,18 @@
|
|
|
131
128
|
"runok": "^0.9.2",
|
|
132
129
|
"sinon": "^9.2.4",
|
|
133
130
|
"sinon-chai": "^3.7.0",
|
|
134
|
-
"testcafe": "^1.
|
|
131
|
+
"testcafe": "^2.1.0",
|
|
135
132
|
"ts-morph": "^3.1.3",
|
|
136
133
|
"ts-node": "^10.9.1",
|
|
137
|
-
"tsd-jsdoc": "
|
|
134
|
+
"tsd-jsdoc": "^2.5.0",
|
|
138
135
|
"typedoc": "^0.23.10",
|
|
139
136
|
"typedoc-plugin-markdown": "^3.13.4",
|
|
140
137
|
"typescript": "^4.8.4",
|
|
141
138
|
"wdio-docker-service": "^1.5.0",
|
|
142
|
-
"webdriverio": "^
|
|
139
|
+
"webdriverio": "^8.3.8",
|
|
143
140
|
"xml2js": "^0.4.23",
|
|
144
141
|
"xmldom": "^0.1.31",
|
|
145
|
-
"xpath": "0.0.27"
|
|
146
|
-
"inquirer-test": "^2.0.1"
|
|
142
|
+
"xpath": "0.0.27"
|
|
147
143
|
},
|
|
148
144
|
"engines": {
|
|
149
145
|
"node": ">=8.9.1",
|
package/typings/index.d.ts
CHANGED
|
@@ -17,6 +17,32 @@ declare namespace CodeceptJS {
|
|
|
17
17
|
path?: string,
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
type RetryConfig = {
|
|
21
|
+
/** Filter tests by string or regexp pattern */
|
|
22
|
+
grep: string | RegExp;
|
|
23
|
+
/** Number of times to repeat scenarios of a Feature */
|
|
24
|
+
Feature: number;
|
|
25
|
+
/** Number of times to repeat scenarios */
|
|
26
|
+
Scenario: number;
|
|
27
|
+
/** Number of times to repeat Before hook */
|
|
28
|
+
Before: number;
|
|
29
|
+
/** Number of times to repeat After hook */
|
|
30
|
+
After: number;
|
|
31
|
+
/** Number of times to repeat BeforeSuite hook */
|
|
32
|
+
BeforeSuite: number;
|
|
33
|
+
/** Number of times to repeat AfterSuite hook */
|
|
34
|
+
AfterSuite: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type TimeoutConfig = {
|
|
38
|
+
/** Filter tests by string or regexp pattern */
|
|
39
|
+
grep: string | RegExp;
|
|
40
|
+
/** Set timeout for a scenarios of a Feature */
|
|
41
|
+
Feature: number;
|
|
42
|
+
/** Set timeout for scenarios */
|
|
43
|
+
Scenario: number;
|
|
44
|
+
};
|
|
45
|
+
|
|
20
46
|
type MainConfig = {
|
|
21
47
|
/** Pattern to locate CodeceptJS tests.
|
|
22
48
|
* Allows to enter glob pattern or an Array<string> of patterns to match tests / test file names.
|
|
@@ -172,8 +198,57 @@ declare namespace CodeceptJS {
|
|
|
172
198
|
* ```js
|
|
173
199
|
* timeout: 20,
|
|
174
200
|
* ```
|
|
201
|
+
*
|
|
202
|
+
* Can be customized to use different timeouts for a subset of tests:
|
|
203
|
+
*
|
|
204
|
+
* ```js
|
|
205
|
+
* timeout: [
|
|
206
|
+
* 10,
|
|
207
|
+
* {
|
|
208
|
+
* grep: '@slow',
|
|
209
|
+
* Scenario: 20
|
|
210
|
+
* }
|
|
211
|
+
* ]
|
|
212
|
+
* ```
|
|
175
213
|
*/
|
|
176
|
-
timeout?: number;
|
|
214
|
+
timeout?: number | Array<TimeoutConfig> | TimeoutConfig;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Configure retry strategy for tests
|
|
218
|
+
*
|
|
219
|
+
* To retry all tests 3 times:
|
|
220
|
+
*
|
|
221
|
+
* ```js
|
|
222
|
+
* retry: 3
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* To retry only Before hook 3 times:
|
|
226
|
+
*
|
|
227
|
+
* ```js
|
|
228
|
+
* retry: {
|
|
229
|
+
* Before: 3
|
|
230
|
+
* }
|
|
231
|
+
* ```
|
|
232
|
+
*
|
|
233
|
+
* To retry tests marked as flaky 3 times, other 1 time:
|
|
234
|
+
*
|
|
235
|
+
* ```js
|
|
236
|
+
* retry: [
|
|
237
|
+
* {
|
|
238
|
+
* Scenario: 1,
|
|
239
|
+
* Before: 1
|
|
240
|
+
* },
|
|
241
|
+
* {
|
|
242
|
+
* grep: '@flaky',
|
|
243
|
+
* Scenario: 3
|
|
244
|
+
* Before: 3
|
|
245
|
+
* }
|
|
246
|
+
* ]
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
retry?: number | Array<RetryConfig> | RetryConfig;
|
|
250
|
+
|
|
251
|
+
|
|
177
252
|
/** Disable registering global functions (Before, Scenario, etc). Not recommended */
|
|
178
253
|
noGlobals?: boolean;
|
|
179
254
|
/**
|