codeceptjs 3.0.6 → 3.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -8
- package/bin/codecept.js +1 -0
- package/docs/build/Appium.js +1 -0
- package/docs/build/GraphQL.js +9 -10
- package/docs/build/Playwright.js +123 -22
- package/docs/build/REST.js +4 -3
- package/docs/build/WebDriver.js +82 -14
- package/docs/changelog.md +35 -9
- package/docs/email.md +8 -8
- package/docs/examples.md +3 -3
- package/docs/helpers/MockRequest.md +3 -3
- package/docs/helpers/Playwright.md +10 -1
- package/docs/helpers/WebDriver.md +1 -0
- package/docs/locators.md +27 -0
- package/docs/nightmare.md +0 -5
- package/docs/parallel.md +14 -7
- package/docs/playwright.md +6 -6
- package/docs/reports.md +5 -4
- package/lib/command/interactive.js +4 -2
- package/lib/helper/GraphQL.js +9 -10
- package/lib/helper/Playwright.js +46 -5
- package/lib/helper/WebDriver.js +82 -14
- package/lib/output.js +3 -0
- package/lib/plugin/screenshotOnFail.js +5 -0
- package/lib/ui.js +6 -2
- package/package.json +2 -2
- package/typings/index.d.ts +44 -21
- package/typings/types.d.ts +17 -5
package/docs/build/WebDriver.js
CHANGED
|
@@ -396,6 +396,7 @@ class WebDriver extends Helper {
|
|
|
396
396
|
this.isRunning = false;
|
|
397
397
|
this.sessionWindows = {};
|
|
398
398
|
this.activeSessionName = '';
|
|
399
|
+
this.customLocatorStrategies = config.customLocatorStrategies;
|
|
399
400
|
|
|
400
401
|
this._setConfig(config);
|
|
401
402
|
|
|
@@ -503,6 +504,33 @@ class WebDriver extends Helper {
|
|
|
503
504
|
}
|
|
504
505
|
}
|
|
505
506
|
|
|
507
|
+
_lookupCustomLocator(customStrategy) {
|
|
508
|
+
if (typeof (this.customLocatorStrategies) !== 'object') {
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
const strategy = this.customLocatorStrategies[customStrategy];
|
|
512
|
+
return typeof (strategy) === 'function' ? strategy : null;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
_isCustomLocator(locator) {
|
|
516
|
+
const locatorObj = new Locator(locator);
|
|
517
|
+
if (locatorObj.isCustom()) {
|
|
518
|
+
const customLocator = this._lookupCustomLocator(locatorObj.type);
|
|
519
|
+
if (customLocator) {
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
throw new Error('Please define "customLocatorStrategies" as an Object and the Locator Strategy as a "function".');
|
|
523
|
+
}
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
async _res(locator) {
|
|
528
|
+
const res = (this._isShadowLocator(locator) || this._isCustomLocator(locator))
|
|
529
|
+
? await this._locate(locator)
|
|
530
|
+
: await this.$$(withStrictLocator(locator));
|
|
531
|
+
return res;
|
|
532
|
+
}
|
|
533
|
+
|
|
506
534
|
async _startBrowser() {
|
|
507
535
|
try {
|
|
508
536
|
if (this.options.multiremote) {
|
|
@@ -530,9 +558,22 @@ class WebDriver extends Helper {
|
|
|
530
558
|
await this._resizeWindowIfNeeded(this.browser, this.options.windowSize);
|
|
531
559
|
|
|
532
560
|
this.$$ = this.browser.$$.bind(this.browser);
|
|
561
|
+
|
|
562
|
+
if (this._isCustomLocatorStrategyDefined()) {
|
|
563
|
+
Object.keys(this.customLocatorStrategies).forEach(async (customLocator) => {
|
|
564
|
+
this.debugSection('Weddriver', `adding custom locator strategy: ${customLocator}`);
|
|
565
|
+
const locatorFunction = this._lookupCustomLocator(customLocator);
|
|
566
|
+
this.browser.addLocatorStrategy(customLocator, locatorFunction);
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
|
|
533
570
|
return this.browser;
|
|
534
571
|
}
|
|
535
572
|
|
|
573
|
+
_isCustomLocatorStrategyDefined() {
|
|
574
|
+
return this.customLocatorStrategies && Object.keys(this.customLocatorStrategies).length;
|
|
575
|
+
}
|
|
576
|
+
|
|
536
577
|
async _stopBrowser() {
|
|
537
578
|
if (this.browser && this.isRunning) await this.browser.deleteSession();
|
|
538
579
|
}
|
|
@@ -755,17 +796,34 @@ class WebDriver extends Helper {
|
|
|
755
796
|
}
|
|
756
797
|
|
|
757
798
|
if (!this.options.smartWait || !smartWait) {
|
|
799
|
+
if (this._isCustomLocator(locator)) {
|
|
800
|
+
const locatorObj = new Locator(locator);
|
|
801
|
+
return this.browser.custom$$(locatorObj.type, locatorObj.value);
|
|
802
|
+
}
|
|
803
|
+
|
|
758
804
|
const els = await this.$$(withStrictLocator(locator));
|
|
759
805
|
return els;
|
|
760
806
|
}
|
|
761
807
|
|
|
762
808
|
await this._smartWait(locator);
|
|
763
809
|
|
|
810
|
+
if (this._isCustomLocator(locator)) {
|
|
811
|
+
const locatorObj = new Locator(locator);
|
|
812
|
+
return this.browser.custom$$(locatorObj.type, locatorObj.value);
|
|
813
|
+
}
|
|
814
|
+
|
|
764
815
|
const els = await this.$$(withStrictLocator(locator));
|
|
765
816
|
await this.defineTimeout({ implicit: 0 });
|
|
766
817
|
return els;
|
|
767
818
|
}
|
|
768
819
|
|
|
820
|
+
_grabCustomLocator(locator) {
|
|
821
|
+
if (typeof locator === 'string') {
|
|
822
|
+
locator = new Locator(locator);
|
|
823
|
+
}
|
|
824
|
+
return locator.value ? locator.value : locator.custom;
|
|
825
|
+
}
|
|
826
|
+
|
|
769
827
|
/**
|
|
770
828
|
* Find a checkbox by providing human readable text:
|
|
771
829
|
*
|
|
@@ -1079,6 +1137,7 @@ class WebDriver extends Helper {
|
|
|
1079
1137
|
* @param {CodeceptJS.StringOrSecret} value text value to fill.
|
|
1080
1138
|
*
|
|
1081
1139
|
* {{ react }}
|
|
1140
|
+
* {{ custom }}
|
|
1082
1141
|
*
|
|
1083
1142
|
*/
|
|
1084
1143
|
async fillField(field, value) {
|
|
@@ -1723,7 +1782,7 @@ class WebDriver extends Helper {
|
|
|
1723
1782
|
*
|
|
1724
1783
|
*/
|
|
1725
1784
|
async seeElementInDOM(locator) {
|
|
1726
|
-
const res = await this
|
|
1785
|
+
const res = await this._res(locator);
|
|
1727
1786
|
return empty('elements').negate(res);
|
|
1728
1787
|
}
|
|
1729
1788
|
|
|
@@ -1738,7 +1797,7 @@ class WebDriver extends Helper {
|
|
|
1738
1797
|
*
|
|
1739
1798
|
*/
|
|
1740
1799
|
async dontSeeElementInDOM(locator) {
|
|
1741
|
-
const res = await this
|
|
1800
|
+
const res = await this._res(locator);
|
|
1742
1801
|
return empty('elements').assert(res);
|
|
1743
1802
|
}
|
|
1744
1803
|
|
|
@@ -2787,7 +2846,7 @@ class WebDriver extends Helper {
|
|
|
2787
2846
|
}, aSec * 1000, `element (${new Locator(locator)}) still not enabled after ${aSec} sec`);
|
|
2788
2847
|
}
|
|
2789
2848
|
return this.browser.waitUntil(async () => {
|
|
2790
|
-
const res = await this
|
|
2849
|
+
const res = await this._res(locator);
|
|
2791
2850
|
if (!res || res.length === 0) {
|
|
2792
2851
|
return false;
|
|
2793
2852
|
}
|
|
@@ -2823,7 +2882,7 @@ class WebDriver extends Helper {
|
|
|
2823
2882
|
}, aSec * 1000, `element (${locator}) still not present on page after ${aSec} sec`);
|
|
2824
2883
|
}
|
|
2825
2884
|
return this.browser.waitUntil(async () => {
|
|
2826
|
-
const res = await this
|
|
2885
|
+
const res = await this._res(locator);
|
|
2827
2886
|
return res && res.length;
|
|
2828
2887
|
}, { timeout: aSec * 1000, timeoutMsg: `element (${locator}) still not present on page after ${aSec} sec` });
|
|
2829
2888
|
}
|
|
@@ -3046,9 +3105,7 @@ class WebDriver extends Helper {
|
|
|
3046
3105
|
}, aSec * 1000, `element (${new Locator(locator)}) still not visible after ${aSec} sec`);
|
|
3047
3106
|
}
|
|
3048
3107
|
return this.browser.waitUntil(async () => {
|
|
3049
|
-
const res =
|
|
3050
|
-
? await this._locate(withStrictLocator(locator))
|
|
3051
|
-
: await this.$$(withStrictLocator(locator));
|
|
3108
|
+
const res = await this._res(locator);
|
|
3052
3109
|
if (!res || res.length === 0) return false;
|
|
3053
3110
|
const selected = await forEachAsync(res, async el => el.isDisplayed());
|
|
3054
3111
|
if (Array.isArray(selected)) {
|
|
@@ -3083,7 +3140,7 @@ class WebDriver extends Helper {
|
|
|
3083
3140
|
}, aSec * 1000, `The number of elements (${new Locator(locator)}) is not ${num} after ${aSec} sec`);
|
|
3084
3141
|
}
|
|
3085
3142
|
return this.browser.waitUntil(async () => {
|
|
3086
|
-
const res = await this
|
|
3143
|
+
const res = await this._res(locator);
|
|
3087
3144
|
if (!res || res.length === 0) return false;
|
|
3088
3145
|
let selected = await forEachAsync(res, async el => el.isDisplayed());
|
|
3089
3146
|
|
|
@@ -3115,7 +3172,7 @@ class WebDriver extends Helper {
|
|
|
3115
3172
|
}, aSec * 1000, `element (${new Locator(locator)}) still visible after ${aSec} sec`);
|
|
3116
3173
|
}
|
|
3117
3174
|
return this.browser.waitUntil(async () => {
|
|
3118
|
-
const res = await this
|
|
3175
|
+
const res = await this._res(locator);
|
|
3119
3176
|
if (!res || res.length === 0) return true;
|
|
3120
3177
|
const selected = await forEachAsync(res, async el => el.isDisplayed());
|
|
3121
3178
|
return !selected.length;
|
|
@@ -3152,7 +3209,7 @@ class WebDriver extends Helper {
|
|
|
3152
3209
|
const aSec = sec || this.options.waitForTimeout;
|
|
3153
3210
|
if (isWebDriver5()) {
|
|
3154
3211
|
return this.browser.waitUntil(async () => {
|
|
3155
|
-
const res = await this
|
|
3212
|
+
const res = await this._res(locator);
|
|
3156
3213
|
if (!res || res.length === 0) {
|
|
3157
3214
|
return true;
|
|
3158
3215
|
}
|
|
@@ -3160,7 +3217,7 @@ class WebDriver extends Helper {
|
|
|
3160
3217
|
}, aSec * 1000, `element (${new Locator(locator)}) still on page after ${aSec} sec`);
|
|
3161
3218
|
}
|
|
3162
3219
|
return this.browser.waitUntil(async () => {
|
|
3163
|
-
const res = await this
|
|
3220
|
+
const res = await this._res(locator);
|
|
3164
3221
|
if (!res || res.length === 0) {
|
|
3165
3222
|
return true;
|
|
3166
3223
|
}
|
|
@@ -3563,12 +3620,9 @@ async function proceedSee(assertType, text, context, strict = false) {
|
|
|
3563
3620
|
}
|
|
3564
3621
|
|
|
3565
3622
|
const smartWaitEnabled = assertType === 'assert';
|
|
3566
|
-
|
|
3567
3623
|
const res = await this._locate(withStrictLocator(context), smartWaitEnabled);
|
|
3568
3624
|
assertElementExists(res, context);
|
|
3569
|
-
|
|
3570
3625
|
const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)));
|
|
3571
|
-
|
|
3572
3626
|
if (strict) {
|
|
3573
3627
|
if (Array.isArray(selected) && selected.length !== 0) {
|
|
3574
3628
|
return selected.map(elText => equals(description)[assertType](text, elText));
|
|
@@ -3636,6 +3690,11 @@ async function filterAsync(array, callback) {
|
|
|
3636
3690
|
|
|
3637
3691
|
async function findClickable(locator, locateFn) {
|
|
3638
3692
|
locator = new Locator(locator);
|
|
3693
|
+
|
|
3694
|
+
if (this._isCustomLocator(locator)) {
|
|
3695
|
+
return locateFn(locator.value);
|
|
3696
|
+
}
|
|
3697
|
+
|
|
3639
3698
|
if (locator.isAccessibilityId() && !this.isWeb) return locateFn(locator, true);
|
|
3640
3699
|
if (!locator.isFuzzy()) return locateFn(locator, true);
|
|
3641
3700
|
|
|
@@ -3657,6 +3716,10 @@ async function findClickable(locator, locateFn) {
|
|
|
3657
3716
|
async function findFields(locator) {
|
|
3658
3717
|
locator = new Locator(locator);
|
|
3659
3718
|
|
|
3719
|
+
if (this._isCustomLocator(locator)) {
|
|
3720
|
+
return this._locate(locator);
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3660
3723
|
if (locator.isAccessibilityId() && !this.isWeb) return this._locate(locator, true);
|
|
3661
3724
|
if (!locator.isFuzzy()) return this._locate(locator, true);
|
|
3662
3725
|
|
|
@@ -3762,6 +3825,10 @@ async function findCheckable(locator, locateFn) {
|
|
|
3762
3825
|
let els;
|
|
3763
3826
|
locator = new Locator(locator);
|
|
3764
3827
|
|
|
3828
|
+
if (this._isCustomLocator(locator)) {
|
|
3829
|
+
return locateFn(locator.value);
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3765
3832
|
if (locator.isAccessibilityId() && !this.isWeb) return locateFn(locator, true);
|
|
3766
3833
|
if (!locator.isFuzzy()) return locateFn(locator, true);
|
|
3767
3834
|
|
|
@@ -3807,6 +3874,7 @@ function getElementId(el) {
|
|
|
3807
3874
|
if (el.ELEMENT) {
|
|
3808
3875
|
return el.ELEMENT;
|
|
3809
3876
|
}
|
|
3877
|
+
|
|
3810
3878
|
return null;
|
|
3811
3879
|
}
|
|
3812
3880
|
|
package/docs/changelog.md
CHANGED
|
@@ -7,13 +7,39 @@ layout: Section
|
|
|
7
7
|
|
|
8
8
|
# Releases
|
|
9
9
|
|
|
10
|
+
## 3.0.7
|
|
11
|
+
|
|
12
|
+
Documentation fixes:
|
|
13
|
+
* Remove broken link from `Nightmare helper`. See [#2860](https://github.com/codeceptjs/CodeceptJS/issues/2860) by **[Arhell](https://github.com/Arhell)**
|
|
14
|
+
* Fixed broken links in `playwright.md`. See [#2848](https://github.com/codeceptjs/CodeceptJS/issues/2848) by **[johnhoodjr](https://github.com/johnhoodjr)**
|
|
15
|
+
* Fix mocha-multi config example. See [#2881](https://github.com/codeceptjs/CodeceptJS/issues/2881) by **[rimesc](https://github.com/rimesc)**
|
|
16
|
+
* Fix small errors in email documentation file. See [#2884](https://github.com/codeceptjs/CodeceptJS/issues/2884) by **[mkrtchian](https://github.com/mkrtchian)**
|
|
17
|
+
* Improve documentation for `Sharing Data Between Workers` section. See [#2891](https://github.com/codeceptjs/CodeceptJS/issues/2891) by **[ngraf](https://github.com/ngraf)**
|
|
18
|
+
|
|
19
|
+
Features:
|
|
20
|
+
* **[WebDriver]** Shadow DOM Support for `Webdriver`. See [#2741](https://github.com/codeceptjs/CodeceptJS/issues/2741) by **[gkushang](https://github.com/gkushang)**
|
|
21
|
+
* [Release management] Introduce the versioning automatically, it follows the semantics versioning. See [#2883](https://github.com/codeceptjs/CodeceptJS/issues/2883) by **[PeterNgTr](https://github.com/PeterNgTr)**
|
|
22
|
+
* Adding opts into `Scenario.skip` that it would be useful for building reports. See [#2867](https://github.com/codeceptjs/CodeceptJS/issues/2867) by **[AlexKo4](https://github.com/AlexKo4)**
|
|
23
|
+
* Added support for attaching screenshots to [cucumberJsonReporter](https://github.com/ktryniszewski-mdsol/codeceptjs-cucumber-json-reporter) See [#2888](https://github.com/codeceptjs/CodeceptJS/issues/2888) by **[fijijavis](https://github.com/fijijavis)**
|
|
24
|
+
* Supported config file for `codeceptjs shell` command. See [#2895](https://github.com/codeceptjs/CodeceptJS/issues/2895) by **[PeterNgTr](https://github.com/PeterNgTr)**:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
npx codeceptjs shell -c foo.conf.js
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Bug fixes:
|
|
31
|
+
* **[GraphQL]** Use a helper-specific instance of Axios to avoid contaminating global defaults. See [#2868](https://github.com/codeceptjs/CodeceptJS/issues/2868) by **[vanvoljg](https://github.com/vanvoljg)**
|
|
32
|
+
* A default system color is used when passing non supported system color when using I.say(). See [#2874](https://github.com/codeceptjs/CodeceptJS/issues/2874) by **[PeterNgTr](https://github.com/PeterNgTr)**
|
|
33
|
+
* **[Playwright]** Avoid the timout due to calling the click on invisible elements. See [#2875](https://github.com/codeceptjs/CodeceptJS/issues/2875) by cbayer97
|
|
34
|
+
|
|
35
|
+
|
|
10
36
|
## 3.0.6
|
|
11
37
|
|
|
12
|
-
* **[Playwright]** Added `electron` as a browser to config. See [#2834](https://github.com/codeceptjs/CodeceptJS/issues/2834) by **[cbayer97](https://github.com/cbayer97)**
|
|
38
|
+
* **[Playwright]** Added `electron` as a browser to config. See [#2834](https://github.com/codeceptjs/CodeceptJS/issues/2834) by **[cbayer97](https://github.com/cbayer97)**
|
|
13
39
|
* **[Playwright]** Implemented `launchPersistentContext` to be able to launch persistent remote browsers. See [#2817](https://github.com/codeceptjs/CodeceptJS/issues/2817) by **[brunoqueiros](https://github.com/brunoqueiros)**. Fixes [#2376](https://github.com/codeceptjs/CodeceptJS/issues/2376).
|
|
14
40
|
* Fixed printing logs and stack traces for `run-workers`. See [#2857](https://github.com/codeceptjs/CodeceptJS/issues/2857) by **[haveac1gar](https://github.com/haveac1gar)**. Fixes [#2621](https://github.com/codeceptjs/CodeceptJS/issues/2621), [#2852](https://github.com/codeceptjs/CodeceptJS/issues/2852)
|
|
15
|
-
* Emit custom messages from worker to the main thread. See [#2824](https://github.com/codeceptjs/CodeceptJS/issues/2824) by **[jccguimaraes](https://github.com/jccguimaraes)**
|
|
16
|
-
* Improved workers processes output. See [#2804](https://github.com/codeceptjs/CodeceptJS/issues/2804) by **[drfiresign](https://github.com/drfiresign)**
|
|
41
|
+
* Emit custom messages from worker to the main thread. See [#2824](https://github.com/codeceptjs/CodeceptJS/issues/2824) by **[jccguimaraes](https://github.com/jccguimaraes)**
|
|
42
|
+
* Improved workers processes output. See [#2804](https://github.com/codeceptjs/CodeceptJS/issues/2804) by **[drfiresign](https://github.com/drfiresign)**
|
|
17
43
|
* BDD. Added ability to use an array of feature files inside config in `gherkin.features`. See [#2814](https://github.com/codeceptjs/CodeceptJS/issues/2814) by **[jbergeronjr](https://github.com/jbergeronjr)**
|
|
18
44
|
|
|
19
45
|
```js
|
|
@@ -22,8 +48,8 @@ layout: Section
|
|
|
22
48
|
"./features/api_features/*.feature"
|
|
23
49
|
],
|
|
24
50
|
```
|
|
25
|
-
* Added `getQueueId` to reporter to rerun a specific promise. See [#2837](https://github.com/codeceptjs/CodeceptJS/issues/2837) by **[jonatask](https://github.com/jonatask)**
|
|
26
|
-
* **Added `fakerTransform` plugin** to use faker data in Gherkin scenarios. See [#2854](https://github.com/codeceptjs/CodeceptJS/issues/2854) by **[adrielcodeco](https://github.com/adrielcodeco)**
|
|
51
|
+
* Added `getQueueId` to reporter to rerun a specific promise. See [#2837](https://github.com/codeceptjs/CodeceptJS/issues/2837) by **[jonatask](https://github.com/jonatask)**
|
|
52
|
+
* **Added `fakerTransform` plugin** to use faker data in Gherkin scenarios. See [#2854](https://github.com/codeceptjs/CodeceptJS/issues/2854) by **[adrielcodeco](https://github.com/adrielcodeco)**
|
|
27
53
|
|
|
28
54
|
```feature
|
|
29
55
|
Scenario Outline: ...
|
|
@@ -35,7 +61,7 @@ Scenario Outline: ...
|
|
|
35
61
|
| productName | customer | email | anythingMore |
|
|
36
62
|
| {{commerce.product}} | Dr. {{name.findName}} | {{internet.email}} | staticData |
|
|
37
63
|
```
|
|
38
|
-
* **[REST]** Use class instance of axios, not the global instance, to avoid contaminating global configuration. [#2846](https://github.com/codeceptjs/CodeceptJS/issues/2846) by **[vanvoljg](https://github.com/vanvoljg)**
|
|
64
|
+
* **[REST]** Use class instance of axios, not the global instance, to avoid contaminating global configuration. [#2846](https://github.com/codeceptjs/CodeceptJS/issues/2846) by **[vanvoljg](https://github.com/vanvoljg)**
|
|
39
65
|
* **[Appium]** Added `tunnelIdentifier` config option to provide tunnel for SauceLabs. See [#2832](https://github.com/codeceptjs/CodeceptJS/issues/2832) by **[gurjeetbains](https://github.com/gurjeetbains)**
|
|
40
66
|
|
|
41
67
|
## 3.0.5
|
|
@@ -43,9 +69,9 @@ Scenario Outline: ...
|
|
|
43
69
|
|
|
44
70
|
Features:
|
|
45
71
|
|
|
46
|
-
* **[Official Docker image for CodeceptJS v3](https://hub.docker.com/r/codeceptjs/codeceptjs)**. New Docker image is based on official Playwright image and supports Playwright, Puppeteer, WebDriver engines. Thanks **[VikentyShevyrin](https://github.com/VikentyShevyrin)**
|
|
72
|
+
* **[Official Docker image for CodeceptJS v3](https://hub.docker.com/r/codeceptjs/codeceptjs)**. New Docker image is based on official Playwright image and supports Playwright, Puppeteer, WebDriver engines. Thanks **[VikentyShevyrin](https://github.com/VikentyShevyrin)**
|
|
47
73
|
* Better support for Typescript `codecept.conf.ts` configuration files. See [#2750](https://github.com/codeceptjs/CodeceptJS/issues/2750) by **[elaichenkov](https://github.com/elaichenkov)**
|
|
48
|
-
* Propagate more events for custom parallel script. See [#2796](https://github.com/codeceptjs/CodeceptJS/issues/2796) by **[jccguimaraes](https://github.com/jccguimaraes)**
|
|
74
|
+
* Propagate more events for custom parallel script. See [#2796](https://github.com/codeceptjs/CodeceptJS/issues/2796) by **[jccguimaraes](https://github.com/jccguimaraes)**
|
|
49
75
|
* [mocha-junit-reporter] Now supports attachments, see documentation for details. See [#2675](https://github.com/codeceptjs/CodeceptJS/issues/2675) by **[Shard](https://github.com/Shard)**
|
|
50
76
|
* CustomLocators interface for TypeScript to extend from LocatorOrString. See [#2798](https://github.com/codeceptjs/CodeceptJS/issues/2798) by **[danielrentz](https://github.com/danielrentz)**
|
|
51
77
|
* **[REST]** Mask sensitive data from log messages.
|
|
@@ -144,7 +170,7 @@ Scenario('title', (I, loginPage) => {});
|
|
|
144
170
|
Scenario('title', ({ I, loginPage }) => {});
|
|
145
171
|
```
|
|
146
172
|
|
|
147
|
-
* **BREAKING** Replaced bootstrap/teardown scripts to accept only functions or async functions. Async function with callback (with done parameter) should be replaced with async/await. [See our
|
|
173
|
+
* **BREAKING** Replaced bootstrap/teardown scripts to accept only functions or async functions. Async function with callback (with done parameter) should be replaced with async/await. [See our upgrade guide](https://bit.ly/codecept3Up).
|
|
148
174
|
* **[TypeScript guide](/typescript)** and [boilerplate project](https://github.com/codeceptjs/typescript-boilerplate)
|
|
149
175
|
* [tryTo](/plugins/#tryto) and [pauseOnFail](/plugins/#pauseOnFail) plugins installed by default
|
|
150
176
|
* Introduced one-line installer:
|
package/docs/email.md
CHANGED
|
@@ -6,10 +6,10 @@ title: Email Testing
|
|
|
6
6
|
# Email Testing
|
|
7
7
|
|
|
8
8
|
In End 2 End testing we need to interact with emails.
|
|
9
|
-
Email delivery can't tested locally or mocked while testing.
|
|
10
|
-
That's why for an end to end test you need
|
|
9
|
+
Email delivery can't be tested locally or mocked while testing.
|
|
10
|
+
That's why for an end to end test you need real emails to be sent and real email address to receive that emails.
|
|
11
11
|
|
|
12
|
-
Setting up an email server can be hard. So we recommend to use
|
|
12
|
+
Setting up an email server can be hard. So we recommend to use [MailSlurp](https://mailslurp.com/) - a service designed for testing emails. It creates disposable mailboxes and provides you an access to those mailboxes via REST API.
|
|
13
13
|
|
|
14
14
|
> You no longer need to open your gmail account in a browser to check for an email!
|
|
15
15
|
|
|
@@ -41,7 +41,7 @@ npx codeceptjs def
|
|
|
41
41
|
|
|
42
42
|
## Creating Mailbox
|
|
43
43
|
|
|
44
|
-
MailSlurp allows you to create disposable mailboxes. It means that an email address is created for
|
|
44
|
+
MailSlurp allows you to create disposable mailboxes. It means that an email address is created for one test only and is deleted afterwards. So you can be confident that no other emails are received at that address.
|
|
45
45
|
|
|
46
46
|
To create a mailbox use `I.haveNewMailbox()` command:
|
|
47
47
|
|
|
@@ -57,7 +57,7 @@ mailbox object contains:
|
|
|
57
57
|
|
|
58
58
|
> See [MailSlurp's guide](https://www.mailslurp.com/guides/getting-started/#create-email-addresses) for details.
|
|
59
59
|
|
|
60
|
-
Mailbox is opened on creation. If you need more than one
|
|
60
|
+
Mailbox is opened on creation. If you need more than one mailbox and you want to switch between them use `openMailbox` method:
|
|
61
61
|
|
|
62
62
|
```js
|
|
63
63
|
const mailbox1 = await I.haveNewMailbox();
|
|
@@ -71,7 +71,7 @@ I.openMailbox(mailbox1);
|
|
|
71
71
|
|
|
72
72
|
A last created mailbox will be activated. It means that it will be used by default to check for emails.
|
|
73
73
|
|
|
74
|
-
After an action that triggers sending an email is performed on a website you should wait for this email to be received.
|
|
74
|
+
After an action that triggers sending an email is performed on a website, you should wait for this email to be received.
|
|
75
75
|
A timeout for waiting an email can be set globally for a helper or for a one call.
|
|
76
76
|
|
|
77
77
|
Use `waitForLatestEmail` function to return the first email from a mailbox:
|
|
@@ -109,7 +109,7 @@ const email = await I.waitForLatestEmail();
|
|
|
109
109
|
```
|
|
110
110
|
> Please note, that we use `await` to assign email. This should be declared inside async function
|
|
111
111
|
|
|
112
|
-
An `email` object contains following fields:
|
|
112
|
+
An `email` object contains the following fields:
|
|
113
113
|
|
|
114
114
|
* `subject`
|
|
115
115
|
* `for`
|
|
@@ -130,7 +130,7 @@ I.amOnPage(url);
|
|
|
130
130
|
|
|
131
131
|
## Assertions
|
|
132
132
|
|
|
133
|
-
Assertions are performed on the currently opened email.Email is opened on `waitFor` email call, however, you can open an exact email by using `openEmail` function.
|
|
133
|
+
Assertions are performed on the currently opened email. Email is opened on `waitFor` email call, however, you can open an exact email by using `openEmail` function.
|
|
134
134
|
|
|
135
135
|
```js
|
|
136
136
|
const email1 = await I.waitForLatestEmail();
|
package/docs/examples.md
CHANGED
|
@@ -8,9 +8,9 @@ editLink: false
|
|
|
8
8
|
|
|
9
9
|
# Examples
|
|
10
10
|
> Add your own examples to our [Wiki Page](https://github.com/codeceptjs/CodeceptJS/wiki/Examples)
|
|
11
|
-
## [TodoMVC Examples](https://github.com/
|
|
11
|
+
## [TodoMVC Examples](https://github.com/codecept-js/examples)
|
|
12
12
|
|
|
13
|
-

|
|
14
14
|
|
|
15
15
|
Playground repository where you can run tests in different helpers on a basic single-page website.
|
|
16
16
|
|
|
@@ -155,4 +155,4 @@ Suggestions and improvements are welcome , please raise a ticket in Issue tab.
|
|
|
155
155
|
* Step by step setup in README
|
|
156
156
|
* Two helpers are added. UI - Puppeteer , API - REST and chai-codeceptJS for assetion
|
|
157
157
|
* ESLint for code check
|
|
158
|
-
* Upcoming : API generic functions , Adaptor design pattern , More utilities
|
|
158
|
+
* Upcoming : API generic functions , Adaptor design pattern , More utilities
|
|
@@ -56,7 +56,7 @@ helpers: {
|
|
|
56
56
|
Puppeteer: {
|
|
57
57
|
// regular Puppeteer config here
|
|
58
58
|
},
|
|
59
|
-
|
|
59
|
+
MockRequestHelper: {
|
|
60
60
|
require: '@codeceptjs/mock-request',
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -67,7 +67,7 @@ helpers: {
|
|
|
67
67
|
```js
|
|
68
68
|
// sample options
|
|
69
69
|
helpers: {
|
|
70
|
-
|
|
70
|
+
MockRequestHelper: {
|
|
71
71
|
require: '@codeceptjs/mock-request',
|
|
72
72
|
mode: record,
|
|
73
73
|
recordIfMissing: true,
|
|
@@ -115,7 +115,7 @@ helpers: {
|
|
|
115
115
|
WebDriver: {
|
|
116
116
|
// regular WebDriver config here
|
|
117
117
|
},
|
|
118
|
-
|
|
118
|
+
MockRequestHelper: {
|
|
119
119
|
require: '@codeceptjs/mock-request',
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -28,7 +28,7 @@ Requires `playwright` package version ^1 to be installed:
|
|
|
28
28
|
This helper should be configured in codecept.json or codecept.conf.js
|
|
29
29
|
|
|
30
30
|
- `url`: base url of website to be tested
|
|
31
|
-
- `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`. Default: chromium.
|
|
31
|
+
- `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
|
|
32
32
|
- `show`: - show browser window.
|
|
33
33
|
- `restart`: - restart browser between tests.
|
|
34
34
|
- `disableScreenshots`: - don't save screenshot on failure.
|
|
@@ -47,6 +47,7 @@ This helper should be configured in codecept.json or codecept.conf.js
|
|
|
47
47
|
- `userAgent`: (optional) user-agent string.
|
|
48
48
|
- `manualStart`: - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
|
|
49
49
|
- `chromium`: (optional) pass additional chromium options
|
|
50
|
+
- `electron`: (optional) pass additional electron options
|
|
50
51
|
|
|
51
52
|
#### Example #1: Wait for 0 network connections.
|
|
52
53
|
|
|
@@ -175,6 +176,14 @@ Add the 'dialog' event listener to a page
|
|
|
175
176
|
|
|
176
177
|
- `page`
|
|
177
178
|
|
|
179
|
+
### _contextLocator
|
|
180
|
+
|
|
181
|
+
Grab Locator if called within Context
|
|
182
|
+
|
|
183
|
+
#### Parameters
|
|
184
|
+
|
|
185
|
+
- `locator` **any**
|
|
186
|
+
|
|
178
187
|
### _getPageUrl
|
|
179
188
|
|
|
180
189
|
Gets page URL including hash.
|
package/docs/locators.md
CHANGED
|
@@ -297,8 +297,35 @@ codeceptjs.locator.addFilter((providedLocator, locatorObj) => {
|
|
|
297
297
|
```
|
|
298
298
|
New locator strategy is ready to use:
|
|
299
299
|
|
|
300
|
+
|
|
300
301
|
```js
|
|
301
302
|
I.click('=Login');
|
|
302
303
|
```
|
|
303
304
|
|
|
305
|
+
#### Custom Strategy Locators
|
|
306
|
+
|
|
307
|
+
CodeceptJS provides the option to specify custom locators that uses Custom Locator Strategies defined in the WebDriver configuration. It uses the WebDriverIO's [custom$](https://webdriver.io/docs/api/browser/custom$.html) locators internally to locate the elements on page.
|
|
308
|
+
To use the defined Custom Locator Strategy add your custom strategy to your configuration.
|
|
309
|
+
|
|
310
|
+
```js
|
|
311
|
+
// in codecept.conf.js
|
|
312
|
+
|
|
313
|
+
const myStrat = (selector) => {
|
|
314
|
+
return document.querySelectorAll(selector)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// under WebDriver Helpers Configuration
|
|
318
|
+
WebDriver: {
|
|
319
|
+
...
|
|
320
|
+
customLocatorStrategies: {
|
|
321
|
+
custom: myStrat
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
I.click({custom: 'my-shadow-element-unique-css'})
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
|
|
304
331
|
> For more details on locator object see [Locator](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/locator.js) class implementation.
|
package/docs/nightmare.md
CHANGED
|
@@ -221,8 +221,3 @@ I.seeAttributeContains('#main img', 'src', '/cat.jpg');
|
|
|
221
221
|
This sample assertion used `_locate` helper method which searched for elements
|
|
222
222
|
by CSS/XPath or a strict locator. Then `browser.evaluate` method was called to
|
|
223
223
|
use locate found elements on a page and return attribute from the first of them.
|
|
224
|
-
|
|
225
|
-
## Additional Links
|
|
226
|
-
|
|
227
|
-
* [Nightmare Tutorial](http://codenroll.it/acceptance-testing-with-codecept-js/) by jploskonka.
|
|
228
|
-
|
package/docs/parallel.md
CHANGED
|
@@ -26,7 +26,7 @@ This command is similar to `run`, however, steps output can't be shown in worker
|
|
|
26
26
|
|
|
27
27
|
Each worker spins an instance of CodeceptJS, executes a group of tests, and sends back report to the main process.
|
|
28
28
|
|
|
29
|
-
By default the tests are assigned one by one to the
|
|
29
|
+
By default the tests are assigned one by one to the available workers this may lead to multiple execution of `BeforeSuite()`. Use the option `--suites` to assigne the suites one by one to the workers.
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
32
|
npx codeceptjs run-workers --suites 2
|
|
@@ -196,22 +196,23 @@ workers.on(event.all.result, (status, completedTests, workerStats) => {
|
|
|
196
196
|
|
|
197
197
|
## Sharing Data Between Workers
|
|
198
198
|
|
|
199
|
-
NodeJS Workers can communicate between each other via messaging system. It may happen that you want to pass some data from one of workers to other. For instance, you may want to share user credentials accross all tests. Data will be appended to a container.
|
|
199
|
+
NodeJS Workers can communicate between each other via messaging system. It may happen that you want to pass some data from one of the workers to other. For instance, you may want to share user credentials accross all tests. Data will be appended to a container.
|
|
200
200
|
|
|
201
|
-
However, you can't access uninitialized data from a container, so to start, you need to
|
|
201
|
+
However, you can't access uninitialized data from a container, so to start, you need to initialize data first. Inside `bootstrap` function of the config we execute the `share` to initialize value:
|
|
202
202
|
|
|
203
203
|
|
|
204
204
|
```js
|
|
205
205
|
// inside codecept.conf.js
|
|
206
206
|
exports.config = {
|
|
207
207
|
bootstrap() {
|
|
208
|
-
// append empty userData to container
|
|
209
|
-
share({ userData: false }
|
|
208
|
+
// append empty userData to container
|
|
209
|
+
share({ userData: false });
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
```
|
|
213
|
+
|
|
213
214
|
Now each worker has `userData` inside a container. However, it is empty.
|
|
214
|
-
When you obtain real data in one of tests you can this data accross tests. Use `inject` function to access data inside a container:
|
|
215
|
+
When you obtain real data in one of the tests you can now `share` this data accross tests. Use `inject` function to access data inside a container:
|
|
215
216
|
|
|
216
217
|
```js
|
|
217
218
|
// get current value of userData
|
|
@@ -220,6 +221,12 @@ let { userData } = inject();
|
|
|
220
221
|
if (!userData) {
|
|
221
222
|
userData = { name: 'user', password: '123456' };
|
|
222
223
|
// now new userData will be shared accross all workers
|
|
223
|
-
share(userData);
|
|
224
|
+
share({userData : userData});
|
|
224
225
|
}
|
|
225
226
|
```
|
|
227
|
+
|
|
228
|
+
If you want to share data only within same worker, and not across all workers, you need to add option `local: true` every time you run `share`
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
share({ userData: false }, {local: true });
|
|
232
|
+
```
|
package/docs/playwright.md
CHANGED
|
@@ -7,7 +7,7 @@ title: Testing with Playwright
|
|
|
7
7
|
|
|
8
8
|
Playwright is a Node library to automate the [Chromium](https://www.chromium.org/Home), [WebKit](https://webkit.org/) and [Firefox](https://www.mozilla.org/en-US/firefox/new/) browsers as well as [Electron](https://www.electronjs.org/) apps with a single API. It enables **cross-browser** web automation that is **ever-green**, **capable**, **reliable** and **fast**.
|
|
9
9
|
|
|
10
|
-
Playwright was built similarly to [Puppeteer](https://github.com/puppeteer/puppeteer), using its API and so is very different in usage. However, Playwright has cross browser support with better design for test
|
|
10
|
+
Playwright was built similarly to [Puppeteer](https://github.com/puppeteer/puppeteer), using its API and so is very different in usage. However, Playwright has cross browser support with better design for test automation.
|
|
11
11
|
|
|
12
12
|
Take a look at a sample test:
|
|
13
13
|
|
|
@@ -270,7 +270,7 @@ Playwright can emulate browsers of mobile devices. Instead of paying for expensi
|
|
|
270
270
|
|
|
271
271
|
Device emulation can be enabled in CodeceptJS globally in a config or per session.
|
|
272
272
|
|
|
273
|
-
Playwright contains a [list of predefined devices](https://github.com/
|
|
273
|
+
Playwright contains a [list of predefined devices](https://github.com/microsoft/playwright/blob/master/src/server/deviceDescriptors.js) to emulate, for instance this is how you can enable iPhone 6 emulation for all tests:
|
|
274
274
|
|
|
275
275
|
```js
|
|
276
276
|
const { devices } = require('playwright');
|
|
@@ -282,7 +282,7 @@ helpers: {
|
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
```
|
|
285
|
-
To adjust browser settings you can pass [custom options](https://github.com/microsoft/playwright/blob/master/docs/api.md
|
|
285
|
+
To adjust browser settings you can pass [custom options](https://github.com/microsoft/playwright/blob/master/docs/src/api/class-browsercontext.md)
|
|
286
286
|
|
|
287
287
|
```js
|
|
288
288
|
helpers: {
|
|
@@ -322,7 +322,7 @@ Playwright can be added to GitHub Actions using [official action](https://github
|
|
|
322
322
|
|
|
323
323
|
## Accessing Playwright API
|
|
324
324
|
|
|
325
|
-
To get [Playwright API](https://github.com/microsoft/playwright/
|
|
325
|
+
To get [Playwright API](https://github.com/microsoft/playwright/tree/master/docs/src/api) inside a test use `I.usePlaywrightTo` method with a callback.
|
|
326
326
|
To keep test readable provide a description of a callback inside the first parameter.
|
|
327
327
|
|
|
328
328
|
```js
|
|
@@ -385,6 +385,6 @@ async setPermissions() {
|
|
|
385
385
|
}
|
|
386
386
|
```
|
|
387
387
|
|
|
388
|
-
> [▶ Learn more about BrowserContext](https://github.com/microsoft/playwright/blob/master/docs/api
|
|
388
|
+
> [▶ Learn more about BrowserContext](https://github.com/microsoft/playwright/blob/master/docs/src/api/class-browsercontext.md)
|
|
389
389
|
|
|
390
|
-
> [▶ Learn more about Helpers](
|
|
390
|
+
> [▶ Learn more about Helpers](https://codecept.io/helpers/)
|
package/docs/reports.md
CHANGED
|
@@ -352,10 +352,11 @@ Configure mocha-multi with reports that you want:
|
|
|
352
352
|
}
|
|
353
353
|
},
|
|
354
354
|
"mochawesome": {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
355
|
+
"stdout": "./output/console.log",
|
|
356
|
+
"options": {
|
|
357
|
+
"reportDir": "./output",
|
|
358
|
+
"reportFilename": "report"
|
|
359
|
+
}
|
|
359
360
|
},
|
|
360
361
|
"mocha-junit-reporter": {
|
|
361
362
|
"stdout": "./output/console.log",
|
|
@@ -8,9 +8,11 @@ module.exports = async function (path, options) {
|
|
|
8
8
|
// Backward compatibility for --profile
|
|
9
9
|
process.profile = options.profile;
|
|
10
10
|
process.env.profile = options.profile;
|
|
11
|
+
const configFile = options.config;
|
|
12
|
+
|
|
13
|
+
const config = getConfig(configFile);
|
|
14
|
+
const testsPath = getTestRoot(configFile);
|
|
11
15
|
|
|
12
|
-
const testsPath = getTestRoot(path);
|
|
13
|
-
const config = getConfig(testsPath);
|
|
14
16
|
const codecept = new Codecept(config, options);
|
|
15
17
|
codecept.init(testsPath);
|
|
16
18
|
|