codeceptjs 3.2.0 → 3.3.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 +78 -2
- package/docs/advanced.md +3 -3
- package/docs/api.md +227 -188
- package/docs/basics.md +26 -1
- package/docs/bdd.md +2 -2
- package/docs/build/ApiDataFactory.js +13 -6
- package/docs/build/Appium.js +98 -36
- package/docs/build/FileSystem.js +11 -1
- package/docs/build/GraphQL.js +11 -0
- package/docs/build/JSONResponse.js +297 -0
- package/docs/build/Nightmare.js +48 -48
- package/docs/build/Playwright.js +277 -151
- package/docs/build/Puppeteer.js +77 -68
- package/docs/build/REST.js +36 -0
- package/docs/build/TestCafe.js +44 -44
- package/docs/build/WebDriver.js +70 -70
- package/docs/changelog.md +28 -2
- package/docs/configuration.md +8 -8
- package/docs/custom-helpers.md +1 -1
- package/docs/data.md +9 -9
- package/docs/helpers/ApiDataFactory.md +7 -0
- package/docs/helpers/Appium.md +240 -198
- package/docs/helpers/FileSystem.md +11 -1
- package/docs/helpers/JSONResponse.md +230 -0
- package/docs/helpers/Playwright.md +283 -216
- package/docs/helpers/Puppeteer.md +9 -1
- package/docs/helpers/REST.md +30 -9
- package/docs/installation.md +3 -1
- package/docs/internal-api.md +265 -0
- package/docs/mobile.md +11 -11
- package/docs/nightmare.md +3 -3
- package/docs/pageobjects.md +2 -0
- package/docs/playwright.md +73 -18
- package/docs/plugins.md +140 -40
- package/docs/puppeteer.md +28 -12
- package/docs/quickstart.md +2 -3
- package/docs/reports.md +44 -3
- package/docs/testcafe.md +1 -1
- package/docs/translation.md +2 -2
- package/docs/videos.md +2 -2
- package/docs/visual.md +2 -2
- package/docs/vue.md +1 -1
- package/docs/webdriver.md +92 -4
- package/lib/actor.js +2 -2
- package/lib/cli.js +25 -20
- package/lib/command/init.js +5 -15
- package/lib/command/workers/runTests.js +25 -7
- package/lib/config.js +17 -13
- package/lib/helper/ApiDataFactory.js +13 -6
- package/lib/helper/Appium.js +65 -3
- package/lib/helper/FileSystem.js +11 -1
- package/lib/helper/GraphQL.js +11 -0
- package/lib/helper/JSONResponse.js +297 -0
- package/lib/helper/Playwright.js +215 -89
- package/lib/helper/Puppeteer.js +13 -4
- package/lib/helper/REST.js +36 -0
- package/lib/helper/WebDriver.js +1 -1
- package/lib/helper/extras/Console.js +8 -0
- package/lib/helper/extras/PlaywrightRestartOpts.js +35 -0
- package/lib/interfaces/bdd.js +3 -1
- package/lib/listener/timeout.js +4 -3
- package/lib/plugin/allure.js +12 -0
- package/lib/plugin/autoLogin.js +1 -1
- package/lib/plugin/eachElement.js +127 -0
- package/lib/plugin/retryFailedStep.js +4 -3
- package/lib/plugin/stepTimeout.js +5 -4
- package/lib/plugin/tryTo.js +6 -0
- package/lib/recorder.js +2 -1
- package/lib/step.js +57 -2
- package/lib/utils.js +20 -0
- package/package.json +6 -4
- package/translations/pt-BR.js +8 -0
- package/typings/index.d.ts +4 -0
- package/typings/types.d.ts +345 -110
|
@@ -14,6 +14,14 @@ class Console {
|
|
|
14
14
|
this._logEntries = [];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
includes(msg) {
|
|
18
|
+
const prev = this._logEntries[this._logEntries.length - 1];
|
|
19
|
+
if (!prev) return false;
|
|
20
|
+
const text = msg.text && msg.text() || msg._text || '';
|
|
21
|
+
const prevText = prev.text && prev.text() || prev._text || '';
|
|
22
|
+
return text === prevText;
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
add(entry) {
|
|
18
26
|
if (Array.isArray(entry)) {
|
|
19
27
|
this._logEntries = this._logEntries.concat(entry);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const RESTART_OPTS = {
|
|
2
|
+
session: 'keep',
|
|
3
|
+
browser: true,
|
|
4
|
+
context: false,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
let restarts = null;
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
|
|
11
|
+
setRestartStrategy(options) {
|
|
12
|
+
const { restart } = options;
|
|
13
|
+
const stringOpts = Object.keys(RESTART_OPTS);
|
|
14
|
+
|
|
15
|
+
if (stringOpts.includes(restart)) {
|
|
16
|
+
return restarts = restart;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
restarts = Object.keys(RESTART_OPTS).find(key => RESTART_OPTS[key] === restart);
|
|
20
|
+
|
|
21
|
+
console.log(restarts);
|
|
22
|
+
|
|
23
|
+
if (restarts === null || restarts === undefined) throw new Error('No restart strategy set, use the following values for restart: session, context, browser');
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
restartsSession() {
|
|
27
|
+
return restarts === 'session';
|
|
28
|
+
},
|
|
29
|
+
restartsContext() {
|
|
30
|
+
return restarts === 'context';
|
|
31
|
+
},
|
|
32
|
+
restartsBrowser() {
|
|
33
|
+
return restarts === 'browser';
|
|
34
|
+
},
|
|
35
|
+
};
|
package/lib/interfaces/bdd.js
CHANGED
|
@@ -25,7 +25,8 @@ const parameterTypeRegistry = new ParameterTypeRegistry();
|
|
|
25
25
|
const matchStep = (step) => {
|
|
26
26
|
for (const stepName in steps) {
|
|
27
27
|
if (stepName.indexOf('/') === 0) {
|
|
28
|
-
const
|
|
28
|
+
const regExpArr = stepName.match(new RegExp('^/(.*?)/([gimy]*)$')) || [];
|
|
29
|
+
const res = step.match(new RegExp(regExpArr[1], regExpArr[2]));
|
|
29
30
|
if (res) {
|
|
30
31
|
const fn = steps[stepName];
|
|
31
32
|
fn.params = res.slice(1);
|
|
@@ -56,6 +57,7 @@ module.exports = {
|
|
|
56
57
|
Given: addStep,
|
|
57
58
|
When: addStep,
|
|
58
59
|
Then: addStep,
|
|
60
|
+
And: addStep,
|
|
59
61
|
matchStep,
|
|
60
62
|
getSteps,
|
|
61
63
|
clearSteps,
|
package/lib/listener/timeout.js
CHANGED
|
@@ -3,6 +3,7 @@ const output = require('../output');
|
|
|
3
3
|
const recorder = require('../recorder');
|
|
4
4
|
const Config = require('../config');
|
|
5
5
|
const { timeouts } = require('../store');
|
|
6
|
+
const TIMEOUT_ORDER = require('../step').TIMEOUT_ORDER;
|
|
6
7
|
|
|
7
8
|
module.exports = function () {
|
|
8
9
|
let timeout;
|
|
@@ -49,14 +50,14 @@ module.exports = function () {
|
|
|
49
50
|
if (typeof timeout !== 'number') return;
|
|
50
51
|
|
|
51
52
|
if (timeout < 0) {
|
|
52
|
-
step.
|
|
53
|
+
step.setTimeout(0.01, TIMEOUT_ORDER.testOrSuite);
|
|
53
54
|
} else {
|
|
54
|
-
step.
|
|
55
|
+
step.setTimeout(timeout, TIMEOUT_ORDER.testOrSuite);
|
|
55
56
|
}
|
|
56
57
|
});
|
|
57
58
|
|
|
58
59
|
event.dispatcher.on(event.step.finished, (step) => {
|
|
59
|
-
timeout -= step.duration;
|
|
60
|
+
if (typeof timeout === 'number' && !Number.isNaN(timeout)) timeout -= step.duration;
|
|
60
61
|
|
|
61
62
|
if (typeof timeout === 'number' && timeout <= 0 && recorder.isRunning()) {
|
|
62
63
|
if (currentTest && currentTest.callback) {
|
package/lib/plugin/allure.js
CHANGED
|
@@ -64,6 +64,18 @@ const defaultConfig = {
|
|
|
64
64
|
* * `addAttachment(name, buffer, type)` - add an attachment to current test / suite
|
|
65
65
|
* * `addLabel(name, value)` - adds a label to current test
|
|
66
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
|
+
* 
|
|
67
79
|
* * `severity(value)` - adds severity label
|
|
68
80
|
* * `epic(value)` - adds epic label
|
|
69
81
|
* * `feature(value)` - adds feature label
|
package/lib/plugin/autoLogin.js
CHANGED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const output = require('../output');
|
|
2
|
+
const store = require('../store');
|
|
3
|
+
const recorder = require('../recorder');
|
|
4
|
+
const container = require('../container');
|
|
5
|
+
const event = require('../event');
|
|
6
|
+
const Step = require('../step');
|
|
7
|
+
const { isAsyncFunction } = require('../utils');
|
|
8
|
+
|
|
9
|
+
const defaultConfig = {
|
|
10
|
+
registerGlobal: true,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Provides `eachElement` global function to iterate over found elements to perform actions on them.
|
|
15
|
+
*
|
|
16
|
+
* `eachElement` takes following args:
|
|
17
|
+
* * `purpose` - the goal of an action. A comment text that will be displayed in output.
|
|
18
|
+
* * `locator` - a CSS/XPath locator to match elements
|
|
19
|
+
* * `fn(element, index)` - **asynchronous** function which will be executed for each matched element.
|
|
20
|
+
*
|
|
21
|
+
* Example of usage:
|
|
22
|
+
*
|
|
23
|
+
* ```js
|
|
24
|
+
* // this example works with Playwright and Puppeteer helper
|
|
25
|
+
* await eachElement('click all checkboxes', 'form input[type=checkbox]', async (el) => {
|
|
26
|
+
* await el.click();
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
* Click odd elements:
|
|
30
|
+
*
|
|
31
|
+
* ```js
|
|
32
|
+
* // this example works with Playwright and Puppeteer helper
|
|
33
|
+
* await eachElement('click odd buttons', '.button-select', async (el, index) => {
|
|
34
|
+
* if (index % 2) await el.click();
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* Check all elements for visibility:
|
|
39
|
+
*
|
|
40
|
+
* ```js
|
|
41
|
+
* // this example works with Playwright and Puppeteer helper
|
|
42
|
+
* const assert = require('assert');
|
|
43
|
+
* await eachElement('check all items are visible', '.item', async (el) => {
|
|
44
|
+
* assert(await el.isVisible());
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
* This method works with WebDriver, Playwright, Puppeteer, Appium helpers.
|
|
48
|
+
*
|
|
49
|
+
* Function parameter `el` represents a matched element.
|
|
50
|
+
* Depending on a helper API of `el` can be different. Refer to API of corresponding browser testing engine for a complete API list:
|
|
51
|
+
*
|
|
52
|
+
* * [Playwright ElementHandle](https://playwright.dev/docs/api/class-elementhandle)
|
|
53
|
+
* * [Puppeteer](https://pptr.dev/#?product=Puppeteer&show=api-class-elementhandle)
|
|
54
|
+
* * [webdriverio element](https://webdriver.io/docs/api)
|
|
55
|
+
*
|
|
56
|
+
* #### Configuration
|
|
57
|
+
*
|
|
58
|
+
* * `registerGlobal` - to register `eachElement` function globally, true by default
|
|
59
|
+
*
|
|
60
|
+
* If `registerGlobal` is false you can use eachElement from the plugin:
|
|
61
|
+
*
|
|
62
|
+
* ```js
|
|
63
|
+
* const eachElement = codeceptjs.container.plugins('eachElement');
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @param {string} purpose
|
|
67
|
+
* @param {CodeceptJS.LocatorOrString} locator
|
|
68
|
+
* @param {Function} fn
|
|
69
|
+
* @return {Promise<*> | undefined}
|
|
70
|
+
*/
|
|
71
|
+
function eachElement(purpose, locator, fn) {
|
|
72
|
+
if (store.dryRun) return;
|
|
73
|
+
const helpers = Object.values(container.helpers());
|
|
74
|
+
|
|
75
|
+
const helper = helpers.filter(h => !!h._locate)[0];
|
|
76
|
+
|
|
77
|
+
if (!helper) {
|
|
78
|
+
throw new Error('No helper enabled with _locate method with returns a list of elements.');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!isAsyncFunction(fn)) {
|
|
82
|
+
throw new Error('Async function should be passed into each element');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const step = new Step(helper, `${purpose || 'each element'} within "${locator}"`);
|
|
86
|
+
step.helperMethod = '_locate';
|
|
87
|
+
// eachElement('select all users', 'locator', async (el) => {
|
|
88
|
+
event.dispatcher.emit(event.step.before, step);
|
|
89
|
+
|
|
90
|
+
return recorder.add('register each element wrapper', async () => {
|
|
91
|
+
event.emit(event.step.started, step);
|
|
92
|
+
const els = await helper._locate(locator);
|
|
93
|
+
output.debug(`Found ${els.length} elements for each elements to iterate`);
|
|
94
|
+
|
|
95
|
+
const errs = [];
|
|
96
|
+
let i = 0;
|
|
97
|
+
for (const el of els) {
|
|
98
|
+
try {
|
|
99
|
+
await fn(el, i);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
output.error(`eachElement: failed operation on element #${i} ${el}`);
|
|
102
|
+
errs.push(err);
|
|
103
|
+
}
|
|
104
|
+
i++;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (errs.length) {
|
|
108
|
+
event.dispatcher.emit(event.step.after, step);
|
|
109
|
+
event.emit(event.step.failed, step, errs[0]);
|
|
110
|
+
event.emit(event.step.finished, step);
|
|
111
|
+
throw errs[0];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
event.dispatcher.emit(event.step.after, step);
|
|
115
|
+
event.emit(event.step.passed, step, null);
|
|
116
|
+
event.emit(event.step.finished, step);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = function (config) {
|
|
121
|
+
config = Object.assign(defaultConfig, config);
|
|
122
|
+
|
|
123
|
+
if (config.registerGlobal) {
|
|
124
|
+
global.eachElement = eachElement;
|
|
125
|
+
}
|
|
126
|
+
return eachElement;
|
|
127
|
+
};
|
|
@@ -2,7 +2,7 @@ const event = require('../event');
|
|
|
2
2
|
const recorder = require('../recorder');
|
|
3
3
|
|
|
4
4
|
const defaultConfig = {
|
|
5
|
-
retries:
|
|
5
|
+
retries: 3,
|
|
6
6
|
defaultIgnoredSteps: [
|
|
7
7
|
'amOnPage',
|
|
8
8
|
'wait*',
|
|
@@ -11,6 +11,7 @@ const defaultConfig = {
|
|
|
11
11
|
'run*',
|
|
12
12
|
'have*',
|
|
13
13
|
],
|
|
14
|
+
factor: 1.5,
|
|
14
15
|
ignoredSteps: [],
|
|
15
16
|
};
|
|
16
17
|
|
|
@@ -36,9 +37,9 @@ const defaultConfig = {
|
|
|
36
37
|
*
|
|
37
38
|
* #### Configuration:
|
|
38
39
|
*
|
|
39
|
-
* * `retries` - number of retries (by default
|
|
40
|
+
* * `retries` - number of retries (by default 3),
|
|
40
41
|
* * `when` - function, when to perform a retry (accepts error as parameter)
|
|
41
|
-
* * `factor` - The exponential factor to use. Default is
|
|
42
|
+
* * `factor` - The exponential factor to use. Default is 1.5.
|
|
42
43
|
* * `minTimeout` - The number of milliseconds before starting the first retry. Default is 1000.
|
|
43
44
|
* * `maxTimeout` - The maximum number of milliseconds between two retries. Default is Infinity.
|
|
44
45
|
* * `randomize` - Randomizes the timeouts by multiplying with a factor between 1 to 2. Default is false.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const event = require('../event');
|
|
2
|
+
const TIMEOUT_ORDER = require('../step').TIMEOUT_ORDER;
|
|
2
3
|
|
|
3
4
|
const defaultConfig = {
|
|
4
5
|
timeout: 150,
|
|
5
|
-
|
|
6
|
+
overrideStepLimits: false,
|
|
6
7
|
noTimeoutSteps: [
|
|
7
8
|
'amOnPage',
|
|
8
9
|
'wait*',
|
|
@@ -33,7 +34,7 @@ const defaultConfig = {
|
|
|
33
34
|
* #### Configuration:
|
|
34
35
|
*
|
|
35
36
|
* * `timeout` - global step timeout, default 150 seconds
|
|
36
|
-
* * `
|
|
37
|
+
* * `overrideStepLimits` - whether to use timeouts set in plugin config to override step timeouts set in code with I.limitTime(x).action(...), default false
|
|
37
38
|
* * `noTimeoutSteps` - an array of steps with no timeout. Default:
|
|
38
39
|
* * `amOnPage`
|
|
39
40
|
* * `wait*`
|
|
@@ -49,7 +50,7 @@ const defaultConfig = {
|
|
|
49
50
|
* plugins: {
|
|
50
51
|
* stepTimeout: {
|
|
51
52
|
* enabled: true,
|
|
52
|
-
*
|
|
53
|
+
* overrideStepLimits: true,
|
|
53
54
|
* noTimeoutSteps: [
|
|
54
55
|
* 'scroll*', // ignore all scroll steps
|
|
55
56
|
* /Cookie/, // ignore all steps with a Cookie in it (by regexp)
|
|
@@ -85,6 +86,6 @@ module.exports = (config) => {
|
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
stepTimeout = stepTimeout === undefined ? config.timeout : stepTimeout;
|
|
88
|
-
step.
|
|
89
|
+
step.setTimeout(stepTimeout * 1000, config.overrideStepLimits ? TIMEOUT_ORDER.stepTimeoutHard : TIMEOUT_ORDER.stepTimeoutSoft);
|
|
89
90
|
});
|
|
90
91
|
};
|
package/lib/plugin/tryTo.js
CHANGED
|
@@ -42,6 +42,12 @@ const defaultConfig = {
|
|
|
42
42
|
* #### Multiple Conditional Assertions
|
|
43
43
|
*
|
|
44
44
|
* ```js
|
|
45
|
+
*
|
|
46
|
+
* Add assert requires first:
|
|
47
|
+
* ```js
|
|
48
|
+
* const assert = require('assert');
|
|
49
|
+
* ```
|
|
50
|
+
* Then use the assert:
|
|
45
51
|
* const result1 = await tryTo(() => I.see('Hello, user'));
|
|
46
52
|
* const result2 = await tryTo(() => I.seeElement('.welcome'));
|
|
47
53
|
* assert.ok(result1 && result2, 'Assertions were not succesful');
|
package/lib/recorder.js
CHANGED
|
@@ -178,7 +178,8 @@ module.exports = {
|
|
|
178
178
|
if (process.env.DEBUG) debug(`${currentQueue()}Queued | ${taskName}`);
|
|
179
179
|
|
|
180
180
|
return promise = Promise.resolve(promise).then((res) => {
|
|
181
|
-
|
|
181
|
+
// prefer options for non-conditional retries
|
|
182
|
+
const retryOpts = this.retries.sort((r1, r2) => r1.when && !r2.when).slice(-1).pop();
|
|
182
183
|
// no retries or unnamed tasks
|
|
183
184
|
if (!retryOpts || !taskName || !retry) {
|
|
184
185
|
const [promise, timer] = getTimeoutPromise(timeout, taskName);
|
package/lib/step.js
CHANGED
|
@@ -13,6 +13,27 @@ const STACK_LINE = 4;
|
|
|
13
13
|
* @param {string} name
|
|
14
14
|
*/
|
|
15
15
|
class Step {
|
|
16
|
+
static get TIMEOUT_ORDER() {
|
|
17
|
+
return {
|
|
18
|
+
/**
|
|
19
|
+
* timeouts set with order below zero only override timeouts of higher order if their value is smaller
|
|
20
|
+
*/
|
|
21
|
+
testOrSuite: -5,
|
|
22
|
+
/**
|
|
23
|
+
* 0-9 - designated for override of timeouts set from code, 5 is used by stepTimeout plugin when stepTimeout.config.overrideStepLimits=true
|
|
24
|
+
*/
|
|
25
|
+
stepTimeoutHard: 5,
|
|
26
|
+
/**
|
|
27
|
+
* 10-19 - designated for timeouts set from code, 15 is order of I.setTimeout(t) operation
|
|
28
|
+
*/
|
|
29
|
+
codeLimitTime: 15,
|
|
30
|
+
/**
|
|
31
|
+
* 20-29 - designated for timeout settings which could be overriden in tests code, 25 is used by stepTimeout plugin when stepTimeout.config.overrideStepLimits=false
|
|
32
|
+
*/
|
|
33
|
+
stepTimeoutSoft: 25,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
16
37
|
constructor(helper, name) {
|
|
17
38
|
/** @member {string} */
|
|
18
39
|
this.actor = 'I'; // I = actor
|
|
@@ -38,8 +59,40 @@ class Step {
|
|
|
38
59
|
this.metaStep = undefined;
|
|
39
60
|
/** @member {string} */
|
|
40
61
|
this.stack = '';
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
|
|
63
|
+
const timeouts = new Map();
|
|
64
|
+
/**
|
|
65
|
+
* @method
|
|
66
|
+
* @returns {number|undefined}
|
|
67
|
+
*/
|
|
68
|
+
this.getTimeout = function () {
|
|
69
|
+
let totalTimeout;
|
|
70
|
+
// iterate over all timeouts starting from highest values of order
|
|
71
|
+
new Map([...timeouts.entries()].sort().reverse()).forEach((timeout, order) => {
|
|
72
|
+
if (timeout !== undefined && (
|
|
73
|
+
// when orders >= 0 - timeout value overrides those set with higher order elements
|
|
74
|
+
order >= 0
|
|
75
|
+
|
|
76
|
+
// when `order < 0 && totalTimeout === undefined` - timeout is used when nothing is set by elements with higher order
|
|
77
|
+
|| totalTimeout === undefined
|
|
78
|
+
|
|
79
|
+
// when `order < 0` - timeout overrides higher values of timeout or 'no timeout' (totalTimeout === 0) set by elements with higher order
|
|
80
|
+
|| timeout > 0 && (timeout < totalTimeout || totalTimeout === 0)
|
|
81
|
+
)) {
|
|
82
|
+
totalTimeout = timeout;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return totalTimeout;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* @method
|
|
89
|
+
* @param {number} timeout - timeout in milliseconds or 0 if no timeout
|
|
90
|
+
* @param {number} order - order defines the priority of timeout, timeouts set with lower order override those set with higher order.
|
|
91
|
+
* When order below 0 value of timeout only override if new value is lower
|
|
92
|
+
*/
|
|
93
|
+
this.setTimeout = function (timeout, order) {
|
|
94
|
+
timeouts.set(order, timeout);
|
|
95
|
+
};
|
|
43
96
|
|
|
44
97
|
this.setTrace();
|
|
45
98
|
}
|
|
@@ -231,6 +284,8 @@ class MetaStep extends Step {
|
|
|
231
284
|
}
|
|
232
285
|
}
|
|
233
286
|
|
|
287
|
+
Step.TIMEOUTS = {};
|
|
288
|
+
|
|
234
289
|
/** @type {Class<MetaStep>} */
|
|
235
290
|
Step.MetaStep = MetaStep;
|
|
236
291
|
|
package/lib/utils.js
CHANGED
|
@@ -431,3 +431,23 @@ module.exports.modifierKeys = modifierKeys;
|
|
|
431
431
|
module.exports.isModifierKey = function (key) {
|
|
432
432
|
return modifierKeys.includes(key);
|
|
433
433
|
};
|
|
434
|
+
|
|
435
|
+
module.exports.requireWithFallback = function (...packages) {
|
|
436
|
+
const exists = function (pkg) {
|
|
437
|
+
try {
|
|
438
|
+
require.resolve(pkg);
|
|
439
|
+
} catch (e) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return true;
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
for (const pkg of packages) {
|
|
447
|
+
if (exists(pkg)) {
|
|
448
|
+
return require(pkg);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
throw new Error(`Cannot find modules ${packages.join(',')}`);
|
|
453
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeceptjs",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0-beta.1",
|
|
4
4
|
"description": "Supercharged End 2 End Testing Framework for NodeJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acceptance",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"allure-js-commons": "^1.3.2",
|
|
60
60
|
"arrify": "^2.0.1",
|
|
61
61
|
"axios": "^0.21.1",
|
|
62
|
+
"chai-deep-match": "^1.2.1",
|
|
62
63
|
"chalk": "^4.1.0",
|
|
63
64
|
"commander": "^2.20.3",
|
|
64
65
|
"cross-spawn": "^7.0.3",
|
|
@@ -72,6 +73,7 @@
|
|
|
72
73
|
"gherkin": "^5.1.0",
|
|
73
74
|
"glob": "^6.0.1",
|
|
74
75
|
"inquirer": "^6.5.2",
|
|
76
|
+
"joi": "^17.6.0",
|
|
75
77
|
"js-beautify": "^1.11.0",
|
|
76
78
|
"lodash.clonedeep": "^4.5.0",
|
|
77
79
|
"lodash.merge": "^4.6.2",
|
|
@@ -97,7 +99,7 @@
|
|
|
97
99
|
"@wdio/selenium-standalone-service": "^5.16.10",
|
|
98
100
|
"@wdio/utils": "^5.23.0",
|
|
99
101
|
"apollo-server-express": "^2.19.0",
|
|
100
|
-
"chai": "^3.
|
|
102
|
+
"chai": "^3.5.0",
|
|
101
103
|
"chai-as-promised": "^5.2.0",
|
|
102
104
|
"chai-subset": "^1.6.0",
|
|
103
105
|
"contributor-faces": "^1.0.3",
|
|
@@ -110,7 +112,7 @@
|
|
|
110
112
|
"eslint-plugin-mocha": "^6.3.0",
|
|
111
113
|
"expect": "^26.6.2",
|
|
112
114
|
"express": "^4.17.1",
|
|
113
|
-
"faker": "
|
|
115
|
+
"faker": "5.5.3",
|
|
114
116
|
"form-data": "^3.0.0",
|
|
115
117
|
"graphql": "^14.6.0",
|
|
116
118
|
"husky": "^4.3.5",
|
|
@@ -120,7 +122,7 @@
|
|
|
120
122
|
"mocha-parallel-tests": "^2.3.0",
|
|
121
123
|
"nightmare": "^3.0.2",
|
|
122
124
|
"nodemon": "^1.19.4",
|
|
123
|
-
"playwright": "^1.
|
|
125
|
+
"playwright": "^1.18.1",
|
|
124
126
|
"puppeteer": "^10.0.0",
|
|
125
127
|
"qrcode-terminal": "^0.12.0",
|
|
126
128
|
"rosie": "^1.6.0",
|
package/translations/pt-BR.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
I: 'Eu',
|
|
3
|
+
contexts: {
|
|
4
|
+
Feature: 'Funcionalidade',
|
|
5
|
+
Scenario: 'Cenário',
|
|
6
|
+
Before: 'Antes',
|
|
7
|
+
After: 'Depois',
|
|
8
|
+
BeforeSuite: 'AntesDaSuite',
|
|
9
|
+
AfterSuite: 'DepoisDaSuite',
|
|
10
|
+
},
|
|
3
11
|
actions: {
|
|
4
12
|
amOutsideAngularApp: 'naoEstouEmAplicacaoAngular',
|
|
5
13
|
amInsideAngularApp: 'estouNaAplicacaoAngular',
|
package/typings/index.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
/// <reference path="./types.d.ts" />
|
|
3
3
|
/// <reference types="webdriverio" />
|
|
4
4
|
/// <reference path="./Mocha.d.ts" />
|
|
5
|
+
/// <reference types="joi" />
|
|
6
|
+
/// <reference types="playwright" />
|
|
5
7
|
|
|
6
8
|
declare namespace CodeceptJS {
|
|
7
9
|
type WithTranslation<T> = T &
|
|
@@ -10,6 +12,8 @@ declare namespace CodeceptJS {
|
|
|
10
12
|
type Cookie = {
|
|
11
13
|
name: string;
|
|
12
14
|
value: string;
|
|
15
|
+
domain?: string,
|
|
16
|
+
path?: string,
|
|
13
17
|
};
|
|
14
18
|
|
|
15
19
|
interface PageScrollPosition {
|