codeceptjs 3.3.0 → 3.3.3
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 +50 -1
- package/README.md +6 -1
- package/docs/api.md +1 -1
- package/docs/bdd.md +1 -0
- package/docs/best.md +1 -1
- package/docs/build/ApiDataFactory.js +4 -3
- package/docs/build/Appium.js +21 -16
- package/docs/build/GraphQL.js +4 -2
- package/docs/build/GraphQLDataFactory.js +3 -3
- package/docs/build/JSONResponse.js +1 -1
- package/docs/build/Nightmare.js +54 -25
- package/docs/build/Playwright.js +105 -52
- package/docs/build/Protractor.js +72 -34
- package/docs/build/Puppeteer.js +80 -37
- package/docs/build/REST.js +5 -2
- package/docs/build/TestCafe.js +54 -23
- package/docs/build/WebDriver.js +115 -67
- package/docs/changelog.md +50 -1
- package/docs/custom-helpers.md +1 -1
- package/docs/data.md +2 -2
- package/docs/helpers/ApiDataFactory.md +7 -3
- package/docs/helpers/Appium.md +217 -175
- package/docs/helpers/GraphQL.md +6 -0
- package/docs/helpers/GraphQLDataFactory.md +3 -3
- package/docs/helpers/JSONResponse.md +1 -1
- package/docs/helpers/Nightmare.md +98 -45
- package/docs/helpers/Playwright.md +151 -59
- package/docs/helpers/Puppeteer.md +103 -26
- package/docs/helpers/REST.md +1 -1
- package/docs/helpers/TestCafe.md +77 -22
- package/docs/helpers/WebDriver.md +150 -62
- package/docs/index.md +1 -1
- package/docs/locators.md +1 -1
- package/docs/webapi/amOnPage.mustache +2 -1
- package/docs/webapi/appendField.mustache +2 -1
- package/docs/webapi/attachFile.mustache +2 -1
- package/docs/webapi/checkOption.mustache +2 -1
- package/docs/webapi/clearCookie.mustache +2 -1
- package/docs/webapi/clearField.mustache +1 -0
- package/docs/webapi/click.mustache +2 -1
- package/docs/webapi/clickLink.mustache +2 -1
- package/docs/webapi/closeCurrentTab.mustache +6 -4
- package/docs/webapi/closeOtherTabs.mustache +6 -4
- package/docs/webapi/dontSee.mustache +1 -0
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +1 -0
- package/docs/webapi/dontSeeCookie.mustache +2 -1
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +2 -1
- package/docs/webapi/dontSeeElement.mustache +2 -1
- package/docs/webapi/dontSeeElementInDOM.mustache +2 -1
- package/docs/webapi/dontSeeInCurrentUrl.mustache +2 -1
- package/docs/webapi/dontSeeInField.mustache +2 -1
- package/docs/webapi/dontSeeInSource.mustache +1 -0
- package/docs/webapi/dontSeeInTitle.mustache +2 -1
- package/docs/webapi/doubleClick.mustache +1 -0
- package/docs/webapi/downloadFile.mustache +2 -1
- package/docs/webapi/dragAndDrop.mustache +1 -0
- package/docs/webapi/dragSlider.mustache +2 -1
- package/docs/webapi/executeAsyncScript.mustache +1 -1
- package/docs/webapi/executeScript.mustache +1 -1
- package/docs/webapi/fillField.mustache +1 -0
- package/docs/webapi/forceClick.mustache +1 -0
- package/docs/webapi/forceRightClick.mustache +1 -0
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +2 -1
- package/docs/webapi/moveCursorTo.mustache +1 -0
- package/docs/webapi/openNewTab.mustache +6 -4
- package/docs/webapi/pressKey.mustache +2 -1
- package/docs/webapi/pressKeyDown.mustache +1 -0
- package/docs/webapi/pressKeyUp.mustache +1 -0
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +1 -0
- package/docs/webapi/refreshPage.mustache +1 -0
- package/docs/webapi/resizeWindow.mustache +2 -1
- package/docs/webapi/rightClick.mustache +1 -0
- package/docs/webapi/saveElementScreenshot.mustache +1 -0
- package/docs/webapi/saveScreenshot.mustache +2 -1
- package/docs/webapi/say.mustache +2 -1
- package/docs/webapi/scrollIntoView.mustache +1 -0
- package/docs/webapi/scrollPageToBottom.mustache +1 -0
- package/docs/webapi/scrollPageToTop.mustache +1 -0
- package/docs/webapi/scrollTo.mustache +2 -1
- package/docs/webapi/see.mustache +2 -1
- package/docs/webapi/seeAttributesOnElements.mustache +2 -1
- package/docs/webapi/seeCheckboxIsChecked.mustache +1 -0
- package/docs/webapi/seeCookie.mustache +1 -0
- package/docs/webapi/seeCssPropertiesOnElements.mustache +2 -1
- package/docs/webapi/seeCurrentUrlEquals.mustache +2 -1
- package/docs/webapi/seeElement.mustache +2 -1
- package/docs/webapi/seeElementInDOM.mustache +1 -0
- package/docs/webapi/seeInCurrentUrl.mustache +2 -1
- package/docs/webapi/seeInField.mustache +1 -0
- package/docs/webapi/seeInPopup.mustache +1 -0
- package/docs/webapi/seeInSource.mustache +2 -1
- package/docs/webapi/seeInTitle.mustache +2 -1
- package/docs/webapi/seeNumberOfElements.mustache +1 -0
- package/docs/webapi/seeNumberOfVisibleElements.mustache +1 -0
- package/docs/webapi/seeTextEquals.mustache +2 -1
- package/docs/webapi/seeTitleEquals.mustache +6 -5
- package/docs/webapi/selectOption.mustache +1 -0
- package/docs/webapi/setCookie.mustache +1 -0
- package/docs/webapi/setGeoLocation.mustache +1 -0
- package/docs/webapi/switchTo.mustache +2 -1
- package/docs/webapi/switchToNextTab.mustache +8 -7
- package/docs/webapi/switchToPreviousTab.mustache +8 -7
- package/docs/webapi/type.mustache +1 -0
- package/docs/webapi/uncheckOption.mustache +2 -1
- package/docs/webapi/wait.mustache +2 -1
- package/docs/webapi/waitForClickable.mustache +2 -1
- package/docs/webapi/waitForDetached.mustache +2 -1
- package/docs/webapi/waitForElement.mustache +2 -1
- package/docs/webapi/waitForEnabled.mustache +2 -1
- package/docs/webapi/waitForFunction.mustache +1 -0
- package/docs/webapi/waitForInvisible.mustache +2 -1
- package/docs/webapi/waitForText.mustache +2 -1
- package/docs/webapi/waitForValue.mustache +1 -0
- package/docs/webapi/waitForVisible.mustache +1 -0
- package/docs/webapi/waitInUrl.mustache +2 -1
- package/docs/webapi/waitNumberOfVisibleElements.mustache +2 -1
- package/docs/webapi/waitToHide.mustache +2 -1
- package/docs/webapi/waitUrlEquals.mustache +2 -1
- package/lib/cli.js +1 -1
- package/lib/command/definitions.js +9 -0
- package/lib/command/run-workers.js +1 -1
- package/lib/command/run.js +2 -2
- package/lib/command/workers/runTests.js +55 -0
- package/lib/helper/ApiDataFactory.js +4 -3
- package/lib/helper/Appium.js +2 -7
- package/lib/helper/GraphQL.js +4 -2
- package/lib/helper/GraphQLDataFactory.js +3 -3
- package/lib/helper/JSONResponse.js +1 -1
- package/lib/helper/Playwright.js +28 -17
- package/lib/helper/REST.js +5 -2
- package/lib/helper/WebDriver.js +4 -0
- package/lib/interfaces/bdd.js +5 -0
- package/lib/listener/steps.js +1 -0
- package/lib/output.js +4 -0
- package/lib/plugin/fakerTransform.js +1 -1
- package/lib/plugin/stepByStepReport.js +8 -6
- package/lib/workers.js +12 -0
- package/package.json +3 -3
- package/typings/types.d.ts +534 -112
|
@@ -6,4 +6,5 @@ I.waitForDetached('#popup');
|
|
|
6
6
|
```
|
|
7
7
|
|
|
8
8
|
@param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
9
|
-
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
9
|
+
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
10
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
|
@@ -7,4 +7,5 @@ I.waitForElement('.btn.continue', 5); // wait for 5 secs
|
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
@param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
10
|
-
@param {number} [sec] (optional, `1` by default) time in seconds to wait
|
|
10
|
+
@param {number} [sec] (optional, `1` by default) time in seconds to wait
|
|
11
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
|
@@ -2,4 +2,5 @@ Waits for element to become enabled (by default waits for 1sec).
|
|
|
2
2
|
Element can be located by CSS or XPath.
|
|
3
3
|
|
|
4
4
|
@param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
5
|
-
@param {number} [sec=1] (optional) time in seconds to wait, 1 by default.
|
|
5
|
+
@param {number} [sec=1] (optional) time in seconds to wait, 1 by default.
|
|
6
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
|
@@ -14,3 +14,4 @@ I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and
|
|
|
14
14
|
@param {string|function} fn to be executed in browser context.
|
|
15
15
|
@param {any[]|number} [argsOrSec] (optional, `1` by default) arguments for function or seconds.
|
|
16
16
|
@param {number} [sec] (optional, `1` by default) time in seconds to wait
|
|
17
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
|
@@ -6,4 +6,5 @@ I.waitForInvisible('#popup');
|
|
|
6
6
|
```
|
|
7
7
|
|
|
8
8
|
@param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
9
|
-
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
9
|
+
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
10
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
|
@@ -9,4 +9,5 @@ I.waitForText('Thank you, form has been submitted', 5, '#modal');
|
|
|
9
9
|
|
|
10
10
|
@param {string }text to wait for.
|
|
11
11
|
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
12
|
-
@param {CodeceptJS.LocatorOrString} [context] (optional) element located by CSS|XPath|strict locator.
|
|
12
|
+
@param {CodeceptJS.LocatorOrString} [context] (optional) element located by CSS|XPath|strict locator.
|
|
13
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
|
@@ -5,4 +5,5 @@ I.waitInUrl('/info', 2);
|
|
|
5
5
|
```
|
|
6
6
|
|
|
7
7
|
@param {string} urlPart value to check.
|
|
8
|
-
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
8
|
+
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
9
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
|
@@ -6,4 +6,5 @@ I.waitNumberOfVisibleElements('a', 3);
|
|
|
6
6
|
|
|
7
7
|
@param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
8
8
|
@param {number} num number of elements.
|
|
9
|
-
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
9
|
+
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
10
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
|
@@ -6,4 +6,5 @@ I.waitToHide('#popup');
|
|
|
6
6
|
```
|
|
7
7
|
|
|
8
8
|
@param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
9
|
-
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
9
|
+
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
10
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
|
@@ -6,4 +6,5 @@ I.waitUrlEquals('http://127.0.0.1:8000/info');
|
|
|
6
6
|
```
|
|
7
7
|
|
|
8
8
|
@param {string} urlPart value to check.
|
|
9
|
-
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
9
|
+
@param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
10
|
+
[!] returns a _promise_ which is synchronized internally by recorder
|
package/lib/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ class Cli extends Base {
|
|
|
19
19
|
if (opts.debug) level = 2;
|
|
20
20
|
if (opts.verbose) level = 3;
|
|
21
21
|
output.level(level);
|
|
22
|
-
output.print(`CodeceptJS v${require('./codecept').version()}`);
|
|
22
|
+
output.print(`CodeceptJS v${require('./codecept').version()} ${output.standWithUkraine()}`);
|
|
23
23
|
output.print(`Using test root "${global.codecept_dir}"`);
|
|
24
24
|
|
|
25
25
|
const showSteps = level >= 1;
|
|
@@ -146,10 +146,19 @@ module.exports = function (genPath, options) {
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
let autoLogin;
|
|
150
|
+
if (config.plugins.autoLogin) {
|
|
151
|
+
autoLogin = config.plugins.autoLogin.inject;
|
|
152
|
+
}
|
|
153
|
+
|
|
149
154
|
const supportObject = new Map();
|
|
150
155
|
supportObject.set('I', 'I');
|
|
151
156
|
supportObject.set('current', 'any');
|
|
152
157
|
|
|
158
|
+
if (autoLogin) {
|
|
159
|
+
supportObject.set(autoLogin, 'any');
|
|
160
|
+
}
|
|
161
|
+
|
|
153
162
|
if (customHelpers.length > 0) {
|
|
154
163
|
hasCustomHelper = true;
|
|
155
164
|
}
|
|
@@ -25,7 +25,7 @@ module.exports = async function (workerCount, options) {
|
|
|
25
25
|
|
|
26
26
|
const numberOfWorkers = parseInt(workerCount, 10);
|
|
27
27
|
|
|
28
|
-
output.print(`CodeceptJS v${require('../codecept').version()}`);
|
|
28
|
+
output.print(`CodeceptJS v${require('../codecept').version()} ${output.standWithUkraine()}`);
|
|
29
29
|
output.print(`Running tests in ${output.styles.bold(numberOfWorkers)} workers...`);
|
|
30
30
|
output.print();
|
|
31
31
|
|
package/lib/command/run.js
CHANGED
|
@@ -23,8 +23,8 @@ module.exports = async function (test, options) {
|
|
|
23
23
|
try {
|
|
24
24
|
codecept.init(testRoot);
|
|
25
25
|
await codecept.bootstrap();
|
|
26
|
-
codecept.loadTests();
|
|
27
|
-
await codecept.run(
|
|
26
|
+
codecept.loadTests(test);
|
|
27
|
+
await codecept.run();
|
|
28
28
|
} catch (err) {
|
|
29
29
|
printError(err);
|
|
30
30
|
process.exitCode = 1;
|
|
@@ -114,7 +114,16 @@ function initializeListeners() {
|
|
|
114
114
|
parent.title = test.parent.title;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
if (test.opts) {
|
|
118
|
+
Object.keys(test.opts).forEach(k => {
|
|
119
|
+
if (typeof test.opts[k] === 'object') delete test.opts[k];
|
|
120
|
+
if (typeof test.opts[k] === 'function') delete test.opts[k];
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
117
124
|
return {
|
|
125
|
+
opts: test.opts || {},
|
|
126
|
+
tags: test.tags || [],
|
|
118
127
|
id: test.id,
|
|
119
128
|
workerIndex,
|
|
120
129
|
retries: test._retries,
|
|
@@ -126,6 +135,46 @@ function initializeListeners() {
|
|
|
126
135
|
};
|
|
127
136
|
}
|
|
128
137
|
|
|
138
|
+
function simplifyStep(step, err = null) {
|
|
139
|
+
step = { ...step };
|
|
140
|
+
|
|
141
|
+
if (step.startTime && !step.duration) {
|
|
142
|
+
const end = new Date();
|
|
143
|
+
step.duration = end - step.startTime;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (step.err) {
|
|
147
|
+
err = simplifyError(step.err);
|
|
148
|
+
step.status = 'failed';
|
|
149
|
+
} else if (err) {
|
|
150
|
+
err = simplifyError(err);
|
|
151
|
+
step.status = 'failed';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const parent = {};
|
|
155
|
+
if (step.metaStep) {
|
|
156
|
+
parent.title = step.metaStep.actor;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (step.opts) {
|
|
160
|
+
Object.keys(step.opts).forEach(k => {
|
|
161
|
+
if (typeof step.opts[k] === 'object') delete step.opts[k];
|
|
162
|
+
if (typeof step.opts[k] === 'function') delete step.opts[k];
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
opts: step.opts || {},
|
|
168
|
+
workerIndex,
|
|
169
|
+
title: step.name,
|
|
170
|
+
status: step.status,
|
|
171
|
+
duration: step.duration || 0,
|
|
172
|
+
err,
|
|
173
|
+
parent,
|
|
174
|
+
test: simplifyTest(step.test),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
129
178
|
collectStats();
|
|
130
179
|
// suite
|
|
131
180
|
event.dispatcher.on(event.suite.before, suite => sendToParentThread({ event: event.suite.before, workerIndex, data: simplifyTest(suite) }));
|
|
@@ -144,6 +193,12 @@ function initializeListeners() {
|
|
|
144
193
|
event.dispatcher.on(event.test.started, test => sendToParentThread({ event: event.test.started, workerIndex, data: simplifyTest(test) }));
|
|
145
194
|
event.dispatcher.on(event.test.skipped, test => sendToParentThread({ event: event.test.skipped, workerIndex, data: simplifyTest(test) }));
|
|
146
195
|
|
|
196
|
+
// steps
|
|
197
|
+
event.dispatcher.on(event.step.finished, step => sendToParentThread({ event: event.step.finished, workerIndex, data: simplifyStep(step) }));
|
|
198
|
+
event.dispatcher.on(event.step.started, step => sendToParentThread({ event: event.step.started, workerIndex, data: simplifyStep(step) }));
|
|
199
|
+
event.dispatcher.on(event.step.passed, step => sendToParentThread({ event: event.step.passed, workerIndex, data: simplifyStep(step) }));
|
|
200
|
+
event.dispatcher.on(event.step.failed, step => sendToParentThread({ event: event.step.failed, workerIndex, data: simplifyStep(step) }));
|
|
201
|
+
|
|
147
202
|
event.dispatcher.on(event.hook.failed, (test, err) => sendToParentThread({ event: event.hook.failed, workerIndex, data: simplifyTest(test, err) }));
|
|
148
203
|
event.dispatcher.on(event.hook.passed, (test, err) => sendToParentThread({ event: event.hook.passed, workerIndex, data: simplifyTest(test, err) }));
|
|
149
204
|
event.dispatcher.on(event.all.failures, (data) => sendToParentThread({ event: event.all.failures, workerIndex, data }));
|
|
@@ -36,7 +36,7 @@ const REST = require('./REST');
|
|
|
36
36
|
* Install [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://www.npmjs.com/package/faker) libraries.
|
|
37
37
|
*
|
|
38
38
|
* ```sh
|
|
39
|
-
* npm i rosie faker --save-dev
|
|
39
|
+
* npm i rosie @faker-js/faker --save-dev
|
|
40
40
|
* ```
|
|
41
41
|
*
|
|
42
42
|
* Create a factory file for a resource.
|
|
@@ -46,8 +46,8 @@ const REST = require('./REST');
|
|
|
46
46
|
* ```js
|
|
47
47
|
* // tests/factories/posts.js
|
|
48
48
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
49
|
+
* const Factory = require('rosie').Factory;
|
|
50
|
+
* const faker = require('@faker-js/faker');
|
|
51
51
|
*
|
|
52
52
|
* module.exports = new Factory()
|
|
53
53
|
* // no need to set id, it will be set by REST API
|
|
@@ -264,6 +264,7 @@ class ApiDataFactory extends Helper {
|
|
|
264
264
|
* @param {*} factory factory to use
|
|
265
265
|
* @param {*} params predefined parameters
|
|
266
266
|
* @param {*} options options for programmatically generate the attributes
|
|
267
|
+
* @returns {Promise<*>}
|
|
267
268
|
*/
|
|
268
269
|
have(factory, params, options) {
|
|
269
270
|
const item = this._createItem(factory, params, options);
|
package/lib/helper/Appium.js
CHANGED
|
@@ -124,6 +124,7 @@ const webRoot = 'body';
|
|
|
124
124
|
class Appium extends Webdriver {
|
|
125
125
|
/**
|
|
126
126
|
* Appium Special Methods for Mobile only
|
|
127
|
+
* @augments WebDriver
|
|
127
128
|
*/
|
|
128
129
|
|
|
129
130
|
constructor(config) {
|
|
@@ -331,7 +332,6 @@ class Appium extends Webdriver {
|
|
|
331
332
|
*
|
|
332
333
|
* @param {*} caps
|
|
333
334
|
* @param {*} fn
|
|
334
|
-
* @return {Promise<any>}
|
|
335
335
|
*/
|
|
336
336
|
async runOnIOS(caps, fn) {
|
|
337
337
|
if (this.platform !== 'ios') return;
|
|
@@ -374,7 +374,6 @@ class Appium extends Webdriver {
|
|
|
374
374
|
*
|
|
375
375
|
* @param {*} caps
|
|
376
376
|
* @param {*} fn
|
|
377
|
-
* @return {Promise<any>}
|
|
378
377
|
*/
|
|
379
378
|
async runOnAndroid(caps, fn) {
|
|
380
379
|
if (this.platform !== 'android') return;
|
|
@@ -395,7 +394,6 @@ class Appium extends Webdriver {
|
|
|
395
394
|
* ```
|
|
396
395
|
*
|
|
397
396
|
* @param {*} fn
|
|
398
|
-
* @return {Promise<any>}
|
|
399
397
|
*/
|
|
400
398
|
/* eslint-disable */
|
|
401
399
|
async runInWeb(fn) {
|
|
@@ -599,7 +597,6 @@ class Appium extends Webdriver {
|
|
|
599
597
|
* ```
|
|
600
598
|
*
|
|
601
599
|
* @param {'LANDSCAPE'|'PORTRAIT'} orientation LANDSCAPE or PORTRAIT
|
|
602
|
-
* @return {Promise<any>}
|
|
603
600
|
*
|
|
604
601
|
* Appium: support Android and iOS
|
|
605
602
|
*/
|
|
@@ -728,7 +725,6 @@ class Appium extends Webdriver {
|
|
|
728
725
|
* Switch to the specified context.
|
|
729
726
|
*
|
|
730
727
|
* @param {*} context the context to switch to
|
|
731
|
-
|
|
732
728
|
*/
|
|
733
729
|
async _switchToContext(context) {
|
|
734
730
|
return this.browser.switchContext(context);
|
|
@@ -774,7 +770,7 @@ class Appium extends Webdriver {
|
|
|
774
770
|
* // or set context explicitly
|
|
775
771
|
* I.switchToNative('SOME_OTHER_CONTEXT');
|
|
776
772
|
* ```
|
|
777
|
-
* @param {*} context
|
|
773
|
+
* @param {*} [context]
|
|
778
774
|
* @return {Promise<void>}
|
|
779
775
|
*/
|
|
780
776
|
async switchToNative(context = null) {
|
|
@@ -834,7 +830,6 @@ class Appium extends Webdriver {
|
|
|
834
830
|
* ```
|
|
835
831
|
*
|
|
836
832
|
* @param {object} settings object
|
|
837
|
-
* @return {Promise<any>}
|
|
838
833
|
*
|
|
839
834
|
* Appium: support Android and iOS
|
|
840
835
|
*/
|
package/lib/helper/GraphQL.js
CHANGED
|
@@ -112,15 +112,15 @@ class GraphQL extends Helper {
|
|
|
112
112
|
*
|
|
113
113
|
* @param {object} operation
|
|
114
114
|
* @param {object} headers
|
|
115
|
+
* @return {object} graphQLRequest
|
|
115
116
|
*/
|
|
116
117
|
_prepareGraphQLRequest(operation, headers) {
|
|
117
|
-
|
|
118
|
+
return {
|
|
118
119
|
baseURL: this.options.endpoint,
|
|
119
120
|
method: 'POST',
|
|
120
121
|
data: operation,
|
|
121
122
|
headers,
|
|
122
123
|
};
|
|
123
|
-
return request;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
/**
|
|
@@ -142,6 +142,7 @@ class GraphQL extends Helper {
|
|
|
142
142
|
* @param {object} variables that may go along with the query
|
|
143
143
|
* @param {object} options are additional query options
|
|
144
144
|
* @param {object} headers
|
|
145
|
+
* @return Promise<any>
|
|
145
146
|
*/
|
|
146
147
|
async sendQuery(query, variables, options = {}, headers = {}) {
|
|
147
148
|
if (typeof query !== 'string') {
|
|
@@ -181,6 +182,7 @@ class GraphQL extends Helper {
|
|
|
181
182
|
* @param {object} variables that may go along with the mutation
|
|
182
183
|
* @param {object} options are additional query options
|
|
183
184
|
* @param {object} headers
|
|
185
|
+
* @return Promise<any>
|
|
184
186
|
*/
|
|
185
187
|
async sendMutation(mutation, variables, options = {}, headers = {}) {
|
|
186
188
|
if (typeof mutation !== 'string') {
|
|
@@ -36,7 +36,7 @@ const GraphQL = require('./GraphQL');
|
|
|
36
36
|
* Install [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://www.npmjs.com/package/faker) libraries.
|
|
37
37
|
*
|
|
38
38
|
* ```sh
|
|
39
|
-
* npm i rosie faker --save-dev
|
|
39
|
+
* npm i rosie @faker-js/faker --save-dev
|
|
40
40
|
* ```
|
|
41
41
|
*
|
|
42
42
|
* Create a factory file for a resource.
|
|
@@ -46,8 +46,8 @@ const GraphQL = require('./GraphQL');
|
|
|
46
46
|
* ```js
|
|
47
47
|
* // tests/factories/users.js
|
|
48
48
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
49
|
+
* const Factory = require('rosie').Factory;
|
|
50
|
+
* const faker = require('@faker-js/faker');
|
|
51
51
|
*
|
|
52
52
|
* // Used with a constructor function passed to Factory, so that the final build
|
|
53
53
|
* // object matches the necessary pattern to be sent as the variables object.
|
|
@@ -218,7 +218,7 @@ class JSONResponse extends Helper {
|
|
|
218
218
|
* Use it to perform custom checks of response data
|
|
219
219
|
*
|
|
220
220
|
* ```js
|
|
221
|
-
* I.seeResponseValidByCallback({ data, status, expect } => {
|
|
221
|
+
* I.seeResponseValidByCallback(({ data, status, expect }) => {
|
|
222
222
|
* expect(status).to.eql(200);
|
|
223
223
|
* expect(data).keys.to.include(['user', 'company']);
|
|
224
224
|
* });
|
package/lib/helper/Playwright.js
CHANGED
|
@@ -92,6 +92,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
92
92
|
* * `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000.
|
|
93
93
|
* * `basicAuth`: (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
|
|
94
94
|
* * `windowSize`: (optional) default window size. Set a dimension like `640x480`.
|
|
95
|
+
* * `colorScheme`: (optional) default color scheme. Possible values: `dark` | `light` | `no-preference`.
|
|
95
96
|
* * `userAgent`: (optional) user-agent string.
|
|
96
97
|
* * `locale`: (optional) locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ...
|
|
97
98
|
* * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
|
|
@@ -212,7 +213,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
212
213
|
* }
|
|
213
214
|
* ```
|
|
214
215
|
*
|
|
215
|
-
* #### Example #7: Launch test with a
|
|
216
|
+
* #### Example #7: Launch test with a specific user locale
|
|
216
217
|
*
|
|
217
218
|
* ```js
|
|
218
219
|
* {
|
|
@@ -225,6 +226,19 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
225
226
|
* }
|
|
226
227
|
* ```
|
|
227
228
|
*
|
|
229
|
+
* * #### Example #8: Launch test with a specific color scheme
|
|
230
|
+
*
|
|
231
|
+
* ```js
|
|
232
|
+
* {
|
|
233
|
+
* helpers: {
|
|
234
|
+
* Playwright : {
|
|
235
|
+
* url: "http://localhost",
|
|
236
|
+
* colorScheme: "dark",
|
|
237
|
+
* }
|
|
238
|
+
* }
|
|
239
|
+
* }
|
|
240
|
+
* ```
|
|
241
|
+
*
|
|
228
242
|
* Note: When connecting to remote browser `show` and specific `chrome` options (e.g. `headless` or `devtools`) are ignored.
|
|
229
243
|
*
|
|
230
244
|
* ## Access From Helpers
|
|
@@ -273,7 +287,7 @@ class Playwright extends Helper {
|
|
|
273
287
|
waitForAction: 100,
|
|
274
288
|
waitForTimeout: 1000,
|
|
275
289
|
pressKeyDelay: 10,
|
|
276
|
-
timeout:
|
|
290
|
+
timeout: 5000,
|
|
277
291
|
fullPageScreenshots: false,
|
|
278
292
|
disableScreenshots: false,
|
|
279
293
|
ignoreLog: ['warning', 'log'],
|
|
@@ -411,6 +425,7 @@ class Playwright extends Helper {
|
|
|
411
425
|
if (this.storageState) contextOptions.storageState = this.storageState;
|
|
412
426
|
if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent;
|
|
413
427
|
if (this.options.locale) contextOptions.locale = this.options.locale;
|
|
428
|
+
if (this.options.colorScheme) contextOptions.colorScheme = this.options.colorScheme;
|
|
414
429
|
if (!this.browserContext || !restartsSession()) {
|
|
415
430
|
this.browserContext = await this.browser.newContext(contextOptions); // Adding the HTTPSError ignore in the context so that we can ignore those errors
|
|
416
431
|
}
|
|
@@ -538,7 +553,7 @@ class Playwright extends Helper {
|
|
|
538
553
|
* ```
|
|
539
554
|
*
|
|
540
555
|
* @param {string} description used to show in logs.
|
|
541
|
-
* @param {function} fn async function that executed with Playwright helper as
|
|
556
|
+
* @param {function} fn async function that executed with Playwright helper as argumen
|
|
542
557
|
*/
|
|
543
558
|
usePlaywrightTo(description, fn) {
|
|
544
559
|
return this._useTo(...arguments);
|
|
@@ -851,7 +866,7 @@ class Playwright extends Helper {
|
|
|
851
866
|
/**
|
|
852
867
|
* {{> dragAndDrop }}
|
|
853
868
|
*
|
|
854
|
-
* [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument.
|
|
869
|
+
* @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument.
|
|
855
870
|
*
|
|
856
871
|
* ```js
|
|
857
872
|
* // specify coordinates for source position
|
|
@@ -886,7 +901,7 @@ class Playwright extends Helper {
|
|
|
886
901
|
/**
|
|
887
902
|
* {{> scrollPageToBottom }}
|
|
888
903
|
*/
|
|
889
|
-
scrollPageToBottom() {
|
|
904
|
+
async scrollPageToBottom() {
|
|
890
905
|
return this.executeScript(() => {
|
|
891
906
|
const body = document.body;
|
|
892
907
|
const html = document.documentElement;
|
|
@@ -972,8 +987,6 @@ class Playwright extends Helper {
|
|
|
972
987
|
* ```js
|
|
973
988
|
* const elements = await this.helpers['Playwright']._locate({name: 'password'});
|
|
974
989
|
* ```
|
|
975
|
-
*
|
|
976
|
-
*
|
|
977
990
|
*/
|
|
978
991
|
async _locate(locator) {
|
|
979
992
|
const context = await this.context || await this._getContext();
|
|
@@ -1186,6 +1199,7 @@ class Playwright extends Helper {
|
|
|
1186
1199
|
* ```
|
|
1187
1200
|
*
|
|
1188
1201
|
* @param {string} [fileName] set filename for downloaded file
|
|
1202
|
+
* @return {Promise<void>}
|
|
1189
1203
|
*/
|
|
1190
1204
|
async handleDownloads(fileName = 'downloads') {
|
|
1191
1205
|
this.page.waitForEvent('download').then(async (download) => {
|
|
@@ -1204,7 +1218,7 @@ class Playwright extends Helper {
|
|
|
1204
1218
|
/**
|
|
1205
1219
|
* {{> click }}
|
|
1206
1220
|
*
|
|
1207
|
-
* [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument.
|
|
1221
|
+
* @param {any} [opts] [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument.
|
|
1208
1222
|
*
|
|
1209
1223
|
* Examples:
|
|
1210
1224
|
*
|
|
@@ -1669,7 +1683,6 @@ class Playwright extends Helper {
|
|
|
1669
1683
|
*
|
|
1670
1684
|
* @param {string|function} fn function to be executed in browser context.
|
|
1671
1685
|
* @param {any} [arg] optional argument to pass to the function
|
|
1672
|
-
* @return {Promise<any>}
|
|
1673
1686
|
*/
|
|
1674
1687
|
async executeScript(fn, arg) {
|
|
1675
1688
|
let context = this.page;
|
|
@@ -1992,7 +2005,7 @@ class Playwright extends Helper {
|
|
|
1992
2005
|
test.artifacts = {};
|
|
1993
2006
|
}
|
|
1994
2007
|
|
|
1995
|
-
if (this.options.recordVideo && this.page.video()) {
|
|
2008
|
+
if (this.options.recordVideo && this.page && this.page.video()) {
|
|
1996
2009
|
test.artifacts.video = await this.page.video().path();
|
|
1997
2010
|
}
|
|
1998
2011
|
|
|
@@ -2004,7 +2017,7 @@ class Playwright extends Helper {
|
|
|
2004
2017
|
}
|
|
2005
2018
|
|
|
2006
2019
|
async _passed(test) {
|
|
2007
|
-
if (this.options.recordVideo && this.page.video()) {
|
|
2020
|
+
if (this.options.recordVideo && this.page && this.page.video()) {
|
|
2008
2021
|
if (this.options.keepVideoForPassedTests) {
|
|
2009
2022
|
test.artifacts.video = await this.page.video().path();
|
|
2010
2023
|
} else {
|
|
@@ -2427,9 +2440,8 @@ class Playwright extends Helper {
|
|
|
2427
2440
|
* ```
|
|
2428
2441
|
* This method allows intercepting and mocking requests & responses. [Learn more about it](https://playwright.dev/docs/network#handle-requests)
|
|
2429
2442
|
*
|
|
2430
|
-
* @param {string} [url] URL, regex or pattern for to match URL
|
|
2431
|
-
* @param {function} [handler] a function to process
|
|
2432
|
-
*
|
|
2443
|
+
* @param {string|RegExp} [url] URL, regex or pattern for to match URL
|
|
2444
|
+
* @param {function} [handler] a function to process reques
|
|
2433
2445
|
*/
|
|
2434
2446
|
async mockRoute(url, handler) {
|
|
2435
2447
|
return this.browserContext.route(...arguments);
|
|
@@ -2444,9 +2456,8 @@ class Playwright extends Helper {
|
|
|
2444
2456
|
* ```
|
|
2445
2457
|
* If no handler is passed, all mock requests for the rote are disabled.
|
|
2446
2458
|
*
|
|
2447
|
-
* @param {string} [url] URL, regex or pattern for to match URL
|
|
2448
|
-
* @param {function} [handler] a function to process
|
|
2449
|
-
*
|
|
2459
|
+
* @param {string|RegExp} [url] URL, regex or pattern for to match URL
|
|
2460
|
+
* @param {function} [handler] a function to process reques
|
|
2450
2461
|
*/
|
|
2451
2462
|
async stopMockingRoute(url, handler) {
|
|
2452
2463
|
return this.browserContext.unroute(...arguments);
|
package/lib/helper/REST.js
CHANGED
|
@@ -87,7 +87,7 @@ class REST extends Helper {
|
|
|
87
87
|
* @param {object} headers headers list
|
|
88
88
|
*/
|
|
89
89
|
haveRequestHeaders(headers) {
|
|
90
|
-
this.headers = { ...headers, ...
|
|
90
|
+
this.headers = { ...this.headers, ...headers };
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
@@ -98,7 +98,7 @@ class REST extends Helper {
|
|
|
98
98
|
* I.amBearerAuthenticated(secret('heregoestoken'))
|
|
99
99
|
* ```
|
|
100
100
|
*
|
|
101
|
-
* @param {string} accessToken Bearer access token
|
|
101
|
+
* @param {string | CodeceptJS.Secret} accessToken Bearer access token
|
|
102
102
|
*/
|
|
103
103
|
amBearerAuthenticated(accessToken) {
|
|
104
104
|
this.haveRequestHeaders({ Authorization: `Bearer ${accessToken}` });
|
|
@@ -112,6 +112,9 @@ class REST extends Helper {
|
|
|
112
112
|
* @returns {Promise<*>} response
|
|
113
113
|
*/
|
|
114
114
|
async _executeRequest(request) {
|
|
115
|
+
// Add custom headers. They can be set by amBearerAuthenticated() or haveRequestHeaders()
|
|
116
|
+
request.headers = { ...this.headers, ...request.headers };
|
|
117
|
+
|
|
115
118
|
const _debugRequest = { ...request };
|
|
116
119
|
this.axios.defaults.timeout = request.timeout || this.options.timeout;
|
|
117
120
|
|
package/lib/helper/WebDriver.js
CHANGED
|
@@ -2551,6 +2551,8 @@ class WebDriver extends Helper {
|
|
|
2551
2551
|
|
|
2552
2552
|
/**
|
|
2553
2553
|
* Placeholder for ~ locator only test case write once run on both Appium and WebDriver.
|
|
2554
|
+
* @param {*} caps
|
|
2555
|
+
* @param {*} fn
|
|
2554
2556
|
*/
|
|
2555
2557
|
/* eslint-disable */
|
|
2556
2558
|
runOnIOS(caps, fn) {
|
|
@@ -2558,6 +2560,8 @@ class WebDriver extends Helper {
|
|
|
2558
2560
|
|
|
2559
2561
|
/**
|
|
2560
2562
|
* Placeholder for ~ locator only test case write once run on both Appium and WebDriver.
|
|
2563
|
+
* @param {*} caps
|
|
2564
|
+
* @param {*} fn
|
|
2561
2565
|
*/
|
|
2562
2566
|
runOnAndroid(caps, fn) {
|
|
2563
2567
|
}
|
package/lib/interfaces/bdd.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { CucumberExpression, ParameterTypeRegistry } = require('cucumber-expressions');
|
|
2
|
+
const Config = require('../config');
|
|
2
3
|
|
|
3
4
|
let steps = {};
|
|
4
5
|
|
|
@@ -9,7 +10,11 @@ const STACK_POSITION = 2;
|
|
|
9
10
|
* @param {*} fn
|
|
10
11
|
*/
|
|
11
12
|
const addStep = (step, fn) => {
|
|
13
|
+
const avoidDuplicateSteps = Config.get('gherkin', {}).avoidDuplicateSteps || false;
|
|
12
14
|
const stack = (new Error()).stack;
|
|
15
|
+
if (avoidDuplicateSteps && steps[step]) {
|
|
16
|
+
throw new Error(`Step '${step}' is already defined`);
|
|
17
|
+
}
|
|
13
18
|
steps[step] = fn;
|
|
14
19
|
fn.line = stack && stack.split('\n')[STACK_POSITION];
|
|
15
20
|
if (fn.line) {
|
package/lib/listener/steps.js
CHANGED
|
@@ -69,6 +69,7 @@ module.exports = function () {
|
|
|
69
69
|
event.dispatcher.on(event.step.started, (step) => {
|
|
70
70
|
if (store.debugMode) return;
|
|
71
71
|
step.startedAt = +new Date();
|
|
72
|
+
step.test = currentTest;
|
|
72
73
|
if (currentHook && Array.isArray(currentHook.steps)) {
|
|
73
74
|
return currentHook.steps.push(step);
|
|
74
75
|
}
|
package/lib/output.js
CHANGED
|
@@ -142,18 +142,20 @@ module.exports = function (config) {
|
|
|
142
142
|
if (step.metaStep && step.metaStep.name === 'BeforeSuite') return;
|
|
143
143
|
|
|
144
144
|
const fileName = `${pad.substring(0, pad.length - stepNum.toString().length) + stepNum.toString()}.png`;
|
|
145
|
+
if (step.status === 'failed') {
|
|
146
|
+
scenarioFailed = true;
|
|
147
|
+
}
|
|
148
|
+
stepNum++;
|
|
149
|
+
slides[fileName] = step;
|
|
145
150
|
try {
|
|
146
|
-
if (step.status === 'failed') {
|
|
147
|
-
scenarioFailed = true;
|
|
148
|
-
}
|
|
149
|
-
stepNum++;
|
|
150
|
-
slides[fileName] = step;
|
|
151
151
|
await helper.saveScreenshot(path.relative(reportDir, path.join(dir, fileName)), config.fullPageScreenshots);
|
|
152
152
|
} catch (err) {
|
|
153
153
|
output.plugin(`Can't save step screenshot: ${err}`);
|
|
154
154
|
error = err;
|
|
155
|
+
return;
|
|
156
|
+
} finally {
|
|
157
|
+
savedStep = step;
|
|
155
158
|
}
|
|
156
|
-
savedStep = step;
|
|
157
159
|
|
|
158
160
|
if (!currentTest.artifacts.screenshots) currentTest.artifacts.screenshots = [];
|
|
159
161
|
// added attachments to test
|