codeceptjs 2.4.3 → 2.6.2
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 +117 -0
- package/README.md +32 -7
- package/bin/codecept.js +3 -0
- package/docs/basics.md +11 -5
- package/docs/bdd.md +4 -4
- package/docs/build/MockRequest.js +3 -0
- package/docs/build/Nightmare.js +10 -2
- package/docs/build/Playwright.js +3187 -0
- package/docs/build/Protractor.js +16 -2
- package/docs/build/Puppeteer.js +126 -19
- package/docs/build/REST.js +3 -1
- package/docs/build/TestCafe.js +11 -3
- package/docs/build/WebDriver.js +361 -28
- package/docs/changelog.md +116 -0
- package/docs/configuration.md +2 -2
- package/docs/custom-helpers.md +55 -10
- package/docs/helpers/Appium.md +81 -1
- package/docs/helpers/MockRequest.md +281 -38
- package/docs/helpers/Nightmare.md +10 -2
- package/docs/helpers/Playwright.md +1770 -0
- package/docs/helpers/Protractor.md +15 -3
- package/docs/helpers/Puppeteer-firefox.md +32 -1
- package/docs/helpers/Puppeteer.md +126 -76
- package/docs/helpers/TestCafe.md +10 -2
- package/docs/helpers/WebDriver.md +208 -118
- package/docs/locators.md +2 -0
- package/docs/playwright.md +306 -0
- package/docs/plugins.md +103 -0
- package/docs/reports.md +12 -0
- package/docs/shadow.md +68 -0
- package/docs/visual.md +0 -73
- package/docs/webapi/forceClick.mustache +27 -0
- package/docs/webapi/seeInPopup.mustache +7 -0
- package/docs/webapi/setCookie.mustache +10 -2
- package/docs/webapi/type.mustache +12 -0
- package/docs/webdriver.md +7 -3
- package/lib/codecept.js +1 -1
- package/lib/command/definitions.js +2 -2
- package/lib/command/generate.js +4 -4
- package/lib/command/gherkin/snippets.js +4 -4
- package/lib/command/init.js +1 -1
- package/lib/command/interactive.js +3 -0
- package/lib/command/run-multiple.js +2 -2
- package/lib/command/run-rerun.js +2 -0
- package/lib/command/run-workers.js +22 -8
- package/lib/command/run.js +2 -0
- package/lib/command/workers/runTests.js +1 -0
- package/lib/container.js +1 -1
- package/lib/event.js +2 -0
- package/lib/helper/MockRequest.js +3 -0
- package/lib/helper/Playwright.js +2422 -0
- package/lib/helper/Protractor.js +1 -2
- package/lib/helper/Puppeteer.js +84 -19
- package/lib/helper/REST.js +3 -1
- package/lib/helper/TestCafe.js +1 -1
- package/lib/helper/WebDriver.js +313 -26
- package/lib/helper/extras/PlaywrightPropEngine.js +53 -0
- package/lib/helper/scripts/isElementClickable.js +54 -14
- package/lib/interfaces/gherkin.js +1 -1
- package/lib/listener/helpers.js +3 -0
- package/lib/locator.js +5 -0
- package/lib/mochaFactory.js +12 -10
- package/lib/plugin/allure.js +8 -1
- package/lib/plugin/autoDelay.js +1 -8
- package/lib/plugin/commentStep.js +133 -0
- package/lib/plugin/screenshotOnFail.js +3 -10
- package/lib/plugin/selenoid.js +2 -2
- package/lib/plugin/standardActingHelpers.js +13 -0
- package/lib/plugin/stepByStepReport.js +1 -8
- package/lib/plugin/wdio.js +10 -1
- package/lib/reporter/cli.js +30 -1
- package/lib/session.js +7 -4
- package/package.json +13 -10
- package/typings/Mocha.d.ts +567 -16
- package/typings/index.d.ts +9 -5
- package/typings/types.d.ts +1634 -74
package/docs/build/Protractor.js
CHANGED
|
@@ -1557,6 +1557,12 @@ class Protractor extends Helper {
|
|
|
1557
1557
|
/**
|
|
1558
1558
|
* Checks that the active JavaScript popup, as created by `window.alert|window.confirm|window.prompt`, contains the
|
|
1559
1559
|
* given string.
|
|
1560
|
+
*
|
|
1561
|
+
* ```js
|
|
1562
|
+
* I.seeInPopup('Popup text');
|
|
1563
|
+
* ```
|
|
1564
|
+
* @param {string} text value to check.
|
|
1565
|
+
*
|
|
1560
1566
|
*/
|
|
1561
1567
|
async seeInPopup(text) {
|
|
1562
1568
|
const popupAlert = await this.browser.switchTo().alert();
|
|
@@ -2256,13 +2262,21 @@ class Protractor extends Helper {
|
|
|
2256
2262
|
}
|
|
2257
2263
|
|
|
2258
2264
|
/**
|
|
2259
|
-
* Sets
|
|
2265
|
+
* Sets cookie(s).
|
|
2266
|
+
*
|
|
2267
|
+
* Can be a single cookie object or an array of cookies:
|
|
2260
2268
|
*
|
|
2261
2269
|
* ```js
|
|
2262
2270
|
* I.setCookie({name: 'auth', value: true});
|
|
2271
|
+
*
|
|
2272
|
+
* // as array
|
|
2273
|
+
* I.setCookie([
|
|
2274
|
+
* {name: 'auth', value: true},
|
|
2275
|
+
* {name: 'agree', value: true}
|
|
2276
|
+
* ]);
|
|
2263
2277
|
* ```
|
|
2264
2278
|
*
|
|
2265
|
-
* @param {object} cookie a cookie object.
|
|
2279
|
+
* @param {object|array} cookie a cookie object or array of cookie objects.
|
|
2266
2280
|
*/
|
|
2267
2281
|
setCookie(cookie) {
|
|
2268
2282
|
return this.browser.manage().addCookie(cookie);
|
package/docs/build/Puppeteer.js
CHANGED
|
@@ -36,7 +36,6 @@ const findReact = require('./extras/React');
|
|
|
36
36
|
|
|
37
37
|
let puppeteer;
|
|
38
38
|
let perfTiming;
|
|
39
|
-
let isAuthenticated = false;
|
|
40
39
|
const popupStore = new Popup();
|
|
41
40
|
const consoleLogStore = new Console();
|
|
42
41
|
|
|
@@ -168,11 +167,14 @@ class Puppeteer extends Helper {
|
|
|
168
167
|
constructor(config) {
|
|
169
168
|
super(config);
|
|
170
169
|
|
|
171
|
-
puppeteer = requireg(
|
|
170
|
+
puppeteer = requireg('puppeteer');
|
|
172
171
|
|
|
173
172
|
// set defaults
|
|
174
173
|
this.isRemoteBrowser = false;
|
|
175
174
|
this.isRunning = false;
|
|
175
|
+
this.isAuthenticated = false;
|
|
176
|
+
this.sessionPages = {};
|
|
177
|
+
this.activeSessionName = '';
|
|
176
178
|
|
|
177
179
|
// override defaults with config
|
|
178
180
|
this._setConfig(config);
|
|
@@ -201,7 +203,7 @@ class Puppeteer extends Helper {
|
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
_getOptions(config) {
|
|
204
|
-
return config.browser === 'firefox' ? this.options.firefox : this.options.chrome;
|
|
206
|
+
return config.browser === 'firefox' ? Object.assign(this.options.firefox, { product: 'firefox' }) : this.options.chrome;
|
|
205
207
|
}
|
|
206
208
|
|
|
207
209
|
_setConfig(config) {
|
|
@@ -220,6 +222,9 @@ class Puppeteer extends Helper {
|
|
|
220
222
|
{
|
|
221
223
|
name: 'show', message: 'Show browser window', default: true, type: 'confirm',
|
|
222
224
|
},
|
|
225
|
+
{
|
|
226
|
+
name: 'windowSize', message: 'Browser viewport size', default: '1200x900',
|
|
227
|
+
},
|
|
223
228
|
];
|
|
224
229
|
}
|
|
225
230
|
|
|
@@ -227,7 +232,7 @@ class Puppeteer extends Helper {
|
|
|
227
232
|
try {
|
|
228
233
|
requireg('puppeteer');
|
|
229
234
|
} catch (e) {
|
|
230
|
-
return ['puppeteer@^
|
|
235
|
+
return ['puppeteer@^3.0.1'];
|
|
231
236
|
}
|
|
232
237
|
}
|
|
233
238
|
|
|
@@ -243,6 +248,7 @@ class Puppeteer extends Helper {
|
|
|
243
248
|
|
|
244
249
|
|
|
245
250
|
async _before() {
|
|
251
|
+
this.sessionPages = {};
|
|
246
252
|
recorder.retry({
|
|
247
253
|
retries: 5,
|
|
248
254
|
when: err => err.message.indexOf('context') > -1, // ignore context errors
|
|
@@ -257,7 +263,8 @@ class Puppeteer extends Helper {
|
|
|
257
263
|
|
|
258
264
|
// close other sessions
|
|
259
265
|
const contexts = this.browser.browserContexts();
|
|
260
|
-
contexts.shift();
|
|
266
|
+
const defaultCtx = contexts.shift();
|
|
267
|
+
|
|
261
268
|
await Promise.all(contexts.map(c => c.close()));
|
|
262
269
|
|
|
263
270
|
if (this.options.restart) {
|
|
@@ -265,6 +272,12 @@ class Puppeteer extends Helper {
|
|
|
265
272
|
return this._stopBrowser();
|
|
266
273
|
}
|
|
267
274
|
|
|
275
|
+
// ensure this.page is from default context
|
|
276
|
+
if (this.page) {
|
|
277
|
+
const existingPages = defaultCtx.targets().filter(t => t.type() === 'page');
|
|
278
|
+
await this._setPage(await existingPages[0].page());
|
|
279
|
+
}
|
|
280
|
+
|
|
268
281
|
if (this.options.keepBrowserState) return;
|
|
269
282
|
|
|
270
283
|
if (!this.options.keepCookies) {
|
|
@@ -291,11 +304,13 @@ class Puppeteer extends Helper {
|
|
|
291
304
|
|
|
292
305
|
_session() {
|
|
293
306
|
return {
|
|
294
|
-
start: async () => {
|
|
307
|
+
start: async (name = '', config) => {
|
|
295
308
|
this.debugSection('Incognito Tab', 'opened');
|
|
309
|
+
this.activeSessionName = name;
|
|
296
310
|
|
|
297
311
|
const bc = await this.browser.createIncognitoBrowserContext();
|
|
298
|
-
await bc.newPage();
|
|
312
|
+
const page = await bc.newPage();
|
|
313
|
+
|
|
299
314
|
// Create a new page inside context.
|
|
300
315
|
return bc;
|
|
301
316
|
},
|
|
@@ -304,12 +319,21 @@ class Puppeteer extends Helper {
|
|
|
304
319
|
},
|
|
305
320
|
loadVars: async (context) => {
|
|
306
321
|
const existingPages = context.targets().filter(t => t.type() === 'page');
|
|
307
|
-
|
|
322
|
+
this.sessionPages[this.activeSessionName] = await existingPages[0].page();
|
|
323
|
+
return this._setPage(this.sessionPages[this.activeSessionName]);
|
|
308
324
|
},
|
|
309
|
-
restoreVars: async () => {
|
|
325
|
+
restoreVars: async (session) => {
|
|
310
326
|
this.withinLocator = null;
|
|
311
|
-
|
|
327
|
+
|
|
328
|
+
if (!session) {
|
|
329
|
+
this.activeSessionName = '';
|
|
330
|
+
} else {
|
|
331
|
+
this.activeSessionName = session;
|
|
332
|
+
}
|
|
333
|
+
const defaultCtx = this.browser.defaultBrowserContext();
|
|
334
|
+
const existingPages = defaultCtx.targets().filter(t => t.type() === 'page');
|
|
312
335
|
await this._setPage(await existingPages[0].page());
|
|
336
|
+
|
|
313
337
|
return this._waitForAction();
|
|
314
338
|
},
|
|
315
339
|
};
|
|
@@ -363,6 +387,12 @@ class Puppeteer extends Helper {
|
|
|
363
387
|
/**
|
|
364
388
|
* Checks that the active JavaScript popup, as created by `window.alert|window.confirm|window.prompt`, contains the
|
|
365
389
|
* given string.
|
|
390
|
+
*
|
|
391
|
+
* ```js
|
|
392
|
+
* I.seeInPopup('Popup text');
|
|
393
|
+
* ```
|
|
394
|
+
* @param {string} text value to check.
|
|
395
|
+
*
|
|
366
396
|
*/
|
|
367
397
|
async seeInPopup(text) {
|
|
368
398
|
popupStore.assertPopupVisible();
|
|
@@ -475,6 +505,7 @@ class Puppeteer extends Helper {
|
|
|
475
505
|
this._setPage(null);
|
|
476
506
|
this.context = null;
|
|
477
507
|
popupStore.clear();
|
|
508
|
+
this.isAuthenticated = false;
|
|
478
509
|
if (this.isRemoteBrowser) {
|
|
479
510
|
await this.browser.disconnect();
|
|
480
511
|
} else {
|
|
@@ -552,10 +583,10 @@ class Puppeteer extends Helper {
|
|
|
552
583
|
url = this.options.url + url;
|
|
553
584
|
}
|
|
554
585
|
|
|
555
|
-
if (this.config.basicAuth && (isAuthenticated !== true)) {
|
|
586
|
+
if (this.config.basicAuth && (this.isAuthenticated !== true)) {
|
|
556
587
|
if (url.includes(this.options.url)) {
|
|
557
|
-
this.page.authenticate(this.config.basicAuth);
|
|
558
|
-
isAuthenticated = true;
|
|
588
|
+
await this.page.authenticate(this.config.basicAuth);
|
|
589
|
+
this.isAuthenticated = true;
|
|
559
590
|
}
|
|
560
591
|
}
|
|
561
592
|
|
|
@@ -1056,6 +1087,63 @@ class Puppeteer extends Helper {
|
|
|
1056
1087
|
return proceedClick.call(this, locator, context);
|
|
1057
1088
|
}
|
|
1058
1089
|
|
|
1090
|
+
/**
|
|
1091
|
+
* Perform an emulated click on a link or a button, given by a locator.
|
|
1092
|
+
* Unlike normal click instead of sending native event, emulates a click with JavaScript.
|
|
1093
|
+
* This works on hidden, animated or inactive elements as well.
|
|
1094
|
+
*
|
|
1095
|
+
* If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
|
|
1096
|
+
* For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
|
|
1097
|
+
* For images, the "alt" attribute and inner text of any parent links are searched.
|
|
1098
|
+
*
|
|
1099
|
+
* The second parameter is a context (CSS or XPath locator) to narrow the search.
|
|
1100
|
+
*
|
|
1101
|
+
* ```js
|
|
1102
|
+
* // simple link
|
|
1103
|
+
* I.forceClick('Logout');
|
|
1104
|
+
* // button of form
|
|
1105
|
+
* I.forceClick('Submit');
|
|
1106
|
+
* // CSS button
|
|
1107
|
+
* I.forceClick('#form input[type=submit]');
|
|
1108
|
+
* // XPath
|
|
1109
|
+
* I.forceClick('//form/*[@type=submit]');
|
|
1110
|
+
* // link in context
|
|
1111
|
+
* I.forceClick('Logout', '#nav');
|
|
1112
|
+
* // using strict locator
|
|
1113
|
+
* I.forceClick({css: 'nav a.login'});
|
|
1114
|
+
* ```
|
|
1115
|
+
*
|
|
1116
|
+
* @param {CodeceptJS.LocatorOrString} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1117
|
+
* @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1118
|
+
*
|
|
1119
|
+
*
|
|
1120
|
+
* {{ react }}
|
|
1121
|
+
*/
|
|
1122
|
+
async forceClick(locator, context = null) {
|
|
1123
|
+
let matcher = await this.context;
|
|
1124
|
+
if (context) {
|
|
1125
|
+
const els = await this._locate(context);
|
|
1126
|
+
assertElementExists(els, context);
|
|
1127
|
+
matcher = els[0];
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
const els = await findClickable.call(this, matcher, locator);
|
|
1131
|
+
if (context) {
|
|
1132
|
+
assertElementExists(els, locator, 'Clickable element', `was not found inside element ${new Locator(context).toString()}`);
|
|
1133
|
+
} else {
|
|
1134
|
+
assertElementExists(els, locator, 'Clickable element');
|
|
1135
|
+
}
|
|
1136
|
+
const elem = els[0];
|
|
1137
|
+
return this.executeScript((el) => {
|
|
1138
|
+
if (document.activeElement instanceof HTMLElement) {
|
|
1139
|
+
document.activeElement.blur();
|
|
1140
|
+
}
|
|
1141
|
+
const event = document.createEvent('MouseEvent');
|
|
1142
|
+
event.initEvent('click', true, true);
|
|
1143
|
+
return el.dispatchEvent(event);
|
|
1144
|
+
}, elem);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1059
1147
|
/**
|
|
1060
1148
|
* Performs a click on a link and waits for navigation before moving on.
|
|
1061
1149
|
*
|
|
@@ -1533,6 +1621,8 @@ class Puppeteer extends Helper {
|
|
|
1533
1621
|
*
|
|
1534
1622
|
* @param {CodeceptJS.LocatorOrString} locator field located by label|name|CSS|XPath|strict locator.
|
|
1535
1623
|
* @param {string} pathToFile local file path relative to codecept.json config file.
|
|
1624
|
+
*
|
|
1625
|
+
* > ⚠ There is an [issue with file upload in Puppeteer 2.1.0 & 2.1.1](https://github.com/puppeteer/puppeteer/issues/5420), downgrade to 2.0.0 if you face it.
|
|
1536
1626
|
*/
|
|
1537
1627
|
async attachFile(locator, pathToFile) {
|
|
1538
1628
|
const file = path.join(global.codecept_dir, pathToFile);
|
|
@@ -1831,13 +1921,21 @@ class Puppeteer extends Helper {
|
|
|
1831
1921
|
}
|
|
1832
1922
|
|
|
1833
1923
|
/**
|
|
1834
|
-
* Sets
|
|
1924
|
+
* Sets cookie(s).
|
|
1925
|
+
*
|
|
1926
|
+
* Can be a single cookie object or an array of cookies:
|
|
1835
1927
|
*
|
|
1836
1928
|
* ```js
|
|
1837
1929
|
* I.setCookie({name: 'auth', value: true});
|
|
1930
|
+
*
|
|
1931
|
+
* // as array
|
|
1932
|
+
* I.setCookie([
|
|
1933
|
+
* {name: 'auth', value: true},
|
|
1934
|
+
* {name: 'agree', value: true}
|
|
1935
|
+
* ]);
|
|
1838
1936
|
* ```
|
|
1839
1937
|
*
|
|
1840
|
-
* @param {object} cookie a cookie object.
|
|
1938
|
+
* @param {object|array} cookie a cookie object or array of cookie objects.
|
|
1841
1939
|
*/
|
|
1842
1940
|
async setCookie(cookie) {
|
|
1843
1941
|
if (Array.isArray(cookie)) {
|
|
@@ -2248,10 +2346,19 @@ class Puppeteer extends Helper {
|
|
|
2248
2346
|
const outputFile = screenshotOutputFolder(fileName);
|
|
2249
2347
|
|
|
2250
2348
|
this.debug(`Screenshot is saving to ${outputFile}`);
|
|
2251
|
-
|
|
2252
|
-
if (
|
|
2253
|
-
|
|
2349
|
+
|
|
2350
|
+
if (this.activeSessionName) {
|
|
2351
|
+
const activeSessionPage = this.sessionPages[this.activeSessionName];
|
|
2352
|
+
|
|
2353
|
+
if (activeSessionPage) {
|
|
2354
|
+
return activeSessionPage.screenshot({
|
|
2355
|
+
path: outputFile,
|
|
2356
|
+
fullPage: fullPageOption,
|
|
2357
|
+
type: 'png',
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2254
2360
|
}
|
|
2361
|
+
|
|
2255
2362
|
return this.page.screenshot({ path: outputFile, fullPage: fullPageOption, type: 'png' });
|
|
2256
2363
|
}
|
|
2257
2364
|
|
|
@@ -2626,7 +2733,7 @@ class Puppeteer extends Helper {
|
|
|
2626
2733
|
}, { timeout: waitTimeout }, locator.value, text, $XPath.toString());
|
|
2627
2734
|
}
|
|
2628
2735
|
} else {
|
|
2629
|
-
waiter = contextObject.waitForFunction(text => document.body.innerText.indexOf(text) > -1, { timeout: waitTimeout }, text);
|
|
2736
|
+
waiter = contextObject.waitForFunction(text => document.body && document.body.innerText.indexOf(text) > -1, { timeout: waitTimeout }, text);
|
|
2630
2737
|
}
|
|
2631
2738
|
|
|
2632
2739
|
return waiter.catch((err) => {
|
package/docs/build/REST.js
CHANGED
|
@@ -75,7 +75,9 @@ class REST extends Helper {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
if ((typeof request.data) === 'string') {
|
|
78
|
-
request.headers
|
|
78
|
+
if (!request.headers || !request.headers['Content-Type']) {
|
|
79
|
+
request.headers = Object.assign(request.headers, { 'Content-Type': 'application/x-www-form-urlencoded' });
|
|
80
|
+
}
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
if (this.config.onRequest) {
|
package/docs/build/TestCafe.js
CHANGED
|
@@ -1339,13 +1339,21 @@ class TestCafe extends Helper {
|
|
|
1339
1339
|
// TODO Add url assertions
|
|
1340
1340
|
|
|
1341
1341
|
/**
|
|
1342
|
-
* Sets
|
|
1342
|
+
* Sets cookie(s).
|
|
1343
|
+
*
|
|
1344
|
+
* Can be a single cookie object or an array of cookies:
|
|
1343
1345
|
*
|
|
1344
1346
|
* ```js
|
|
1345
1347
|
* I.setCookie({name: 'auth', value: true});
|
|
1348
|
+
*
|
|
1349
|
+
* // as array
|
|
1350
|
+
* I.setCookie([
|
|
1351
|
+
* {name: 'auth', value: true},
|
|
1352
|
+
* {name: 'agree', value: true}
|
|
1353
|
+
* ]);
|
|
1346
1354
|
* ```
|
|
1347
1355
|
*
|
|
1348
|
-
* @param {object} cookie a cookie object.
|
|
1356
|
+
* @param {object|array} cookie a cookie object or array of cookie objects.
|
|
1349
1357
|
*/
|
|
1350
1358
|
async setCookie(cookie) {
|
|
1351
1359
|
if (Array.isArray(cookie)) {
|
|
@@ -1747,7 +1755,7 @@ async function proceedClick(locator, context = null) {
|
|
|
1747
1755
|
await assertElementExists(els, locator, 'Clickable element');
|
|
1748
1756
|
}
|
|
1749
1757
|
|
|
1750
|
-
const firstElement = await els.nth(0);
|
|
1758
|
+
const firstElement = await els.filterVisible().nth(0);
|
|
1751
1759
|
|
|
1752
1760
|
return this.t
|
|
1753
1761
|
.click(firstElement)
|