1
1
<?php
2
2
3
+ //phpcs:disable Generic.Files.LineLength.TooLong
3
4
declare (strict_types=1 );
4
5
5
6
namespace Codeception \Module ;
65
66
*
66
67
* * Java is required
67
68
* * NodeJS is required
68
- *
69
+ *
69
70
* The fastest way to get started is to [Install and launch Selenium using selenium-standalone NodeJS package](https://www.npmjs.com/package/selenium-standalone).
70
- *
71
+ *
71
72
* Launch selenium standalone in separate console window:
72
- *
73
+ *
73
74
* ```
74
75
* selenium-standalone start
75
76
* ```
83
84
* url: 'http://localhost/'
84
85
* browser: chrome # 'chrome' or 'firefox'
85
86
* ```
86
- *
87
+ *
87
88
* ## Headless Chrome Browser
88
- *
89
+ *
89
90
* To enable headless mode (launch tests without showing a window) for Chrome browser using Selenium use this config in `acceptance.suite.yml`:
90
- *
91
+ *
91
92
* ```yaml
92
93
* modules:
93
94
* enabled:
98
99
* chromeOptions:
99
100
* args: ["--headless", "--disable-gpu"]
100
101
* ```
101
- *
102
+ *
102
103
* ## Headless Selenium in Docker
103
104
*
104
105
* Docker can ship Selenium Server with all its dependencies and browsers inside a single container.
113
114
* ## Local Chrome and/or Firefox
114
115
*
115
116
* Tests can be executed directly through ChromeDriver or GeckoDriver (for Firefox). Consider using this option if you don't plan to use Selenium.
116
- *
117
+ *
117
118
* ### ChromeDriver
118
- *
119
+ *
119
120
* * Download and install [ChromeDriver](https://sites.google.com/chromium.org/driver/downloads?authuser=0)
120
121
* * Launch ChromeDriver in a separate console window: `chromedriver --url-base=/wd/hub`.
121
- *
122
+ *
122
123
* Configuration in `acceptance.suite.yml`:
123
124
*
124
125
* ```yaml
139
140
*
140
141
*
141
142
* ### GeckoDriver
142
- *
143
+ *
143
144
* * [GeckoDriver](https://github.com/mozilla/geckodriver/releases) must be installed
144
145
* * Start GeckoDriver in a separate console window: `geckodriver`.
145
- *
146
+ *
146
147
* Configuration in `acceptance.suite.yml`:
147
148
*
148
149
* ```yaml
160
161
* intl.accept_languages: "de-AT" # Set HTTP-Header `Accept-Language: de-AT` for requests
161
162
* ```
162
163
* See here for [Firefox capabilities](https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities#List_of_capabilities)
163
- *
164
+ *
164
165
* ## Cloud Testing
165
166
*
166
167
* Cloud Testing services can run your WebDriver tests in the cloud.
@@ -460,15 +461,24 @@ public function _requires(): array
460
461
protected function getBaseElement (): WebDriverSearchContext
461
462
{
462
463
if (!$ this ->baseElement ) {
463
- throw new ModuleException ($ this , "Page not loaded. Use ` \$I->amOnPage` (or hidden API methods `_request` and `_loadPage`) to open it " );
464
+ throw new ModuleException (
465
+ $ this ,
466
+ "Page not loaded. Use ` \$I->amOnPage` (or hidden API methods `_request` and `_loadPage`) to open it "
467
+ );
464
468
}
465
469
466
470
return $ this ->baseElement ;
467
471
}
468
472
469
473
public function _initialize ()
470
474
{
471
- $ this ->wdHost = sprintf ('%s://%s:%s%s ' , $ this ->config ['protocol ' ], $ this ->config ['host ' ], $ this ->config ['port ' ], $ this ->config ['path ' ]);
475
+ $ this ->wdHost = sprintf (
476
+ '%s://%s:%s%s ' ,
477
+ $ this ->config ['protocol ' ],
478
+ $ this ->config ['host ' ],
479
+ $ this ->config ['port ' ],
480
+ $ this ->config ['path ' ]
481
+ );
472
482
$ this ->capabilities = $ this ->config ['capabilities ' ];
473
483
$ this ->capabilities [WebDriverCapabilityType::BROWSER_NAME ] = $ this ->config ['browser ' ];
474
484
if ($ proxy = $ this ->getProxy ()) {
@@ -674,7 +684,8 @@ public function debugWebDriverLogs(TestInterface $test = null): void
674
684
675
685
$ this ->debugSection ("Selenium {$ logType } Logs " , "\n" . $ this ->formatLogEntries ($ logEntries ));
676
686
677
- if ($ logType === 'browser ' && $ this ->config ['log_js_errors ' ]
687
+ if (
688
+ $ logType === 'browser ' && $ this ->config ['log_js_errors ' ]
678
689
&& ($ test instanceof ScenarioDriven)
679
690
) {
680
691
$ this ->logJSErrors ($ test , $ logEntries );
@@ -711,7 +722,8 @@ protected function formatLogEntries(array $logEntries): string
711
722
protected function logJSErrors (ScenarioDriven $ test , array $ browserLogEntries ): void
712
723
{
713
724
foreach ($ browserLogEntries as $ logEntry ) {
714
- if (isset ($ logEntry ['level ' ])
725
+ if (
726
+ isset ($ logEntry ['level ' ])
715
727
&& isset ($ logEntry ['message ' ])
716
728
&& $ this ->isJSError ($ logEntry ['level ' ], $ logEntry ['message ' ])
717
729
) {
@@ -1167,7 +1179,10 @@ public function click($link, $context = null): void
1167
1179
try {
1168
1180
$ els = $ this ->match ($ page , $ link );
1169
1181
} catch (MalformedLocatorException $ exception ) {
1170
- throw new ElementNotFound ("name= {$ link }" , "' {$ link }' is invalid CSS and XPath selector and Link or Button " );
1182
+ throw new ElementNotFound (
1183
+ "name= {$ link }" ,
1184
+ "' {$ link }' is invalid CSS and XPath selector and Link or Button "
1185
+ );
1171
1186
}
1172
1187
1173
1188
$ el = reset ($ els );
@@ -1237,7 +1252,6 @@ public function _findClickable(WebDriverSearchContext $page, $link): ?WebDriverE
1237
1252
".//input[./@type = 'submit' or ./@type = 'image' or ./@type = 'button'][./@name = {$ locator } or ./@title = {$ locator }] " ,
1238
1253
".//button[./@name = {$ locator } or ./@title = {$ locator }] "
1239
1254
);
1240
-
1241
1255
$ els = $ page ->findElements (WebDriverBy::xpath ($ xpath ));
1242
1256
if (count ($ els ) > 0 ) {
1243
1257
return reset ($ els );
@@ -1270,10 +1284,8 @@ protected function findFields($selector): array
1270
1284
$ locator = static ::xPathLiteral (trim ((string ) $ selector ));
1271
1285
// by text or label
1272
1286
$ xpath = Locator::combine (
1273
- // @codingStandardsIgnoreStart
1274
1287
".//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')][(((./@name = {$ locator }) or ./@id = //label[contains(normalize-space(string(.)), {$ locator })]/@for) or ./@placeholder = {$ locator })] " ,
1275
1288
".//label[contains(normalize-space(string(.)), {$ locator })]//.//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')] "
1276
- // @codingStandardsIgnoreEnd
1277
1289
);
1278
1290
$ fields = $ this ->getBaseElement ()->findElements (WebDriverBy::xpath ($ xpath ));
1279
1291
if (!empty ($ fields )) {
@@ -1321,7 +1333,10 @@ public function seeLink(string $text, string $url = null): void
1321
1333
$ nodes = $ this ->filterNodesByHref ($ url , $ nodes );
1322
1334
}
1323
1335
1324
- $ this ->assertNotEmpty ($ nodes , "No links containing text ' {$ text }' and URL ' {$ url }' were found in page {$ currentUri }" );
1336
+ $ this ->assertNotEmpty (
1337
+ $ nodes ,
1338
+ "No links containing text ' {$ text }' and URL ' {$ url }' were found in page {$ currentUri }"
1339
+ );
1325
1340
}
1326
1341
1327
1342
public function dontSeeLink (string $ text , string $ url = '' ): void
@@ -1332,7 +1347,10 @@ public function dontSeeLink(string $text, string $url = ''): void
1332
1347
$ this ->assertEmpty ($ nodes , "Link containing text ' {$ text }' was found in page {$ currentUri }" );
1333
1348
} else {
1334
1349
$ nodes = $ this ->filterNodesByHref ($ url , $ nodes );
1335
- $ this ->assertEmpty ($ nodes , "Link containing text ' {$ text }' and URL ' {$ url }' was found in page {$ currentUri }" );
1350
+ $ this ->assertEmpty (
1351
+ $ nodes ,
1352
+ "Link containing text ' {$ text }' and URL ' {$ url }' was found in page {$ currentUri }"
1353
+ );
1336
1354
}
1337
1355
}
1338
1356
@@ -1529,15 +1547,15 @@ protected function proceedSeeInField(array $elements, $value): array
1529
1547
1530
1548
break ;
1531
1549
case 'option ' :
1532
- // no break we need the trim text and the value also
1533
1550
if (!$ el ->isSelected ()) {
1534
1551
break ;
1535
1552
}
1536
1553
1537
1554
$ currentValues [] = $ el ->getText ();
1555
+ // no break we need the trim text and the value also
1538
1556
case 'textarea ' :
1539
- // we include trimmed and real value of textarea for check
1540
1557
$ currentValues [] = trim ($ el ->getText ());
1558
+ // we include trimmed and real value of textarea for check
1541
1559
default :
1542
1560
$ currentValues [] = $ el ->getAttribute ('value ' ); // raw value
1543
1561
break ;
@@ -1629,7 +1647,10 @@ public function selectOption($select, $option): void
1629
1647
return ;
1630
1648
}
1631
1649
1632
- throw new ElementNotFound (json_encode ($ option , JSON_THROW_ON_ERROR ), "Option inside {$ select } matched by name or value " );
1650
+ throw new ElementNotFound (
1651
+ json_encode ($ option , JSON_THROW_ON_ERROR ),
1652
+ "Option inside {$ select } matched by name or value "
1653
+ );
1633
1654
}
1634
1655
1635
1656
/**
@@ -1662,7 +1683,10 @@ public function _initializeSession(): void
1662
1683
$ this ->initialWindowSize ();
1663
1684
} catch (WebDriverCurlException $ exception ) {
1664
1685
codecept_debug ('Curl error: ' . $ exception ->getMessage ());
1665
- throw new ConnectionException ("Can't connect to WebDriver at {$ this ->wdHost }. Make sure that ChromeDriver, GeckoDriver or Selenium Server is running. " );
1686
+ throw new ConnectionException (
1687
+ "Can't connect to WebDriver at {$ this ->wdHost }.' "
1688
+ . ' Make sure that ChromeDriver, GeckoDriver or Selenium Server is running. '
1689
+ );
1666
1690
}
1667
1691
}
1668
1692
@@ -1765,8 +1789,11 @@ public function unselectOption($select, $option): void
1765
1789
/**
1766
1790
* @param string|array|WebDriverBy|WebDriverElement $radioOrCheckbox
1767
1791
*/
1768
- protected function findCheckable (WebDriverSearchContext $ context , $ radioOrCheckbox , bool $ byValue = false ): ?WebDriverElement
1769
- {
1792
+ protected function findCheckable (
1793
+ WebDriverSearchContext $ context ,
1794
+ $ radioOrCheckbox ,
1795
+ bool $ byValue = false
1796
+ ): ?WebDriverElement {
1770
1797
if ($ radioOrCheckbox instanceof WebDriverElement) {
1771
1798
return $ radioOrCheckbox ;
1772
1799
}
@@ -1786,23 +1813,22 @@ protected function findCheckable(WebDriverSearchContext $context, $radioOrCheckb
1786
1813
$ typeLiteral = static ::xPathLiteral ($ contextType );
1787
1814
$ inputLocatorFragment = "input[@type = {$ typeLiteral }][@name = {$ nameLiteral }] " ;
1788
1815
$ xpath = Locator::combine (
1789
- // @codingStandardsIgnoreStart
1790
1816
"ancestor::form// {$ inputLocatorFragment }[(@id = ancestor::form//label[contains(normalize-space(string(.)), {$ locator })]/@for) or @placeholder = {$ locator }] " ,
1791
- // @codingStandardsIgnoreEnd
1792
1817
"ancestor::form//label[contains(normalize-space(string(.)), {$ locator })]// {$ inputLocatorFragment }"
1793
1818
);
1794
1819
if ($ byValue ) {
1795
1820
$ xpath = Locator::combine ($ xpath , "ancestor::form// {$ inputLocatorFragment }[@value = {$ locator }] " );
1796
1821
}
1797
1822
} else {
1798
1823
$ xpath = Locator::combine (
1799
- // @codingStandardsIgnoreStart
1800
1824
"//input[@type = 'checkbox' or @type = 'radio'][(@id = //label[contains(normalize-space(string(.)), {$ locator })]/@for) or @placeholder = {$ locator } or @name = {$ locator }] " ,
1801
- // @codingStandardsIgnoreEnd
1802
1825
"//label[contains(normalize-space(string(.)), {$ locator })]//input[@type = 'radio' or @type = 'checkbox'] "
1803
1826
);
1804
1827
if ($ byValue ) {
1805
- $ xpath = Locator::combine ($ xpath , sprintf ("//input[@type = 'checkbox' or @type = 'radio'][@value = %s] " , $ locator ));
1828
+ $ xpath = Locator::combine (
1829
+ $ xpath ,
1830
+ sprintf ("//input[@type = 'checkbox' or @type = 'radio'][@value = %s] " , $ locator )
1831
+ );
1806
1832
}
1807
1833
}
1808
1834
@@ -2446,7 +2472,9 @@ public function submitForm($selector, array $params, $button = null): void
2446
2472
$ form = $ this ->matchFirstOrFail ($ this ->getBaseElement (), $ selector );
2447
2473
2448
2474
$ fields = $ form ->findElements (
2449
- WebDriverBy::cssSelector ('input:enabled[name],textarea:enabled[name],select:enabled[name],input[type=hidden][name] ' )
2475
+ WebDriverBy::cssSelector (
2476
+ 'input:enabled[name],textarea:enabled[name],select:enabled[name],input[type=hidden][name] '
2477
+ )
2450
2478
);
2451
2479
foreach ($ fields as $ field ) {
2452
2480
$ fieldName = $ this ->getSubmissionFormFieldName ($ field ->getAttribute ('name ' ) ?? '' );
@@ -3278,7 +3306,10 @@ public function appendField($field, string $value): void
3278
3306
return ;
3279
3307
}
3280
3308
3281
- throw new ElementNotFound (json_encode ($ value , JSON_THROW_ON_ERROR ), "Option inside {$ field } matched by name or value " );
3309
+ throw new ElementNotFound (
3310
+ json_encode ($ value , JSON_THROW_ON_ERROR ),
3311
+ "Option inside {$ field } matched by name or value "
3312
+ );
3282
3313
case "textarea " :
3283
3314
$ el ->sendKeys ($ value );
3284
3315
return ;
@@ -3491,7 +3522,7 @@ public function openNewTab(): void
3491
3522
public function seeNumberOfTabs ($ number ): void
3492
3523
{
3493
3524
$ this ->assertSame (count ($ this ->webDriver ->getWindowHandles ()), $ number );
3494
- }
3525
+ }
3495
3526
3496
3527
/**
3497
3528
* Closes current browser tab and switches to previous active tab.
@@ -3697,5 +3728,4 @@ private static function xPathLiteral($s): string
3697
3728
3698
3729
return sprintf ('concat(%s) ' , implode (', ' , $ parts ));
3699
3730
}
3700
-
3701
3731
}
0 commit comments