codeceptjs 3.0.3 → 3.0.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/CHANGELOG.md +114 -18
- package/bin/codecept.js +1 -0
- package/docs/basics.md +2 -2
- package/docs/bdd.md +12 -1
- package/docs/build/Appium.js +2 -1
- package/docs/build/GraphQL.js +9 -10
- package/docs/build/Nightmare.js +4 -5
- package/docs/build/Playwright.js +164 -37
- package/docs/build/Protractor.js +1 -1
- package/docs/build/Puppeteer.js +1 -1
- package/docs/build/REST.js +24 -4
- package/docs/build/TestCafe.js +1 -1
- package/docs/build/WebDriver.js +85 -17
- package/docs/changelog.md +114 -18
- package/docs/data.md +5 -5
- package/docs/detox.md +2 -2
- package/docs/docker.md +11 -11
- package/docs/email.md +8 -8
- package/docs/helpers/Appium.md +1 -1
- package/docs/helpers/Nightmare.md +4 -5
- package/docs/helpers/Playwright.md +94 -64
- package/docs/helpers/Protractor.md +1 -1
- package/docs/helpers/Puppeteer.md +1 -1
- package/docs/helpers/REST.md +9 -0
- package/docs/helpers/TestCafe.md +1 -1
- package/docs/helpers/WebDriver.md +2 -1
- package/docs/locators.md +29 -2
- package/docs/mobile-react-native-locators.md +2 -2
- package/docs/mobile.md +3 -3
- package/docs/nightmare.md +0 -5
- package/docs/pageobjects.md +3 -1
- package/docs/parallel.md +35 -10
- package/docs/playwright.md +55 -8
- package/docs/plugins.md +73 -29
- package/docs/reports.md +8 -7
- package/docs/typescript.md +47 -5
- package/docs/webapi/fillField.mustache +1 -1
- package/lib/cli.js +25 -10
- package/lib/codecept.js +9 -1
- package/lib/command/interactive.js +10 -9
- package/lib/command/run.js +1 -1
- package/lib/command/workers/runTests.js +11 -6
- package/lib/config.js +8 -3
- package/lib/event.js +2 -0
- package/lib/helper/Appium.js +1 -0
- package/lib/helper/GraphQL.js +9 -10
- package/lib/helper/Nightmare.js +1 -1
- package/lib/helper/Playwright.js +131 -38
- package/lib/helper/REST.js +24 -4
- package/lib/helper/WebDriver.js +84 -16
- package/lib/interfaces/gherkin.js +11 -4
- package/lib/output.js +7 -4
- package/lib/plugin/allure.js +3 -7
- package/lib/plugin/fakerTransform.js +51 -0
- package/lib/plugin/screenshotOnFail.js +6 -2
- package/lib/recorder.js +9 -0
- package/lib/step.js +2 -1
- package/lib/transform.js +26 -0
- package/lib/ui.js +6 -2
- package/lib/within.js +1 -1
- package/lib/workers.js +39 -25
- package/package.json +14 -9
- package/typings/index.d.ts +49 -21
- package/typings/types.d.ts +72 -26
package/lib/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ const ms = require('ms');
|
|
|
3
3
|
const event = require('./event');
|
|
4
4
|
const AssertionFailedError = require('./assert/error');
|
|
5
5
|
const output = require('./output');
|
|
6
|
+
const { MetaStep } = require('./step');
|
|
6
7
|
|
|
7
8
|
const cursor = Base.cursor;
|
|
8
9
|
let currentMetaStep = [];
|
|
@@ -77,17 +78,22 @@ class Cli extends Base {
|
|
|
77
78
|
});
|
|
78
79
|
|
|
79
80
|
event.dispatcher.on(event.step.started, (step) => {
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
let processingStep = step;
|
|
82
|
+
const metaSteps = [];
|
|
83
|
+
while (processingStep.metaStep) {
|
|
84
|
+
metaSteps.unshift(processingStep.metaStep);
|
|
85
|
+
processingStep = processingStep.metaStep;
|
|
86
|
+
}
|
|
87
|
+
const shift = metaSteps.length;
|
|
88
|
+
|
|
89
|
+
for (let i = 0; i < Math.max(currentMetaStep.length, metaSteps.length); i++) {
|
|
90
|
+
if (currentMetaStep[i] !== metaSteps[i]) {
|
|
91
|
+
output.stepShift = 3 + 2 * i;
|
|
92
|
+
if (metaSteps[i]) output.step(metaSteps[i]);
|
|
86
93
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
printMetaStep(step.metaStep);
|
|
94
|
+
}
|
|
95
|
+
currentMetaStep = metaSteps;
|
|
96
|
+
output.stepShift = 3 + 2 * shift;
|
|
91
97
|
output.step(step);
|
|
92
98
|
});
|
|
93
99
|
|
|
@@ -131,6 +137,8 @@ class Cli extends Base {
|
|
|
131
137
|
output.print(output.styles.bold('-- FAILURES:'));
|
|
132
138
|
}
|
|
133
139
|
|
|
140
|
+
const failuresLog = [];
|
|
141
|
+
|
|
134
142
|
// failures
|
|
135
143
|
if (stats.failures) {
|
|
136
144
|
// append step traces
|
|
@@ -178,10 +186,17 @@ class Cli extends Base {
|
|
|
178
186
|
return test;
|
|
179
187
|
});
|
|
180
188
|
|
|
189
|
+
const originalLog = Base.consoleLog;
|
|
190
|
+
Base.consoleLog = (...data) => {
|
|
191
|
+
failuresLog.push([...data]);
|
|
192
|
+
originalLog(...data);
|
|
193
|
+
};
|
|
181
194
|
Base.list(this.failures);
|
|
195
|
+
Base.consoleLog = originalLog;
|
|
182
196
|
console.log();
|
|
183
197
|
}
|
|
184
198
|
|
|
199
|
+
event.emit(event.all.failures, { failuresLog, stats });
|
|
185
200
|
output.result(stats.passes, stats.failures, stats.pending, ms(stats.duration));
|
|
186
201
|
|
|
187
202
|
if (stats.failures && output.level() < 3) {
|
package/lib/codecept.js
CHANGED
|
@@ -131,7 +131,15 @@ class Codecept {
|
|
|
131
131
|
if (!pattern) {
|
|
132
132
|
patterns = [];
|
|
133
133
|
if (this.config.tests && !this.opts.features) patterns.push(this.config.tests);
|
|
134
|
-
if (this.config.gherkin.features && !this.opts.tests)
|
|
134
|
+
if (this.config.gherkin.features && !this.opts.tests) {
|
|
135
|
+
if (Array.isArray(this.config.gherkin.features)) {
|
|
136
|
+
this.config.gherkin.features.forEach(feature => {
|
|
137
|
+
patterns.push(feature);
|
|
138
|
+
});
|
|
139
|
+
} else {
|
|
140
|
+
patterns.push(this.config.gherkin.features);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
135
143
|
}
|
|
136
144
|
|
|
137
145
|
for (pattern of patterns) {
|
|
@@ -4,21 +4,20 @@ const Codecept = require('../codecept');
|
|
|
4
4
|
const event = require('../event');
|
|
5
5
|
const output = require('../output');
|
|
6
6
|
|
|
7
|
-
module.exports = function (path, options) {
|
|
7
|
+
module.exports = async function (path, options) {
|
|
8
8
|
// Backward compatibility for --profile
|
|
9
9
|
process.profile = options.profile;
|
|
10
10
|
process.env.profile = options.profile;
|
|
11
|
+
const configFile = options.config;
|
|
12
|
+
|
|
13
|
+
const config = getConfig(configFile);
|
|
14
|
+
const testsPath = getTestRoot(configFile);
|
|
11
15
|
|
|
12
|
-
const testsPath = getTestRoot(path);
|
|
13
|
-
const config = getConfig(testsPath);
|
|
14
16
|
const codecept = new Codecept(config, options);
|
|
15
17
|
codecept.init(testsPath);
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
output.error(`Error while running bootstrap file :${err}`);
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
19
|
+
try {
|
|
20
|
+
await codecept.bootstrap();
|
|
22
21
|
|
|
23
22
|
if (options.verbose) output.level(3);
|
|
24
23
|
|
|
@@ -36,5 +35,7 @@ module.exports = function (path, options) {
|
|
|
36
35
|
recorder.add(() => event.emit(event.suite.after, {}));
|
|
37
36
|
recorder.add(() => event.emit(event.all.result, {}));
|
|
38
37
|
recorder.add(() => codecept.teardown());
|
|
39
|
-
})
|
|
38
|
+
} catch (err) {
|
|
39
|
+
output.error(`Error while running bootstrap file :${err}`);
|
|
40
|
+
}
|
|
40
41
|
};
|
package/lib/command/run.js
CHANGED
|
@@ -19,9 +19,9 @@ module.exports = async function (test, options) {
|
|
|
19
19
|
createOutputDir(config, testRoot);
|
|
20
20
|
|
|
21
21
|
const codecept = new Codecept(config, options);
|
|
22
|
-
codecept.init(testRoot);
|
|
23
22
|
|
|
24
23
|
try {
|
|
24
|
+
codecept.init(testRoot);
|
|
25
25
|
await codecept.bootstrap();
|
|
26
26
|
codecept.loadTests();
|
|
27
27
|
await codecept.run(test);
|
|
@@ -39,9 +39,12 @@ codecept.init(testRoot);
|
|
|
39
39
|
codecept.loadTests();
|
|
40
40
|
const mocha = container.mocha();
|
|
41
41
|
filterTests();
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
|
|
43
|
+
(async function () {
|
|
44
|
+
if (mocha.suite.total()) {
|
|
45
|
+
await runTests();
|
|
46
|
+
}
|
|
47
|
+
}());
|
|
45
48
|
|
|
46
49
|
async function runTests() {
|
|
47
50
|
try {
|
|
@@ -116,14 +119,16 @@ function initializeListeners() {
|
|
|
116
119
|
// tests
|
|
117
120
|
event.dispatcher.on(event.test.before, test => sendToParentThread({ event: event.test.before, workerIndex, data: simplifyTest(test) }));
|
|
118
121
|
event.dispatcher.on(event.test.after, test => sendToParentThread({ event: event.test.after, workerIndex, data: simplifyTest(test) }));
|
|
119
|
-
|
|
120
|
-
event.dispatcher.on(event.test.
|
|
121
|
-
event.dispatcher.on(event.test.
|
|
122
|
+
// we should force-send correct errors to prevent race condition
|
|
123
|
+
event.dispatcher.on(event.test.finished, (test, err) => sendToParentThread({ event: event.test.finished, workerIndex, data: simplifyTest(test, err) }));
|
|
124
|
+
event.dispatcher.on(event.test.failed, (test, err) => sendToParentThread({ event: event.test.failed, workerIndex, data: simplifyTest(test, err) }));
|
|
125
|
+
event.dispatcher.on(event.test.passed, (test, err) => sendToParentThread({ event: event.test.passed, workerIndex, data: simplifyTest(test, err) }));
|
|
122
126
|
event.dispatcher.on(event.test.started, test => sendToParentThread({ event: event.test.started, workerIndex, data: simplifyTest(test) }));
|
|
123
127
|
event.dispatcher.on(event.test.skipped, test => sendToParentThread({ event: event.test.skipped, workerIndex, data: simplifyTest(test) }));
|
|
124
128
|
|
|
125
129
|
event.dispatcher.on(event.hook.failed, (test, err) => sendToParentThread({ event: event.hook.failed, workerIndex, data: simplifyTest(test, err) }));
|
|
126
130
|
event.dispatcher.on(event.hook.passed, (test, err) => sendToParentThread({ event: event.hook.passed, workerIndex, data: simplifyTest(test, err) }));
|
|
131
|
+
event.dispatcher.on(event.all.failures, (data) => sendToParentThread({ event: event.all.failures, workerIndex, data }));
|
|
127
132
|
|
|
128
133
|
// all
|
|
129
134
|
event.dispatcher.once(event.all.result, () => parentPort.close());
|
package/lib/config.js
CHANGED
|
@@ -77,13 +77,18 @@ class Config {
|
|
|
77
77
|
return loadConfigFile(jsonConfig);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
const tsConfig = path.join(configFile, 'codecept.conf.ts');
|
|
81
|
+
if (isFile(tsConfig)) {
|
|
82
|
+
return loadConfigFile(tsConfig);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
throw new Error(`Can not load config from ${jsConfig} or ${jsonConfig} or ${tsConfig}\nCodeceptJS is not initialized in this dir. Execute 'codeceptjs init' to start`);
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
/**
|
|
84
89
|
* Get current config.
|
|
85
|
-
* @param {string} key
|
|
86
|
-
* @param {*} val
|
|
90
|
+
* @param {string} [key]
|
|
91
|
+
* @param {*} [val]
|
|
87
92
|
* @return {*}
|
|
88
93
|
*/
|
|
89
94
|
static get(key, val) {
|
package/lib/event.js
CHANGED
|
@@ -99,11 +99,13 @@ module.exports = {
|
|
|
99
99
|
* @property {'global.before'} before
|
|
100
100
|
* @property {'global.after'} after
|
|
101
101
|
* @property {'global.result'} result
|
|
102
|
+
* @property {'global.failures'} failures
|
|
102
103
|
*/
|
|
103
104
|
all: {
|
|
104
105
|
before: 'global.before',
|
|
105
106
|
after: 'global.after',
|
|
106
107
|
result: 'global.result',
|
|
108
|
+
failures: 'global.failures',
|
|
107
109
|
},
|
|
108
110
|
/**
|
|
109
111
|
* @type {object}
|
package/lib/helper/Appium.js
CHANGED
|
@@ -183,6 +183,7 @@ class Appium extends Webdriver {
|
|
|
183
183
|
config.capabilities.browserName = config.browser || config.capabilities.browserName;
|
|
184
184
|
config.capabilities.app = config.app || config.capabilities.app;
|
|
185
185
|
config.capabilities.platformName = config.platform || config.capabilities.platformName;
|
|
186
|
+
config.capabilities.tunnelIdentifier = config.tunnelIdentifier || config.capabilities.tunnelIdentifier; // Adding the code to connect to sauce labs via sauce tunnel
|
|
186
187
|
config.waitForTimeout /= 1000; // convert to seconds
|
|
187
188
|
|
|
188
189
|
// [CodeceptJS compatible] transform host to hostname
|
package/lib/helper/GraphQL.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
const axios = require('axios').default;
|
|
2
2
|
const Helper = require('../helper');
|
|
3
3
|
|
|
4
|
-
let headers = {};
|
|
5
|
-
|
|
6
4
|
/**
|
|
7
5
|
* GraphQL helper allows to send additional requests to a GraphQl endpoint during acceptance tests.
|
|
8
6
|
* [Axios](https://github.com/axios/axios) library is used to perform requests.
|
|
@@ -41,15 +39,16 @@ let headers = {};
|
|
|
41
39
|
class GraphQL extends Helper {
|
|
42
40
|
constructor(config) {
|
|
43
41
|
super(config);
|
|
44
|
-
axios =
|
|
42
|
+
this.axios = axios.create();
|
|
43
|
+
this.headers = {};
|
|
45
44
|
this.options = {
|
|
46
45
|
timeout: 10000,
|
|
47
46
|
defaultHeaders: {},
|
|
48
47
|
endpoint: '',
|
|
49
48
|
};
|
|
50
49
|
this.options = Object.assign(this.options, config);
|
|
51
|
-
headers = { ...this.options.defaultHeaders };
|
|
52
|
-
axios.defaults.headers = this.options.defaultHeaders;
|
|
50
|
+
this.headers = { ...this.options.defaultHeaders };
|
|
51
|
+
this.axios.defaults.headers = this.options.defaultHeaders;
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
static _checkRequirements() {
|
|
@@ -66,10 +65,10 @@ class GraphQL extends Helper {
|
|
|
66
65
|
* @param {object} request
|
|
67
66
|
*/
|
|
68
67
|
async _executeQuery(request) {
|
|
69
|
-
axios.defaults.timeout = request.timeout || this.options.timeout;
|
|
68
|
+
this.axios.defaults.timeout = request.timeout || this.options.timeout;
|
|
70
69
|
|
|
71
|
-
if (headers && headers.auth) {
|
|
72
|
-
request.auth = headers.auth;
|
|
70
|
+
if (this.headers && this.headers.auth) {
|
|
71
|
+
request.auth = this.headers.auth;
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
request.headers = Object.assign(request.headers, {
|
|
@@ -84,7 +83,7 @@ class GraphQL extends Helper {
|
|
|
84
83
|
|
|
85
84
|
let response;
|
|
86
85
|
try {
|
|
87
|
-
response = await axios(request);
|
|
86
|
+
response = await this.axios(request);
|
|
88
87
|
} catch (err) {
|
|
89
88
|
if (!err.response) throw err;
|
|
90
89
|
this.debugSection(
|