codeceptjs 3.1.3 → 3.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +75 -1
- package/README.md +2 -3
- package/bin/codecept.js +1 -0
- package/docs/advanced.md +99 -61
- package/docs/basics.md +27 -2
- package/docs/bdd.md +2 -2
- package/docs/build/Appium.js +62 -0
- package/docs/build/FileSystem.js +12 -1
- package/docs/build/Playwright.js +37 -33
- package/docs/build/Protractor.js +9 -24
- package/docs/build/Puppeteer.js +10 -28
- package/docs/build/REST.js +1 -0
- package/docs/build/WebDriver.js +2 -24
- package/docs/changelog.md +75 -1
- package/docs/configuration.md +8 -8
- package/docs/custom-helpers.md +2 -37
- package/docs/data.md +9 -9
- package/docs/helpers/Appium.md +240 -198
- package/docs/helpers/FileSystem.md +12 -2
- package/docs/helpers/Playwright.md +226 -225
- package/docs/helpers/Puppeteer.md +1 -17
- package/docs/helpers/REST.md +3 -1
- package/docs/helpers/WebDriver.md +1 -17
- package/docs/installation.md +1 -1
- package/docs/mobile-react-native-locators.md +3 -0
- package/docs/mobile.md +11 -11
- package/docs/nightmare.md +3 -3
- package/docs/pageobjects.md +2 -0
- package/docs/playwright.md +4 -4
- package/docs/plugins.md +138 -9
- package/docs/puppeteer.md +5 -5
- package/docs/reports.md +3 -3
- package/docs/testcafe.md +1 -1
- package/docs/translation.md +1 -1
- package/docs/visual.md +2 -2
- package/docs/vue.md +1 -1
- package/docs/webdriver.md +2 -2
- package/lib/actor.js +19 -1
- package/lib/cli.js +25 -20
- package/lib/codecept.js +2 -0
- package/lib/command/info.js +1 -1
- package/lib/command/workers/runTests.js +25 -7
- package/lib/config.js +12 -0
- package/lib/container.js +3 -1
- package/lib/helper/Appium.js +62 -0
- package/lib/helper/FileSystem.js +12 -1
- package/lib/helper/Playwright.js +37 -23
- package/lib/helper/Protractor.js +2 -14
- package/lib/helper/Puppeteer.js +3 -18
- package/lib/helper/REST.js +1 -0
- package/lib/helper/WebDriver.js +2 -14
- package/lib/interfaces/featureConfig.js +3 -0
- package/lib/interfaces/scenarioConfig.js +4 -0
- package/lib/listener/steps.js +21 -3
- package/lib/listener/timeout.js +72 -0
- package/lib/locator.js +3 -0
- package/lib/plugin/allure.js +6 -1
- package/lib/plugin/autoLogin.js +1 -1
- package/lib/plugin/retryFailedStep.js +4 -3
- package/lib/plugin/retryTo.js +130 -0
- package/lib/plugin/screenshotOnFail.js +1 -0
- package/lib/plugin/stepByStepReport.js +7 -0
- package/lib/plugin/stepTimeout.js +91 -0
- package/lib/plugin/tryTo.js +6 -0
- package/lib/recorder.js +18 -6
- package/lib/step.js +58 -0
- package/lib/store.js +2 -0
- package/lib/ui.js +2 -2
- package/package.json +4 -6
- package/typings/index.d.ts +8 -1
- package/typings/types.d.ts +149 -164
- package/docs/angular.md +0 -325
- package/docs/helpers/Protractor.md +0 -1658
- package/docs/webapi/waitUntil.mustache +0 -11
- package/typings/Protractor.d.ts +0 -16
package/lib/codecept.js
CHANGED
|
@@ -77,6 +77,7 @@ class Codecept {
|
|
|
77
77
|
global.inject = container.support;
|
|
78
78
|
global.share = container.share;
|
|
79
79
|
global.secret = require('./secret').secret;
|
|
80
|
+
global.codecept_debug = output.debug;
|
|
80
81
|
global.codeceptjs = require('./index'); // load all objects
|
|
81
82
|
|
|
82
83
|
// BDD
|
|
@@ -95,6 +96,7 @@ class Codecept {
|
|
|
95
96
|
runHook(require('./listener/steps'));
|
|
96
97
|
runHook(require('./listener/config'));
|
|
97
98
|
runHook(require('./listener/helpers'));
|
|
99
|
+
runHook(require('./listener/timeout'));
|
|
98
100
|
runHook(require('./listener/exit'));
|
|
99
101
|
|
|
100
102
|
// custom hooks
|
package/lib/command/info.js
CHANGED
|
@@ -32,7 +32,7 @@ module.exports = async function (path) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
output.print('***************************************');
|
|
35
|
-
output.print('If you have questions ask them in our Slack:
|
|
35
|
+
output.print('If you have questions ask them in our Slack: http://bit.ly/chat-codeceptjs');
|
|
36
36
|
output.print('Or ask them on our discussion board: https://codecept.discourse.group/');
|
|
37
37
|
output.print('Please copy environment info when you report issues on GitHub: https://github.com/Codeception/CodeceptJS/issues');
|
|
38
38
|
output.print('***************************************');
|
|
@@ -73,6 +73,27 @@ function filterTests() {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
function initializeListeners() {
|
|
76
|
+
function simplifyError(error) {
|
|
77
|
+
if (error) {
|
|
78
|
+
const {
|
|
79
|
+
stack,
|
|
80
|
+
uncaught,
|
|
81
|
+
message,
|
|
82
|
+
actual,
|
|
83
|
+
expected,
|
|
84
|
+
} = error;
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
stack,
|
|
88
|
+
uncaught,
|
|
89
|
+
message,
|
|
90
|
+
actual,
|
|
91
|
+
expected,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
76
97
|
function simplifyTest(test, err = null) {
|
|
77
98
|
test = { ...test };
|
|
78
99
|
|
|
@@ -82,13 +103,10 @@ function initializeListeners() {
|
|
|
82
103
|
}
|
|
83
104
|
|
|
84
105
|
if (test.err) {
|
|
85
|
-
err =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
actual: test.err.actual,
|
|
90
|
-
expected: test.err.expected,
|
|
91
|
-
};
|
|
106
|
+
err = simplifyError(test.err);
|
|
107
|
+
test.status = 'failed';
|
|
108
|
+
} else if (err) {
|
|
109
|
+
err = simplifyError(err);
|
|
92
110
|
test.status = 'failed';
|
|
93
111
|
}
|
|
94
112
|
const parent = {};
|
package/lib/config.js
CHANGED
|
@@ -13,6 +13,7 @@ const defaultConfig = {
|
|
|
13
13
|
include: {},
|
|
14
14
|
mocha: {},
|
|
15
15
|
bootstrap: null,
|
|
16
|
+
timeout: null,
|
|
16
17
|
teardown: null,
|
|
17
18
|
hooks: [],
|
|
18
19
|
gherkin: {},
|
|
@@ -21,6 +22,17 @@ const defaultConfig = {
|
|
|
21
22
|
enabled: true, // will be disabled by default in 2.0
|
|
22
23
|
},
|
|
23
24
|
},
|
|
25
|
+
stepTimeout: 0,
|
|
26
|
+
stepTimeoutOverride: [
|
|
27
|
+
{
|
|
28
|
+
pattern: 'wait.*',
|
|
29
|
+
timeout: 0,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
pattern: 'amOnPage',
|
|
33
|
+
timeout: 0,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
24
36
|
};
|
|
25
37
|
|
|
26
38
|
let hooks = [];
|
package/lib/container.js
CHANGED
|
@@ -7,6 +7,7 @@ const MochaFactory = require('./mochaFactory');
|
|
|
7
7
|
const recorder = require('./recorder');
|
|
8
8
|
const event = require('./event');
|
|
9
9
|
const WorkerStorage = require('./workerStorage');
|
|
10
|
+
const store = require('./store');
|
|
10
11
|
|
|
11
12
|
let container = {
|
|
12
13
|
helpers: {},
|
|
@@ -45,6 +46,7 @@ class Container {
|
|
|
45
46
|
container.support = createSupportObjects(config.include || {});
|
|
46
47
|
container.plugins = createPlugins(config.plugins || {}, opts);
|
|
47
48
|
if (config.gherkin) loadGherkinSteps(config.gherkin.steps || []);
|
|
49
|
+
if (opts && typeof opts.timeouts === 'boolean') store.timeouts = opts.timeouts;
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/**
|
|
@@ -233,7 +235,7 @@ function createSupportObjects(config) {
|
|
|
233
235
|
const currentObject = objects[object];
|
|
234
236
|
Object.keys(currentObject).forEach((method) => {
|
|
235
237
|
const currentMethod = currentObject[method];
|
|
236
|
-
if (currentMethod[Symbol.toStringTag] === 'AsyncFunction') {
|
|
238
|
+
if (currentMethod && currentMethod[Symbol.toStringTag] === 'AsyncFunction') {
|
|
237
239
|
objects[object][method] = asyncWrapper(currentMethod);
|
|
238
240
|
}
|
|
239
241
|
});
|
package/lib/helper/Appium.js
CHANGED
|
@@ -331,6 +331,7 @@ class Appium extends Webdriver {
|
|
|
331
331
|
*
|
|
332
332
|
* @param {*} caps
|
|
333
333
|
* @param {*} fn
|
|
334
|
+
* @return {Promise<any>}
|
|
334
335
|
*/
|
|
335
336
|
async runOnIOS(caps, fn) {
|
|
336
337
|
if (this.platform !== 'ios') return;
|
|
@@ -373,6 +374,7 @@ class Appium extends Webdriver {
|
|
|
373
374
|
*
|
|
374
375
|
* @param {*} caps
|
|
375
376
|
* @param {*} fn
|
|
377
|
+
* @return {Promise<any>}
|
|
376
378
|
*/
|
|
377
379
|
async runOnAndroid(caps, fn) {
|
|
378
380
|
if (this.platform !== 'android') return;
|
|
@@ -393,6 +395,7 @@ class Appium extends Webdriver {
|
|
|
393
395
|
* ```
|
|
394
396
|
*
|
|
395
397
|
* @param {*} fn
|
|
398
|
+
* @return {Promise<any>}
|
|
396
399
|
*/
|
|
397
400
|
/* eslint-disable */
|
|
398
401
|
async runInWeb(fn) {
|
|
@@ -434,6 +437,7 @@ class Appium extends Webdriver {
|
|
|
434
437
|
* ```
|
|
435
438
|
*
|
|
436
439
|
* @param {string} bundleId String ID of bundled app
|
|
440
|
+
* @return {Promise<void>}
|
|
437
441
|
*
|
|
438
442
|
* Appium: support only Android
|
|
439
443
|
*/
|
|
@@ -451,6 +455,7 @@ class Appium extends Webdriver {
|
|
|
451
455
|
* ```
|
|
452
456
|
*
|
|
453
457
|
* @param {string} bundleId String ID of bundled app
|
|
458
|
+
* @return {Promise<void>}
|
|
454
459
|
*
|
|
455
460
|
* Appium: support only Android
|
|
456
461
|
*/
|
|
@@ -467,6 +472,7 @@ class Appium extends Webdriver {
|
|
|
467
472
|
* I.installApp('/path/to/file.apk');
|
|
468
473
|
* ```
|
|
469
474
|
* @param {string} path path to apk file
|
|
475
|
+
* @return {Promise<void>}
|
|
470
476
|
*
|
|
471
477
|
* Appium: support only Android
|
|
472
478
|
*/
|
|
@@ -508,6 +514,7 @@ class Appium extends Webdriver {
|
|
|
508
514
|
* I.seeCurrentActivityIs(".HomeScreenActivity")
|
|
509
515
|
* ```
|
|
510
516
|
* @param {string} currentActivity
|
|
517
|
+
* @return {Promise<void>}
|
|
511
518
|
*
|
|
512
519
|
* Appium: support only Android
|
|
513
520
|
*/
|
|
@@ -524,6 +531,8 @@ class Appium extends Webdriver {
|
|
|
524
531
|
* I.seeDeviceIsLocked();
|
|
525
532
|
* ```
|
|
526
533
|
*
|
|
534
|
+
* @return {Promise<void>}
|
|
535
|
+
*
|
|
527
536
|
* Appium: support only Android
|
|
528
537
|
*/
|
|
529
538
|
async seeDeviceIsLocked() {
|
|
@@ -539,6 +548,8 @@ class Appium extends Webdriver {
|
|
|
539
548
|
* I.seeDeviceIsUnlocked();
|
|
540
549
|
* ```
|
|
541
550
|
*
|
|
551
|
+
* @return {Promise<void>}
|
|
552
|
+
*
|
|
542
553
|
* Appium: support only Android
|
|
543
554
|
*/
|
|
544
555
|
async seeDeviceIsUnlocked() {
|
|
@@ -555,6 +566,8 @@ class Appium extends Webdriver {
|
|
|
555
566
|
* I.seeOrientationIs('LANDSCAPE')
|
|
556
567
|
* ```
|
|
557
568
|
*
|
|
569
|
+
* @return {Promise<void>}
|
|
570
|
+
*
|
|
558
571
|
* @param {'LANDSCAPE'|'PORTRAIT'} orientation LANDSCAPE or PORTRAIT
|
|
559
572
|
*
|
|
560
573
|
* Appium: support Android and iOS
|
|
@@ -586,6 +599,7 @@ class Appium extends Webdriver {
|
|
|
586
599
|
* ```
|
|
587
600
|
*
|
|
588
601
|
* @param {'LANDSCAPE'|'PORTRAIT'} orientation LANDSCAPE or PORTRAIT
|
|
602
|
+
* @return {Promise<any>}
|
|
589
603
|
*
|
|
590
604
|
* Appium: support Android and iOS
|
|
591
605
|
*/
|
|
@@ -609,6 +623,8 @@ class Appium extends Webdriver {
|
|
|
609
623
|
* let contexts = await I.grabAllContexts();
|
|
610
624
|
* ```
|
|
611
625
|
*
|
|
626
|
+
* @return {Promise<string[]>}
|
|
627
|
+
*
|
|
612
628
|
* Appium: support Android and iOS
|
|
613
629
|
*/
|
|
614
630
|
async grabAllContexts() {
|
|
@@ -623,6 +639,8 @@ class Appium extends Webdriver {
|
|
|
623
639
|
* let context = await I.grabContext();
|
|
624
640
|
* ```
|
|
625
641
|
*
|
|
642
|
+
* @return {Promise<string|null>}
|
|
643
|
+
*
|
|
626
644
|
* Appium: support Android and iOS
|
|
627
645
|
*/
|
|
628
646
|
async grabContext() {
|
|
@@ -637,6 +655,8 @@ class Appium extends Webdriver {
|
|
|
637
655
|
* let activity = await I.grabCurrentActivity();
|
|
638
656
|
* ```
|
|
639
657
|
*
|
|
658
|
+
* @return {Promise<string>}
|
|
659
|
+
*
|
|
640
660
|
* Appium: support only Android
|
|
641
661
|
*/
|
|
642
662
|
async grabCurrentActivity() {
|
|
@@ -653,6 +673,8 @@ class Appium extends Webdriver {
|
|
|
653
673
|
* let con = await I.grabNetworkConnection();
|
|
654
674
|
* ```
|
|
655
675
|
*
|
|
676
|
+
* @return {Promise<{}>}
|
|
677
|
+
*
|
|
656
678
|
* Appium: support only Android
|
|
657
679
|
*/
|
|
658
680
|
async grabNetworkConnection() {
|
|
@@ -673,6 +695,8 @@ class Appium extends Webdriver {
|
|
|
673
695
|
* let orientation = await I.grabOrientation();
|
|
674
696
|
* ```
|
|
675
697
|
*
|
|
698
|
+
* @return {Promise<string>}
|
|
699
|
+
*
|
|
676
700
|
* Appium: support Android and iOS
|
|
677
701
|
*/
|
|
678
702
|
async grabOrientation() {
|
|
@@ -689,6 +713,8 @@ class Appium extends Webdriver {
|
|
|
689
713
|
* let settings = await I.grabSettings();
|
|
690
714
|
* ```
|
|
691
715
|
*
|
|
716
|
+
* @return {Promise<string>}
|
|
717
|
+
*
|
|
692
718
|
* Appium: support Android and iOS
|
|
693
719
|
*/
|
|
694
720
|
async grabSettings() {
|
|
@@ -720,6 +746,8 @@ class Appium extends Webdriver {
|
|
|
720
746
|
* I.switchToWeb('WEBVIEW_io.selendroid.testapp');
|
|
721
747
|
* ```
|
|
722
748
|
*
|
|
749
|
+
* @return {Promise<void>}
|
|
750
|
+
*
|
|
723
751
|
* @param {string} [context]
|
|
724
752
|
*/
|
|
725
753
|
async switchToWeb(context) {
|
|
@@ -747,6 +775,7 @@ class Appium extends Webdriver {
|
|
|
747
775
|
* I.switchToNative('SOME_OTHER_CONTEXT');
|
|
748
776
|
* ```
|
|
749
777
|
* @param {*} context
|
|
778
|
+
* @return {Promise<void>}
|
|
750
779
|
*/
|
|
751
780
|
async switchToNative(context = null) {
|
|
752
781
|
this.isWeb = false;
|
|
@@ -763,6 +792,8 @@ class Appium extends Webdriver {
|
|
|
763
792
|
* I.startActivity('io.selendroid.testapp', '.RegisterUserActivity');
|
|
764
793
|
* ```
|
|
765
794
|
*
|
|
795
|
+
* @return {Promise<void>}
|
|
796
|
+
*
|
|
766
797
|
* Appium: support only Android
|
|
767
798
|
*/
|
|
768
799
|
async startActivity(appPackage, appActivity) {
|
|
@@ -786,6 +817,8 @@ class Appium extends Webdriver {
|
|
|
786
817
|
* ```
|
|
787
818
|
* See corresponding [webdriverio reference](http://webdriver.io/api/mobile/setNetworkConnection.html).
|
|
788
819
|
*
|
|
820
|
+
* @return {Promise<{}>}
|
|
821
|
+
*
|
|
789
822
|
* Appium: support only Android
|
|
790
823
|
*/
|
|
791
824
|
async setNetworkConnection(value) {
|
|
@@ -801,6 +834,7 @@ class Appium extends Webdriver {
|
|
|
801
834
|
* ```
|
|
802
835
|
*
|
|
803
836
|
* @param {object} settings object
|
|
837
|
+
* @return {Promise<any>}
|
|
804
838
|
*
|
|
805
839
|
* Appium: support Android and iOS
|
|
806
840
|
*/
|
|
@@ -841,6 +875,7 @@ class Appium extends Webdriver {
|
|
|
841
875
|
* ```
|
|
842
876
|
*
|
|
843
877
|
* @param {number} keyValue Device specific key value
|
|
878
|
+
* @return {Promise<void>}
|
|
844
879
|
*
|
|
845
880
|
* Appium: support only Android
|
|
846
881
|
*/
|
|
@@ -859,6 +894,8 @@ class Appium extends Webdriver {
|
|
|
859
894
|
* I.openNotifications();
|
|
860
895
|
* ```
|
|
861
896
|
*
|
|
897
|
+
* @return {Promise<void>}
|
|
898
|
+
*
|
|
862
899
|
* Appium: support only Android
|
|
863
900
|
*/
|
|
864
901
|
async openNotifications() {
|
|
@@ -877,6 +914,8 @@ class Appium extends Webdriver {
|
|
|
877
914
|
* I.makeTouchAction("~buttonStartWebviewCD", 'tap');
|
|
878
915
|
* ```
|
|
879
916
|
*
|
|
917
|
+
* @return {Promise<void>}
|
|
918
|
+
*
|
|
880
919
|
* Appium: support Android and iOS
|
|
881
920
|
*/
|
|
882
921
|
async makeTouchAction(locator, action) {
|
|
@@ -898,6 +937,8 @@ class Appium extends Webdriver {
|
|
|
898
937
|
*
|
|
899
938
|
* Shortcut for `makeTouchAction`
|
|
900
939
|
*
|
|
940
|
+
* @return {Promise<void>}
|
|
941
|
+
*
|
|
901
942
|
* @param {*} locator
|
|
902
943
|
*/
|
|
903
944
|
async tap(locator) {
|
|
@@ -918,6 +959,7 @@ class Appium extends Webdriver {
|
|
|
918
959
|
* @param {number} xoffset
|
|
919
960
|
* @param {number} yoffset
|
|
920
961
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
962
|
+
* @return {Promise<void>}
|
|
921
963
|
*
|
|
922
964
|
* Appium: support Android and iOS
|
|
923
965
|
*/
|
|
@@ -971,6 +1013,7 @@ class Appium extends Webdriver {
|
|
|
971
1013
|
* @param {CodeceptJS.LocatorOrString} locator
|
|
972
1014
|
* @param {number} [yoffset] (optional)
|
|
973
1015
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
1016
|
+
* @return {Promise<void>}
|
|
974
1017
|
*
|
|
975
1018
|
* Appium: support Android and iOS
|
|
976
1019
|
*/
|
|
@@ -999,6 +1042,7 @@ class Appium extends Webdriver {
|
|
|
999
1042
|
* @param {CodeceptJS.LocatorOrString} locator
|
|
1000
1043
|
* @param {number} [xoffset] (optional)
|
|
1001
1044
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
1045
|
+
* @return {Promise<void>}
|
|
1002
1046
|
*
|
|
1003
1047
|
* Appium: support Android and iOS
|
|
1004
1048
|
*/
|
|
@@ -1025,6 +1069,7 @@ class Appium extends Webdriver {
|
|
|
1025
1069
|
* @param {CodeceptJS.LocatorOrString} locator
|
|
1026
1070
|
* @param {number} [xoffset] (optional)
|
|
1027
1071
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
1072
|
+
* @return {Promise<void>}
|
|
1028
1073
|
*
|
|
1029
1074
|
* Appium: support Android and iOS
|
|
1030
1075
|
*/
|
|
@@ -1051,6 +1096,7 @@ class Appium extends Webdriver {
|
|
|
1051
1096
|
* @param {CodeceptJS.LocatorOrString} locator
|
|
1052
1097
|
* @param {number} [yoffset] (optional)
|
|
1053
1098
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
1099
|
+
* @return {Promise<void>}
|
|
1054
1100
|
*
|
|
1055
1101
|
* Appium: support Android and iOS
|
|
1056
1102
|
*/
|
|
@@ -1084,6 +1130,7 @@ class Appium extends Webdriver {
|
|
|
1084
1130
|
* @param {number} timeout
|
|
1085
1131
|
* @param {number} offset
|
|
1086
1132
|
* @param {number} speed
|
|
1133
|
+
* @return {Promise<void>}
|
|
1087
1134
|
*
|
|
1088
1135
|
* Appium: support Android and iOS
|
|
1089
1136
|
*/
|
|
@@ -1181,6 +1228,10 @@ class Appium extends Webdriver {
|
|
|
1181
1228
|
* I.pullFile('/storage/emulated/0/DCIM/logo.png', output_dir);
|
|
1182
1229
|
* ```
|
|
1183
1230
|
*
|
|
1231
|
+
* @param {string} path
|
|
1232
|
+
* @param {string} dest
|
|
1233
|
+
* @return {Promise<string>}
|
|
1234
|
+
*
|
|
1184
1235
|
* Appium: support Android and iOS
|
|
1185
1236
|
*/
|
|
1186
1237
|
async pullFile(path, dest) {
|
|
@@ -1200,6 +1251,8 @@ class Appium extends Webdriver {
|
|
|
1200
1251
|
* I.shakeDevice();
|
|
1201
1252
|
* ```
|
|
1202
1253
|
*
|
|
1254
|
+
* @return {Promise<void>}
|
|
1255
|
+
*
|
|
1203
1256
|
* Appium: support only iOS
|
|
1204
1257
|
*/
|
|
1205
1258
|
async shakeDevice() {
|
|
@@ -1216,6 +1269,8 @@ class Appium extends Webdriver {
|
|
|
1216
1269
|
*
|
|
1217
1270
|
* See corresponding [webdriverio reference](http://webdriver.io/api/mobile/rotate.html).
|
|
1218
1271
|
*
|
|
1272
|
+
* @return {Promise<void>}
|
|
1273
|
+
*
|
|
1219
1274
|
* Appium: support only iOS
|
|
1220
1275
|
*/
|
|
1221
1276
|
async rotate(x, y, duration, radius, rotation, touchCount) {
|
|
@@ -1228,6 +1283,8 @@ class Appium extends Webdriver {
|
|
|
1228
1283
|
*
|
|
1229
1284
|
* See corresponding [webdriverio reference](http://webdriver.io/api/mobile/setImmediateValue.html).
|
|
1230
1285
|
*
|
|
1286
|
+
* @return {Promise<void>}
|
|
1287
|
+
*
|
|
1231
1288
|
* Appium: support only iOS
|
|
1232
1289
|
*/
|
|
1233
1290
|
async setImmediateValue(id, value) {
|
|
@@ -1244,6 +1301,8 @@ class Appium extends Webdriver {
|
|
|
1244
1301
|
* I.touchId(false); // simulates invalid fingerprint
|
|
1245
1302
|
* ```
|
|
1246
1303
|
*
|
|
1304
|
+
* @return {Promise<void>}
|
|
1305
|
+
*
|
|
1247
1306
|
* Appium: support only iOS
|
|
1248
1307
|
* TODO: not tested
|
|
1249
1308
|
*/
|
|
@@ -1260,6 +1319,8 @@ class Appium extends Webdriver {
|
|
|
1260
1319
|
* I.closeApp();
|
|
1261
1320
|
* ```
|
|
1262
1321
|
*
|
|
1322
|
+
* @return {Promise<void>}
|
|
1323
|
+
*
|
|
1263
1324
|
* Appium: support only iOS
|
|
1264
1325
|
*/
|
|
1265
1326
|
async closeApp() {
|
|
@@ -1410,6 +1471,7 @@ class Appium extends Webdriver {
|
|
|
1410
1471
|
* ```
|
|
1411
1472
|
*
|
|
1412
1473
|
* @param {string} fileName file name to save.
|
|
1474
|
+
* @return {Promise<void>}
|
|
1413
1475
|
*/
|
|
1414
1476
|
async saveScreenshot(fileName) {
|
|
1415
1477
|
return super.saveScreenshot(fileName, false);
|
package/lib/helper/FileSystem.js
CHANGED
|
@@ -15,7 +15,17 @@ const { fileEquals } = require('../assert/equal');
|
|
|
15
15
|
* I.amInPath('test');
|
|
16
16
|
* I.seeFile('codecept.json');
|
|
17
17
|
* I.seeInThisFile('FileSystem');
|
|
18
|
-
* I.dontSeeInThisFile("
|
|
18
|
+
* I.dontSeeInThisFile("WebDriver");
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* ## Configuration
|
|
22
|
+
*
|
|
23
|
+
* Enable helper in config file:
|
|
24
|
+
*
|
|
25
|
+
* ```js
|
|
26
|
+
* helpers: {
|
|
27
|
+
* FileSystem: {},
|
|
28
|
+
* }
|
|
19
29
|
* ```
|
|
20
30
|
*
|
|
21
31
|
* ## Methods
|
|
@@ -91,6 +101,7 @@ class FileSystem extends Helper {
|
|
|
91
101
|
* I.amInPath('output/downloads');
|
|
92
102
|
* I.seeFileNameMatching('.pdf');
|
|
93
103
|
* ```
|
|
104
|
+
* @param {string} text
|
|
94
105
|
*/
|
|
95
106
|
seeFileNameMatching(text) {
|
|
96
107
|
assert.ok(
|
package/lib/helper/Playwright.js
CHANGED
|
@@ -14,7 +14,6 @@ const {
|
|
|
14
14
|
ucfirst,
|
|
15
15
|
fileExists,
|
|
16
16
|
chunkArray,
|
|
17
|
-
toCamelCase,
|
|
18
17
|
convertCssPropertiesToCamelCase,
|
|
19
18
|
screenshotOutputFolder,
|
|
20
19
|
getNormalizedKeyAttributeValue,
|
|
@@ -73,16 +72,18 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
73
72
|
* * `keepBrowserState`: (optional, default: false) - keep browser state between tests when `restart` is set to false.
|
|
74
73
|
* * `keepCookies`: (optional, default: false) - keep cookies between tests when `restart` is set to false.
|
|
75
74
|
* * `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
|
|
76
|
-
* * `waitForNavigation`: (optional, default: 'load'). When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle`. Choose one of those options is possible. See [Playwright API](https://github.com/microsoft/playwright/blob/
|
|
75
|
+
* * `waitForNavigation`: (optional, default: 'load'). When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle`. Choose one of those options is possible. See [Playwright API](https://github.com/microsoft/playwright/blob/main/docs/api.md#pagewaitfornavigationoptions).
|
|
77
76
|
* * `pressKeyDelay`: (optional, default: '10'). Delay between key presses in ms. Used when calling Playwrights page.type(...) in fillField/appendField
|
|
78
77
|
* * `getPageTimeout` (optional, default: '0') config option to set maximum navigation time in milliseconds.
|
|
79
78
|
* * `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000.
|
|
80
79
|
* * `basicAuth`: (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
|
|
81
80
|
* * `windowSize`: (optional) default window size. Set a dimension like `640x480`.
|
|
82
81
|
* * `userAgent`: (optional) user-agent string.
|
|
82
|
+
* * `locale`: (optional) locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ...
|
|
83
83
|
* * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
|
|
84
84
|
* * `chromium`: (optional) pass additional chromium options
|
|
85
85
|
* * `electron`: (optional) pass additional electron options
|
|
86
|
+
* * `channel`: (optional) While Playwright can operate against the stock Google Chrome and Microsoft Edge browsers available on the machine. In particular, current Playwright version will support Stable and Beta channels of these browsers. See [Google Chrome & Microsoft Edge](https://playwright.dev/docs/browsers/#google-chrome--microsoft-edge).
|
|
86
87
|
*
|
|
87
88
|
* #### Video Recording Customization
|
|
88
89
|
*
|
|
@@ -197,6 +198,19 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
197
198
|
* }
|
|
198
199
|
* ```
|
|
199
200
|
*
|
|
201
|
+
* #### Example #7: Launch test with a specifc user locale
|
|
202
|
+
*
|
|
203
|
+
* ```js
|
|
204
|
+
* {
|
|
205
|
+
* helpers: {
|
|
206
|
+
* Playwright : {
|
|
207
|
+
* url: "http://localhost",
|
|
208
|
+
* locale: "fr-FR",
|
|
209
|
+
* }
|
|
210
|
+
* }
|
|
211
|
+
* }
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
200
214
|
* Note: When connecting to remote browser `show` and specific `chrome` options (e.g. `headless` or `devtools`) are ignored.
|
|
201
215
|
*
|
|
202
216
|
* ## Access From Helpers
|
|
@@ -287,6 +301,11 @@ class Playwright extends Helper {
|
|
|
287
301
|
headless: !this.options.show,
|
|
288
302
|
...this._getOptionsForBrowser(config),
|
|
289
303
|
};
|
|
304
|
+
|
|
305
|
+
if (this.options.channel && this.options.browser === 'chromium') {
|
|
306
|
+
this.playwrightOptions.channel = this.options.channel;
|
|
307
|
+
}
|
|
308
|
+
|
|
290
309
|
if (this.options.video) {
|
|
291
310
|
this.options.recordVideo = { size: parseWindowSize(this.options.windowSize) };
|
|
292
311
|
}
|
|
@@ -351,6 +370,7 @@ class Playwright extends Helper {
|
|
|
351
370
|
return err.message.includes('context');
|
|
352
371
|
},
|
|
353
372
|
});
|
|
373
|
+
|
|
354
374
|
if (this.options.restart && !this.options.manualStart) await this._startBrowser();
|
|
355
375
|
if (!this.isRunning && !this.options.manualStart) await this._startBrowser();
|
|
356
376
|
|
|
@@ -371,6 +391,8 @@ class Playwright extends Helper {
|
|
|
371
391
|
}
|
|
372
392
|
if (this.options.recordVideo) contextOptions.recordVideo = this.options.recordVideo;
|
|
373
393
|
if (this.storageState) contextOptions.storageState = this.storageState;
|
|
394
|
+
if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent;
|
|
395
|
+
if (this.options.locale) contextOptions.locale = this.options.locale;
|
|
374
396
|
this.browserContext = await this.browser.newContext(contextOptions); // Adding the HTTPSError ignore in the context so that we can ignore those errors
|
|
375
397
|
}
|
|
376
398
|
|
|
@@ -484,10 +506,10 @@ class Playwright extends Helper {
|
|
|
484
506
|
* First argument is a description of an action.
|
|
485
507
|
* Second argument is async function that gets this helper as parameter.
|
|
486
508
|
*
|
|
487
|
-
* { [`page`](https://github.com/microsoft/playwright/blob/
|
|
509
|
+
* { [`page`](https://github.com/microsoft/playwright/blob/main/docs/src/api/class-page.md), [`context`](https://github.com/microsoft/playwright/blob/main/docs/src/api/class-browsercontext.md) [`browser`](https://github.com/microsoft/playwright/blob/main/docs/src/api/class-browser.md) } objects from Playwright API are available.
|
|
488
510
|
*
|
|
489
511
|
* ```js
|
|
490
|
-
* I.usePlaywrightTo('emulate offline mode', async ({ context }) {
|
|
512
|
+
* I.usePlaywrightTo('emulate offline mode', async ({ context }) => {
|
|
491
513
|
* await context.setOffline(true);
|
|
492
514
|
* });
|
|
493
515
|
* ```
|
|
@@ -562,6 +584,11 @@ class Playwright extends Helper {
|
|
|
562
584
|
this.page = page;
|
|
563
585
|
if (!page) return;
|
|
564
586
|
page.setDefaultNavigationTimeout(this.options.getPageTimeout);
|
|
587
|
+
|
|
588
|
+
page.on('crash', async () => {
|
|
589
|
+
console.log('ERROR: Page has crashed, closing page!');
|
|
590
|
+
await page.close();
|
|
591
|
+
});
|
|
565
592
|
this.context = await this.page;
|
|
566
593
|
this.contextLocator = null;
|
|
567
594
|
if (this.options.browser === 'chrome') {
|
|
@@ -1049,7 +1076,7 @@ class Playwright extends Helper {
|
|
|
1049
1076
|
* I.openNewTab();
|
|
1050
1077
|
* ```
|
|
1051
1078
|
*
|
|
1052
|
-
* You can pass in [page options](https://github.com/microsoft/playwright/blob/
|
|
1079
|
+
* You can pass in [page options](https://github.com/microsoft/playwright/blob/main/docs/api.md#browsernewpageoptions) to emulate device on this page
|
|
1053
1080
|
*
|
|
1054
1081
|
* ```js
|
|
1055
1082
|
* // enable mobile
|
|
@@ -1558,7 +1585,7 @@ class Playwright extends Helper {
|
|
|
1558
1585
|
*/
|
|
1559
1586
|
async clearCookie() {
|
|
1560
1587
|
// Playwright currently doesn't support to delete a certain cookie
|
|
1561
|
-
// https://github.com/microsoft/playwright/blob/
|
|
1588
|
+
// https://github.com/microsoft/playwright/blob/main/docs/api.md#class-browsercontext
|
|
1562
1589
|
if (!this.browserContext) return;
|
|
1563
1590
|
return this.browserContext.clearCookies();
|
|
1564
1591
|
}
|
|
@@ -1866,7 +1893,7 @@ class Playwright extends Helper {
|
|
|
1866
1893
|
}
|
|
1867
1894
|
|
|
1868
1895
|
if (this.options.trace) {
|
|
1869
|
-
const path = `${global.output_dir}/trace/${clearString(test.title)
|
|
1896
|
+
const path = `${`${global.output_dir}/trace/${clearString(test.title)}`.slice(0, 251)}.zip`;
|
|
1870
1897
|
await this.browserContext.tracing.stop({ path });
|
|
1871
1898
|
test.artifacts.trace = path;
|
|
1872
1899
|
}
|
|
@@ -2146,11 +2173,11 @@ class Playwright extends Helper {
|
|
|
2146
2173
|
}
|
|
2147
2174
|
|
|
2148
2175
|
/**
|
|
2149
|
-
* Waits for a network
|
|
2176
|
+
* Waits for a network response.
|
|
2150
2177
|
*
|
|
2151
2178
|
* ```js
|
|
2152
2179
|
* I.waitForResponse('http://example.com/resource');
|
|
2153
|
-
* I.waitForResponse(
|
|
2180
|
+
* I.waitForResponse(response => response.url() === 'https://example.com' && response.status() === 200);
|
|
2154
2181
|
* ```
|
|
2155
2182
|
*
|
|
2156
2183
|
* @param {string|function} urlOrPredicate
|
|
@@ -2236,16 +2263,6 @@ class Playwright extends Helper {
|
|
|
2236
2263
|
return this.page.waitForNavigation(opts);
|
|
2237
2264
|
}
|
|
2238
2265
|
|
|
2239
|
-
/**
|
|
2240
|
-
* {{> waitUntil }}
|
|
2241
|
-
*/
|
|
2242
|
-
async waitUntil(fn, sec = null) {
|
|
2243
|
-
console.log('This method will remove in CodeceptJS 1.4; use `waitForFunction` instead!');
|
|
2244
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
2245
|
-
const context = await this._getContext();
|
|
2246
|
-
return context.waitForFunction(fn, { timeout: waitTimeout });
|
|
2247
|
-
}
|
|
2248
|
-
|
|
2249
2266
|
async waitUntilExists(locator, sec) {
|
|
2250
2267
|
console.log(`waitUntilExists deprecated:
|
|
2251
2268
|
* use 'waitForElement' to wait for element to be attached
|
|
@@ -2662,13 +2679,10 @@ async function targetCreatedHandler(page) {
|
|
|
2662
2679
|
});
|
|
2663
2680
|
});
|
|
2664
2681
|
page.on('console', (msg) => {
|
|
2665
|
-
this.debugSection(`Browser:${ucfirst(msg.type())}`, (msg._text || '') + msg.args().join(' '));
|
|
2682
|
+
this.debugSection(`Browser:${ucfirst(msg.type())}`, (msg.text && msg.text() || msg._text || '') + msg.args().join(' '));
|
|
2666
2683
|
consoleLogStore.add(msg);
|
|
2667
2684
|
});
|
|
2668
2685
|
|
|
2669
|
-
if (this.options.userAgent) {
|
|
2670
|
-
await page.setUserAgent(this.options.userAgent);
|
|
2671
|
-
}
|
|
2672
2686
|
if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0 && this._getType() === 'Browser') {
|
|
2673
2687
|
await page.setViewportSize(parseWindowSize(this.options.windowSize));
|
|
2674
2688
|
}
|
package/lib/helper/Protractor.js
CHANGED
|
@@ -838,11 +838,7 @@ class Protractor extends Helper {
|
|
|
838
838
|
}
|
|
839
839
|
|
|
840
840
|
/**
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
* ```js
|
|
844
|
-
* I.seeTitleEquals('Test title.');
|
|
845
|
-
* ```
|
|
841
|
+
* {{> seeTitleEquals }}
|
|
846
842
|
*/
|
|
847
843
|
async seeTitleEquals(text) {
|
|
848
844
|
const title = await this.browser.getTitle();
|
|
@@ -1018,7 +1014,7 @@ class Protractor extends Helper {
|
|
|
1018
1014
|
}
|
|
1019
1015
|
|
|
1020
1016
|
/**
|
|
1021
|
-
|
|
1017
|
+
* {{> seeInCurrentUrl }}
|
|
1022
1018
|
*/
|
|
1023
1019
|
async seeInCurrentUrl(url) {
|
|
1024
1020
|
return this.browser.getCurrentUrl().then(currentUrl => stringIncludes('url').assert(url, currentUrl));
|
|
@@ -1498,14 +1494,6 @@ class Protractor extends Helper {
|
|
|
1498
1494
|
return this.browser.wait(() => this.browser.executeScript.call(this.browser, fn, ...args), aSec * 1000);
|
|
1499
1495
|
}
|
|
1500
1496
|
|
|
1501
|
-
/**
|
|
1502
|
-
* {{> waitUntil }}
|
|
1503
|
-
*/
|
|
1504
|
-
async waitUntil(fn, sec = null, timeoutMsg = null) {
|
|
1505
|
-
const aSec = sec || this.options.waitForTimeout;
|
|
1506
|
-
return this.browser.wait(fn, aSec * 1000, timeoutMsg);
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
1497
|
/**
|
|
1510
1498
|
* {{> waitInUrl }}
|
|
1511
1499
|
*/
|