codeceptjs 3.3.0 → 3.3.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 +39 -1
- package/README.md +26 -0
- 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 +26 -11
- 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 +52 -23
- package/docs/build/Playwright.js +126 -48
- package/docs/build/Protractor.js +70 -32
- package/docs/build/Puppeteer.js +78 -35
- package/docs/build/REST.js +4 -1
- package/docs/build/TestCafe.js +53 -22
- package/docs/build/WebDriver.js +115 -65
- package/docs/changelog.md +39 -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 +113 -15
- 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 +131 -29
- package/docs/helpers/Playwright.md +424 -215
- package/docs/helpers/Puppeteer.md +229 -92
- package/docs/helpers/REST.md +1 -1
- package/docs/helpers/TestCafe.md +166 -62
- package/docs/helpers/WebDriver.md +254 -103
- 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/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/command/definitions.js +9 -0
- package/lib/command/run.js +2 -2
- package/lib/command/workers/runTests.js +40 -0
- package/lib/helper/ApiDataFactory.js +4 -3
- package/lib/helper/Appium.js +7 -2
- 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 +49 -13
- package/lib/helper/REST.js +4 -1
- package/lib/helper/WebDriver.js +6 -0
- package/lib/interfaces/bdd.js +5 -0
- package/lib/listener/steps.js +1 -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 +558 -607
|
@@ -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
|
+
@return {Promise<any>}
|
|
@@ -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
|
+
@return {Promise<any>}
|
|
@@ -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
|
+
@return {Promise<any>}
|
|
@@ -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
|
+
@return {Promise<any>}
|
|
@@ -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
|
+
@return {Promise<any>}
|
|
@@ -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
|
+
@return {Promise<any>}
|
|
@@ -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
|
}
|
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;
|
|
@@ -115,6 +115,8 @@ function initializeListeners() {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
return {
|
|
118
|
+
opts: test.opts || {},
|
|
119
|
+
tags: test.tags || [],
|
|
118
120
|
id: test.id,
|
|
119
121
|
workerIndex,
|
|
120
122
|
retries: test._retries,
|
|
@@ -126,6 +128,38 @@ function initializeListeners() {
|
|
|
126
128
|
};
|
|
127
129
|
}
|
|
128
130
|
|
|
131
|
+
function simplifyStep(step, err = null) {
|
|
132
|
+
step = { ...step };
|
|
133
|
+
|
|
134
|
+
if (step.startTime && !step.duration) {
|
|
135
|
+
const end = new Date();
|
|
136
|
+
step.duration = end - step.startTime;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (step.err) {
|
|
140
|
+
err = simplifyError(step.err);
|
|
141
|
+
step.status = 'failed';
|
|
142
|
+
} else if (err) {
|
|
143
|
+
err = simplifyError(err);
|
|
144
|
+
step.status = 'failed';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const parent = {};
|
|
148
|
+
if (step.metaStep) {
|
|
149
|
+
parent.title = step.metaStep.actor;
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
opts: step.opts || {},
|
|
153
|
+
workerIndex,
|
|
154
|
+
title: step.name,
|
|
155
|
+
status: step.status,
|
|
156
|
+
duration: step.duration || 0,
|
|
157
|
+
err,
|
|
158
|
+
parent,
|
|
159
|
+
test: simplifyTest(step.test),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
129
163
|
collectStats();
|
|
130
164
|
// suite
|
|
131
165
|
event.dispatcher.on(event.suite.before, suite => sendToParentThread({ event: event.suite.before, workerIndex, data: simplifyTest(suite) }));
|
|
@@ -144,6 +178,12 @@ function initializeListeners() {
|
|
|
144
178
|
event.dispatcher.on(event.test.started, test => sendToParentThread({ event: event.test.started, workerIndex, data: simplifyTest(test) }));
|
|
145
179
|
event.dispatcher.on(event.test.skipped, test => sendToParentThread({ event: event.test.skipped, workerIndex, data: simplifyTest(test) }));
|
|
146
180
|
|
|
181
|
+
// steps
|
|
182
|
+
event.dispatcher.on(event.step.finished, step => sendToParentThread({ event: event.step.finished, workerIndex, data: simplifyStep(step) }));
|
|
183
|
+
event.dispatcher.on(event.step.started, step => sendToParentThread({ event: event.step.started, workerIndex, data: simplifyStep(step) }));
|
|
184
|
+
event.dispatcher.on(event.step.passed, step => sendToParentThread({ event: event.step.passed, workerIndex, data: simplifyStep(step) }));
|
|
185
|
+
event.dispatcher.on(event.step.failed, step => sendToParentThread({ event: event.step.failed, workerIndex, data: simplifyStep(step) }));
|
|
186
|
+
|
|
147
187
|
event.dispatcher.on(event.hook.failed, (test, err) => sendToParentThread({ event: event.hook.failed, workerIndex, data: simplifyTest(test, err) }));
|
|
148
188
|
event.dispatcher.on(event.hook.passed, (test, err) => sendToParentThread({ event: event.hook.passed, workerIndex, data: simplifyTest(test, err) }));
|
|
149
189
|
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) {
|
|
@@ -492,6 +493,7 @@ class Appium extends Webdriver {
|
|
|
492
493
|
*
|
|
493
494
|
* @param {string} appId
|
|
494
495
|
* @param {string} [bundleId] ID of bundle
|
|
496
|
+
* @return {Promise<any>}
|
|
495
497
|
*/
|
|
496
498
|
async removeApp(appId, bundleId) {
|
|
497
499
|
onlyForApps.call(this, 'Android');
|
|
@@ -728,7 +730,7 @@ class Appium extends Webdriver {
|
|
|
728
730
|
* Switch to the specified context.
|
|
729
731
|
*
|
|
730
732
|
* @param {*} context the context to switch to
|
|
731
|
-
|
|
733
|
+
* @return {Promise<any>}
|
|
732
734
|
*/
|
|
733
735
|
async _switchToContext(context) {
|
|
734
736
|
return this.browser.switchContext(context);
|
|
@@ -774,7 +776,7 @@ class Appium extends Webdriver {
|
|
|
774
776
|
* // or set context explicitly
|
|
775
777
|
* I.switchToNative('SOME_OTHER_CONTEXT');
|
|
776
778
|
* ```
|
|
777
|
-
* @param {*} context
|
|
779
|
+
* @param {*} [context]
|
|
778
780
|
* @return {Promise<void>}
|
|
779
781
|
*/
|
|
780
782
|
async switchToNative(context = null) {
|
|
@@ -859,6 +861,7 @@ class Appium extends Webdriver {
|
|
|
859
861
|
*
|
|
860
862
|
* @param {'tapOutside' | 'pressKey'} [strategy] Desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’)
|
|
861
863
|
* @param {string} [key] Optional key
|
|
864
|
+
* @return {Promise<any>}
|
|
862
865
|
*/
|
|
863
866
|
async hideDeviceKeyboard(strategy, key) {
|
|
864
867
|
onlyForApps.call(this);
|
|
@@ -981,6 +984,7 @@ class Appium extends Webdriver {
|
|
|
981
984
|
*
|
|
982
985
|
* @param {object} from
|
|
983
986
|
* @param {object} to
|
|
987
|
+
* @return {Promise<any>}
|
|
984
988
|
*
|
|
985
989
|
* Appium: support Android and iOS
|
|
986
990
|
*/
|
|
@@ -1213,6 +1217,7 @@ class Appium extends Webdriver {
|
|
|
1213
1217
|
* Appium: support Android and iOS
|
|
1214
1218
|
*
|
|
1215
1219
|
* @param {Array} actions Array of touch actions
|
|
1220
|
+
* @return {Promise<any>}
|
|
1216
1221
|
*/
|
|
1217
1222
|
async touchPerform(actions) {
|
|
1218
1223
|
onlyForApps.call(this);
|
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
|
}
|
|
@@ -539,6 +554,7 @@ class Playwright extends Helper {
|
|
|
539
554
|
*
|
|
540
555
|
* @param {string} description used to show in logs.
|
|
541
556
|
* @param {function} fn async function that executed with Playwright helper as argument
|
|
557
|
+
* @return {Promise<any>}
|
|
542
558
|
*/
|
|
543
559
|
usePlaywrightTo(description, fn) {
|
|
544
560
|
return this._useTo(...arguments);
|
|
@@ -553,6 +569,7 @@ class Playwright extends Helper {
|
|
|
553
569
|
* I.click('#triggerPopup');
|
|
554
570
|
* I.acceptPopup();
|
|
555
571
|
* ```
|
|
572
|
+
* @return {Promise<any>}
|
|
556
573
|
*/
|
|
557
574
|
amAcceptingPopups() {
|
|
558
575
|
popupStore.actionType = 'accept';
|
|
@@ -562,6 +579,7 @@ class Playwright extends Helper {
|
|
|
562
579
|
* Accepts the active JavaScript native popup window, as created by window.alert|window.confirm|window.prompt.
|
|
563
580
|
* Don't confuse popups with modal windows, as created by [various
|
|
564
581
|
* libraries](http://jster.net/category/windows-modals-popups).
|
|
582
|
+
* @return {Promise<any>}
|
|
565
583
|
*/
|
|
566
584
|
acceptPopup() {
|
|
567
585
|
popupStore.assertPopupActionType('accept');
|
|
@@ -576,6 +594,7 @@ class Playwright extends Helper {
|
|
|
576
594
|
* I.click('#triggerPopup');
|
|
577
595
|
* I.cancelPopup();
|
|
578
596
|
* ```
|
|
597
|
+
* @return {Promise<any>}
|
|
579
598
|
*/
|
|
580
599
|
amCancellingPopups() {
|
|
581
600
|
popupStore.actionType = 'cancel';
|
|
@@ -583,6 +602,7 @@ class Playwright extends Helper {
|
|
|
583
602
|
|
|
584
603
|
/**
|
|
585
604
|
* Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt.
|
|
605
|
+
* @return {Promise<any>}
|
|
586
606
|
*/
|
|
587
607
|
cancelPopup() {
|
|
588
608
|
popupStore.assertPopupActionType('cancel');
|
|
@@ -600,6 +620,7 @@ class Playwright extends Helper {
|
|
|
600
620
|
/**
|
|
601
621
|
* Set current page
|
|
602
622
|
* @param {object} page page to set
|
|
623
|
+
* @return {Promise<any>}
|
|
603
624
|
*/
|
|
604
625
|
async _setPage(page) {
|
|
605
626
|
page = await page;
|
|
@@ -624,6 +645,7 @@ class Playwright extends Helper {
|
|
|
624
645
|
/**
|
|
625
646
|
* Add the 'dialog' event listener to a page
|
|
626
647
|
* @page {playwright.Page}
|
|
648
|
+
* @return {Promise<any>}
|
|
627
649
|
*
|
|
628
650
|
* The popup listener handles the dialog with the predefined action when it appears on the page.
|
|
629
651
|
* It also saves a reference to the object which is used in seeInPopup.
|
|
@@ -654,6 +676,7 @@ class Playwright extends Helper {
|
|
|
654
676
|
|
|
655
677
|
/**
|
|
656
678
|
* Gets page URL including hash.
|
|
679
|
+
* @return {Promise<any>}
|
|
657
680
|
*/
|
|
658
681
|
async _getPageUrl() {
|
|
659
682
|
return this.executeScript(() => window.location.href);
|
|
@@ -826,6 +849,7 @@ class Playwright extends Helper {
|
|
|
826
849
|
* ```
|
|
827
850
|
*
|
|
828
851
|
* @param {object} customHeaders headers to set
|
|
852
|
+
* @return {Promise<any>}
|
|
829
853
|
*/
|
|
830
854
|
async haveRequestHeaders(customHeaders) {
|
|
831
855
|
if (!customHeaders) {
|
|
@@ -851,7 +875,7 @@ class Playwright extends Helper {
|
|
|
851
875
|
/**
|
|
852
876
|
* {{> dragAndDrop }}
|
|
853
877
|
*
|
|
854
|
-
* [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument.
|
|
878
|
+
* @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument.
|
|
855
879
|
*
|
|
856
880
|
* ```js
|
|
857
881
|
* // specify coordinates for source position
|
|
@@ -886,7 +910,7 @@ class Playwright extends Helper {
|
|
|
886
910
|
/**
|
|
887
911
|
* {{> scrollPageToBottom }}
|
|
888
912
|
*/
|
|
889
|
-
scrollPageToBottom() {
|
|
913
|
+
async scrollPageToBottom() {
|
|
890
914
|
return this.executeScript(() => {
|
|
891
915
|
const body = document.body;
|
|
892
916
|
const html = document.documentElement;
|
|
@@ -972,8 +996,7 @@ class Playwright extends Helper {
|
|
|
972
996
|
* ```js
|
|
973
997
|
* const elements = await this.helpers['Playwright']._locate({name: 'password'});
|
|
974
998
|
* ```
|
|
975
|
-
*
|
|
976
|
-
*
|
|
999
|
+
* @return {Promise<any>}
|
|
977
1000
|
*/
|
|
978
1001
|
async _locate(locator) {
|
|
979
1002
|
const context = await this.context || await this._getContext();
|
|
@@ -987,6 +1010,7 @@ class Playwright extends Helper {
|
|
|
987
1010
|
* ```js
|
|
988
1011
|
* this.helpers['Playwright']._locateCheckable('I agree with terms and conditions').then // ...
|
|
989
1012
|
* ```
|
|
1013
|
+
* @return {Promise<any>}
|
|
990
1014
|
*/
|
|
991
1015
|
async _locateCheckable(locator, providedContext = null) {
|
|
992
1016
|
const context = providedContext || await this._getContext();
|
|
@@ -1001,6 +1025,7 @@ class Playwright extends Helper {
|
|
|
1001
1025
|
* ```js
|
|
1002
1026
|
* this.helpers['Playwright']._locateClickable('Next page').then // ...
|
|
1003
1027
|
* ```
|
|
1028
|
+
* @return {Promise<any>}
|
|
1004
1029
|
*/
|
|
1005
1030
|
async _locateClickable(locator) {
|
|
1006
1031
|
const context = await this._getContext();
|
|
@@ -1013,6 +1038,7 @@ class Playwright extends Helper {
|
|
|
1013
1038
|
* ```js
|
|
1014
1039
|
* this.helpers['Playwright']._locateFields('Your email').then // ...
|
|
1015
1040
|
* ```
|
|
1041
|
+
* @return {Promise<any>}
|
|
1016
1042
|
*/
|
|
1017
1043
|
async _locateFields(locator) {
|
|
1018
1044
|
return findFields.call(this, locator);
|
|
@@ -1027,6 +1053,7 @@ class Playwright extends Helper {
|
|
|
1027
1053
|
* ```
|
|
1028
1054
|
*
|
|
1029
1055
|
* @param {number} [num=1]
|
|
1056
|
+
* @return {Promise<any>}
|
|
1030
1057
|
*/
|
|
1031
1058
|
async switchToNextTab(num = 1) {
|
|
1032
1059
|
if (this.isElectron) {
|
|
@@ -1053,6 +1080,7 @@ class Playwright extends Helper {
|
|
|
1053
1080
|
* I.switchToPreviousTab(2);
|
|
1054
1081
|
* ```
|
|
1055
1082
|
* @param {number} [num=1]
|
|
1083
|
+
* @return {Promise<any>}
|
|
1056
1084
|
*/
|
|
1057
1085
|
async switchToPreviousTab(num = 1) {
|
|
1058
1086
|
if (this.isElectron) {
|
|
@@ -1077,6 +1105,7 @@ class Playwright extends Helper {
|
|
|
1077
1105
|
* ```js
|
|
1078
1106
|
* I.closeCurrentTab();
|
|
1079
1107
|
* ```
|
|
1108
|
+
* @return {Promise<any>}
|
|
1080
1109
|
*/
|
|
1081
1110
|
async closeCurrentTab() {
|
|
1082
1111
|
if (this.isElectron) {
|
|
@@ -1094,6 +1123,7 @@ class Playwright extends Helper {
|
|
|
1094
1123
|
* ```js
|
|
1095
1124
|
* I.closeOtherTabs();
|
|
1096
1125
|
* ```
|
|
1126
|
+
* @return {Promise<any>}
|
|
1097
1127
|
*/
|
|
1098
1128
|
async closeOtherTabs() {
|
|
1099
1129
|
const pages = await this.browserContext.pages();
|
|
@@ -1118,6 +1148,7 @@ class Playwright extends Helper {
|
|
|
1118
1148
|
* // enable mobile
|
|
1119
1149
|
* I.openNewTab({ isMobile: true });
|
|
1120
1150
|
* ```
|
|
1151
|
+
* @return {Promise<any>}
|
|
1121
1152
|
*/
|
|
1122
1153
|
async openNewTab(options) {
|
|
1123
1154
|
if (this.isElectron) {
|
|
@@ -1186,6 +1217,7 @@ class Playwright extends Helper {
|
|
|
1186
1217
|
* ```
|
|
1187
1218
|
*
|
|
1188
1219
|
* @param {string} [fileName] set filename for downloaded file
|
|
1220
|
+
* @return {Promise<void>}
|
|
1189
1221
|
*/
|
|
1190
1222
|
async handleDownloads(fileName = 'downloads') {
|
|
1191
1223
|
this.page.waitForEvent('download').then(async (download) => {
|
|
@@ -1204,7 +1236,7 @@ class Playwright extends Helper {
|
|
|
1204
1236
|
/**
|
|
1205
1237
|
* {{> click }}
|
|
1206
1238
|
*
|
|
1207
|
-
* [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument.
|
|
1239
|
+
* @param {any} [opts] [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument.
|
|
1208
1240
|
*
|
|
1209
1241
|
* Examples:
|
|
1210
1242
|
*
|
|
@@ -1223,6 +1255,7 @@ class Playwright extends Helper {
|
|
|
1223
1255
|
|
|
1224
1256
|
/**
|
|
1225
1257
|
* Clicks link and waits for navigation (deprecated)
|
|
1258
|
+
* @return {Promise<any>}
|
|
1226
1259
|
*/
|
|
1227
1260
|
async clickLink(locator, context = null) {
|
|
1228
1261
|
console.log('clickLink deprecated: Playwright automatically waits for navigation to happen.');
|
|
@@ -1992,7 +2025,7 @@ class Playwright extends Helper {
|
|
|
1992
2025
|
test.artifacts = {};
|
|
1993
2026
|
}
|
|
1994
2027
|
|
|
1995
|
-
if (this.options.recordVideo && this.page.video()) {
|
|
2028
|
+
if (this.options.recordVideo && this.page && this.page.video()) {
|
|
1996
2029
|
test.artifacts.video = await this.page.video().path();
|
|
1997
2030
|
}
|
|
1998
2031
|
|
|
@@ -2004,7 +2037,7 @@ class Playwright extends Helper {
|
|
|
2004
2037
|
}
|
|
2005
2038
|
|
|
2006
2039
|
async _passed(test) {
|
|
2007
|
-
if (this.options.recordVideo && this.page.video()) {
|
|
2040
|
+
if (this.options.recordVideo && this.page && this.page.video()) {
|
|
2008
2041
|
if (this.options.keepVideoForPassedTests) {
|
|
2009
2042
|
test.artifacts.video = await this.page.video().path();
|
|
2010
2043
|
} else {
|
|
@@ -2270,6 +2303,7 @@ class Playwright extends Helper {
|
|
|
2270
2303
|
*
|
|
2271
2304
|
* @param {string|function} urlOrPredicate
|
|
2272
2305
|
* @param {?number} [sec=null] seconds to wait
|
|
2306
|
+
* @return {Promise<any>}
|
|
2273
2307
|
*/
|
|
2274
2308
|
async waitForRequest(urlOrPredicate, sec = null) {
|
|
2275
2309
|
const timeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2286,6 +2320,7 @@ class Playwright extends Helper {
|
|
|
2286
2320
|
*
|
|
2287
2321
|
* @param {string|function} urlOrPredicate
|
|
2288
2322
|
* @param {?number} [sec=null] number of seconds to wait
|
|
2323
|
+
* @return {Promise<any>}
|
|
2289
2324
|
*/
|
|
2290
2325
|
async waitForResponse(urlOrPredicate, sec = null) {
|
|
2291
2326
|
const timeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2357,6 +2392,7 @@ class Playwright extends Helper {
|
|
|
2357
2392
|
* See [Playwright's reference](https://playwright.dev/docs/api/class-page?_highlight=waitfornavi#pagewaitfornavigationoptions)
|
|
2358
2393
|
*
|
|
2359
2394
|
* @param {*} opts
|
|
2395
|
+
* @return {Promise<any>}
|
|
2360
2396
|
*/
|
|
2361
2397
|
async waitForNavigation(opts = {}) {
|
|
2362
2398
|
opts = {
|
|
@@ -2427,9 +2463,9 @@ class Playwright extends Helper {
|
|
|
2427
2463
|
* ```
|
|
2428
2464
|
* This method allows intercepting and mocking requests & responses. [Learn more about it](https://playwright.dev/docs/network#handle-requests)
|
|
2429
2465
|
*
|
|
2430
|
-
* @param {string} [url] URL, regex or pattern for to match URL
|
|
2466
|
+
* @param {string|RegExp} [url] URL, regex or pattern for to match URL
|
|
2431
2467
|
* @param {function} [handler] a function to process request
|
|
2432
|
-
*
|
|
2468
|
+
* @return {Promise<any>}
|
|
2433
2469
|
*/
|
|
2434
2470
|
async mockRoute(url, handler) {
|
|
2435
2471
|
return this.browserContext.route(...arguments);
|
|
@@ -2444,9 +2480,9 @@ class Playwright extends Helper {
|
|
|
2444
2480
|
* ```
|
|
2445
2481
|
* If no handler is passed, all mock requests for the rote are disabled.
|
|
2446
2482
|
*
|
|
2447
|
-
* @param {string} [url] URL, regex or pattern for to match URL
|
|
2483
|
+
* @param {string|RegExp} [url] URL, regex or pattern for to match URL
|
|
2448
2484
|
* @param {function} [handler] a function to process request
|
|
2449
|
-
*
|
|
2485
|
+
* @return {Promise<any>}
|
|
2450
2486
|
*/
|
|
2451
2487
|
async stopMockingRoute(url, handler) {
|
|
2452
2488
|
return this.browserContext.unroute(...arguments);
|
package/lib/helper/REST.js
CHANGED
|
@@ -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 = { ...request.headers, ...this.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,9 @@ 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
|
|
2556
|
+
* @return {Promise<any>}
|
|
2554
2557
|
*/
|
|
2555
2558
|
/* eslint-disable */
|
|
2556
2559
|
runOnIOS(caps, fn) {
|
|
@@ -2558,6 +2561,9 @@ class WebDriver extends Helper {
|
|
|
2558
2561
|
|
|
2559
2562
|
/**
|
|
2560
2563
|
* Placeholder for ~ locator only test case write once run on both Appium and WebDriver.
|
|
2564
|
+
* @param {*} caps
|
|
2565
|
+
* @param {*} fn
|
|
2566
|
+
* @return {Promise<any>}
|
|
2561
2567
|
*/
|
|
2562
2568
|
runOnAndroid(caps, fn) {
|
|
2563
2569
|
}
|
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
|
}
|