WebDriverExpectedCondition.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. <?php
  2. // Copyright 2004-present Facebook. All Rights Reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. namespace Facebook\WebDriver;
  16. use Facebook\WebDriver\Exception\NoAlertOpenException;
  17. use Facebook\WebDriver\Exception\NoSuchElementException;
  18. use Facebook\WebDriver\Exception\NoSuchFrameException;
  19. use Facebook\WebDriver\Exception\StaleElementReferenceException;
  20. /**
  21. * Canned ExpectedConditions which are generally useful within webdriver tests.
  22. *
  23. * @see WebDriverWait
  24. */
  25. class WebDriverExpectedCondition
  26. {
  27. /**
  28. * A callable function to be executed by WebDriverWait. It should return
  29. * a truthy value, mostly boolean or a WebDriverElement, on success.
  30. * @var callable
  31. */
  32. private $apply;
  33. /**
  34. * @return callable A callable function to be executed by WebDriverWait
  35. */
  36. public function getApply()
  37. {
  38. return $this->apply;
  39. }
  40. protected function __construct(callable $apply)
  41. {
  42. $this->apply = $apply;
  43. }
  44. /**
  45. * An expectation for checking the title of a page.
  46. *
  47. * @param string $title The expected title, which must be an exact match.
  48. * @return WebDriverExpectedCondition<bool> Condition returns whether current page title equals given string.
  49. */
  50. public static function titleIs($title)
  51. {
  52. return new static(
  53. function (WebDriver $driver) use ($title) {
  54. return $title === $driver->getTitle();
  55. }
  56. );
  57. }
  58. /**
  59. * An expectation for checking substring of a page Title.
  60. *
  61. * @param string $title The expected substring of Title.
  62. * @return WebDriverExpectedCondition<bool> Condition returns whether current page title contains given string.
  63. */
  64. public static function titleContains($title)
  65. {
  66. return new static(
  67. function (WebDriver $driver) use ($title) {
  68. return strpos($driver->getTitle(), $title) !== false;
  69. }
  70. );
  71. }
  72. /**
  73. * An expectation for checking current page title matches the given regular expression.
  74. *
  75. * @param string $titleRegexp The regular expression to test against.
  76. * @return WebDriverExpectedCondition<bool> Condition returns whether current page title matches the regular
  77. * expression.
  78. */
  79. public static function titleMatches($titleRegexp)
  80. {
  81. return new static(
  82. function (WebDriver $driver) use ($titleRegexp) {
  83. return (bool) preg_match($titleRegexp, $driver->getTitle());
  84. }
  85. );
  86. }
  87. /**
  88. * An expectation for checking the URL of a page.
  89. *
  90. * @param string $url The expected URL, which must be an exact match.
  91. * @return WebDriverExpectedCondition<bool> Condition returns whether current URL equals given one.
  92. */
  93. public static function urlIs($url)
  94. {
  95. return new static(
  96. function (WebDriver $driver) use ($url) {
  97. return $url === $driver->getCurrentURL();
  98. }
  99. );
  100. }
  101. /**
  102. * An expectation for checking substring of the URL of a page.
  103. *
  104. * @param string $url The expected substring of the URL
  105. * @return WebDriverExpectedCondition<bool> Condition returns whether current URL contains given string.
  106. */
  107. public static function urlContains($url)
  108. {
  109. return new static(
  110. function (WebDriver $driver) use ($url) {
  111. return strpos($driver->getCurrentURL(), $url) !== false;
  112. }
  113. );
  114. }
  115. /**
  116. * An expectation for checking current page URL matches the given regular expression.
  117. *
  118. * @param string $urlRegexp The regular expression to test against.
  119. * @return WebDriverExpectedCondition<bool> Condition returns whether current URL matches the regular expression.
  120. */
  121. public static function urlMatches($urlRegexp)
  122. {
  123. return new static(
  124. function (WebDriver $driver) use ($urlRegexp) {
  125. return (bool) preg_match($urlRegexp, $driver->getCurrentURL());
  126. }
  127. );
  128. }
  129. /**
  130. * An expectation for checking that an element is present on the DOM of a page.
  131. * This does not necessarily mean that the element is visible.
  132. *
  133. * @param WebDriverBy $by The locator used to find the element.
  134. * @return WebDriverExpectedCondition<WebDriverElement> Condition returns the element which is located.
  135. */
  136. public static function presenceOfElementLocated(WebDriverBy $by)
  137. {
  138. return new static(
  139. function (WebDriver $driver) use ($by) {
  140. return $driver->findElement($by);
  141. }
  142. );
  143. }
  144. /**
  145. * An expectation for checking that there is at least one element present on a web page.
  146. *
  147. * @param WebDriverBy $by The locator used to find the element.
  148. * @return WebDriverExpectedCondition<array> Condition returns an array of WebDriverElements once they are located.
  149. */
  150. public static function presenceOfAllElementsLocatedBy(WebDriverBy $by)
  151. {
  152. return new static(
  153. function (WebDriver $driver) use ($by) {
  154. $elements = $driver->findElements($by);
  155. return count($elements) > 0 ? $elements : null;
  156. }
  157. );
  158. }
  159. /**
  160. * An expectation for checking that an element is present on the DOM of a page and visible.
  161. * Visibility means that the element is not only displayed but also has a height and width that is greater than 0.
  162. *
  163. * @param WebDriverBy $by The locator used to find the element.
  164. * @return WebDriverExpectedCondition<WebDriverElement> Condition returns the element which is located and visible.
  165. */
  166. public static function visibilityOfElementLocated(WebDriverBy $by)
  167. {
  168. return new static(
  169. function (WebDriver $driver) use ($by) {
  170. try {
  171. $element = $driver->findElement($by);
  172. return $element->isDisplayed() ? $element : null;
  173. } catch (StaleElementReferenceException $e) {
  174. return null;
  175. }
  176. }
  177. );
  178. }
  179. /**
  180. * An expectation for checking that an element, known to be present on the DOM of a page, is visible.
  181. * Visibility means that the element is not only displayed but also has a height and width that is greater than 0.
  182. *
  183. * @param WebDriverElement $element The element to be checked.
  184. * @return WebDriverExpectedCondition<WebDriverElement> Condition returns the same WebDriverElement once it is
  185. * visible.
  186. */
  187. public static function visibilityOf(WebDriverElement $element)
  188. {
  189. return new static(
  190. function () use ($element) {
  191. return $element->isDisplayed() ? $element : null;
  192. }
  193. );
  194. }
  195. /**
  196. * An expectation for checking if the given text is present in the specified element.
  197. * To check exact text match use elementTextIs() condition.
  198. *
  199. * @codeCoverageIgnore
  200. * @deprecated Use WebDriverExpectedCondition::elementTextContains() instead
  201. * @param WebDriverBy $by The locator used to find the element.
  202. * @param string $text The text to be presented in the element.
  203. * @return WebDriverExpectedCondition<bool> Condition returns whether the text is present in the element.
  204. */
  205. public static function textToBePresentInElement(WebDriverBy $by, $text)
  206. {
  207. return self::elementTextContains($by, $text);
  208. }
  209. /**
  210. * An expectation for checking if the given text is present in the specified element.
  211. * To check exact text match use elementTextIs() condition.
  212. *
  213. * @param WebDriverBy $by The locator used to find the element.
  214. * @param string $text The text to be presented in the element.
  215. * @return WebDriverExpectedCondition<bool> Condition returns whether the partial text is present in the element.
  216. */
  217. public static function elementTextContains(WebDriverBy $by, $text)
  218. {
  219. return new static(
  220. function (WebDriver $driver) use ($by, $text) {
  221. try {
  222. $element_text = $driver->findElement($by)->getText();
  223. return strpos($element_text, $text) !== false;
  224. } catch (StaleElementReferenceException $e) {
  225. return null;
  226. }
  227. }
  228. );
  229. }
  230. /**
  231. * An expectation for checking if the given text exactly equals the text in specified element.
  232. * To check only partial substring of the text use elementTextContains() condition.
  233. *
  234. * @param WebDriverBy $by The locator used to find the element.
  235. * @param string $text The expected text of the element.
  236. * @return WebDriverExpectedCondition<bool> Condition returns whether the element has text value equal to given one.
  237. */
  238. public static function elementTextIs(WebDriverBy $by, $text)
  239. {
  240. return new static(
  241. function (WebDriver $driver) use ($by, $text) {
  242. try {
  243. return $driver->findElement($by)->getText() == $text;
  244. } catch (StaleElementReferenceException $e) {
  245. return null;
  246. }
  247. }
  248. );
  249. }
  250. /**
  251. * An expectation for checking if the given regular expression matches the text in specified element.
  252. *
  253. * @param WebDriverBy $by The locator used to find the element.
  254. * @param string $regexp The regular expression to test against.
  255. * @return WebDriverExpectedCondition<bool> Condition returns whether the element has text value equal to given one.
  256. */
  257. public static function elementTextMatches(WebDriverBy $by, $regexp)
  258. {
  259. return new static(
  260. function (WebDriver $driver) use ($by, $regexp) {
  261. try {
  262. return (bool) preg_match($regexp, $driver->findElement($by)->getText());
  263. } catch (StaleElementReferenceException $e) {
  264. return null;
  265. }
  266. }
  267. );
  268. }
  269. /**
  270. * An expectation for checking if the given text is present in the specified elements value attribute.
  271. *
  272. * @param WebDriverBy $by The locator used to find the element.
  273. * @param string $text The text to be presented in the element value.
  274. * @return WebDriverExpectedCondition<bool> Condition returns whether the text is present in value attribute.
  275. */
  276. public static function textToBePresentInElementValue(WebDriverBy $by, $text)
  277. {
  278. return new static(
  279. function (WebDriver $driver) use ($by, $text) {
  280. try {
  281. $element_text = $driver->findElement($by)->getAttribute('value');
  282. return strpos($element_text, $text) !== false;
  283. } catch (StaleElementReferenceException $e) {
  284. return null;
  285. }
  286. }
  287. );
  288. }
  289. /**
  290. * Expectation for checking if iFrame exists. If iFrame exists switches driver's focus to the iFrame.
  291. *
  292. * @param string $frame_locator The locator used to find the iFrame
  293. * expected to be either the id or name value of the i/frame
  294. * @return WebDriverExpectedCondition<WebDriver|bool> Condition returns object focused on new frame when frame is
  295. * found, false otherwise.
  296. */
  297. public static function frameToBeAvailableAndSwitchToIt($frame_locator)
  298. {
  299. return new static(
  300. function (WebDriver $driver) use ($frame_locator) {
  301. try {
  302. return $driver->switchTo()->frame($frame_locator);
  303. } catch (NoSuchFrameException $e) {
  304. return false;
  305. }
  306. }
  307. );
  308. }
  309. /**
  310. * An expectation for checking that an element is either invisible or not present on the DOM.
  311. *
  312. * @param WebDriverBy $by The locator used to find the element.
  313. * @return WebDriverExpectedCondition<bool> Condition returns whether no visible element located.
  314. */
  315. public static function invisibilityOfElementLocated(WebDriverBy $by)
  316. {
  317. return new static(
  318. function (WebDriver $driver) use ($by) {
  319. try {
  320. return !$driver->findElement($by)->isDisplayed();
  321. } catch (NoSuchElementException $e) {
  322. return true;
  323. } catch (StaleElementReferenceException $e) {
  324. return true;
  325. }
  326. }
  327. );
  328. }
  329. /**
  330. * An expectation for checking that an element with text is either invisible or not present on the DOM.
  331. *
  332. * @param WebdriverBy $by The locator used to find the element.
  333. * @param string $text The text of the element.
  334. * @return WebDriverExpectedCondition<bool> Condition returns whether the text is found in the element located.
  335. */
  336. public static function invisibilityOfElementWithText(WebDriverBy $by, $text)
  337. {
  338. return new static(
  339. function (WebDriver $driver) use ($by, $text) {
  340. try {
  341. return !($driver->findElement($by)->getText() === $text);
  342. } catch (NoSuchElementException $e) {
  343. return true;
  344. } catch (StaleElementReferenceException $e) {
  345. return true;
  346. }
  347. }
  348. );
  349. }
  350. /**
  351. * An expectation for checking an element is visible and enabled such that you can click it.
  352. *
  353. * @param WebDriverBy $by The locator used to find the element
  354. * @return WebDriverExpectedCondition<WebDriverElement> Condition return the WebDriverElement once it is located,
  355. * visible and clickable.
  356. */
  357. public static function elementToBeClickable(WebDriverBy $by)
  358. {
  359. $visibility_of_element_located =
  360. self::visibilityOfElementLocated($by);
  361. return new static(
  362. function (WebDriver $driver) use ($visibility_of_element_located) {
  363. $element = call_user_func(
  364. $visibility_of_element_located->getApply(),
  365. $driver
  366. );
  367. try {
  368. if ($element !== null && $element->isEnabled()) {
  369. return $element;
  370. }
  371. return null;
  372. } catch (StaleElementReferenceException $e) {
  373. return null;
  374. }
  375. }
  376. );
  377. }
  378. /**
  379. * Wait until an element is no longer attached to the DOM.
  380. *
  381. * @param WebDriverElement $element The element to wait for.
  382. * @return WebDriverExpectedCondition<bool> Condition returns whether the element is still attached to the DOM.
  383. */
  384. public static function stalenessOf(WebDriverElement $element)
  385. {
  386. return new static(
  387. function () use ($element) {
  388. try {
  389. $element->isEnabled();
  390. return false;
  391. } catch (StaleElementReferenceException $e) {
  392. return true;
  393. }
  394. }
  395. );
  396. }
  397. /**
  398. * Wrapper for a condition, which allows for elements to update by redrawing.
  399. *
  400. * This works around the problem of conditions which have two parts: find an element and then check for some
  401. * condition on it. For these conditions it is possible that an element is located and then subsequently it is
  402. * redrawn on the client. When this happens a StaleElementReferenceException is thrown when the second part of
  403. * the condition is checked.
  404. *
  405. * @param WebDriverExpectedCondition $condition The condition wrapped.
  406. * @return WebDriverExpectedCondition<mixed> Condition returns the return value of the getApply() of the given
  407. * condition.
  408. */
  409. public static function refreshed(WebDriverExpectedCondition $condition)
  410. {
  411. return new static(
  412. function (WebDriver $driver) use ($condition) {
  413. try {
  414. return call_user_func($condition->getApply(), $driver);
  415. } catch (StaleElementReferenceException $e) {
  416. return null;
  417. }
  418. }
  419. );
  420. }
  421. /**
  422. * An expectation for checking if the given element is selected.
  423. *
  424. * @param mixed $element_or_by Either the element or the locator.
  425. * @return WebDriverExpectedCondition<bool> Condition returns whether the element is selected.
  426. */
  427. public static function elementToBeSelected($element_or_by)
  428. {
  429. return self::elementSelectionStateToBe(
  430. $element_or_by,
  431. true
  432. );
  433. }
  434. /**
  435. * An expectation for checking if the given element is selected.
  436. *
  437. * @param mixed $element_or_by Either the element or the locator.
  438. * @param bool $selected The required state.
  439. * @return WebDriverExpectedCondition<bool> Condition returns whether the element is selected.
  440. */
  441. public static function elementSelectionStateToBe($element_or_by, $selected)
  442. {
  443. if ($element_or_by instanceof WebDriverElement) {
  444. return new static(
  445. function () use ($element_or_by, $selected) {
  446. return $element_or_by->isSelected() === $selected;
  447. }
  448. );
  449. } else {
  450. if ($element_or_by instanceof WebDriverBy) {
  451. return new static(
  452. function (WebDriver $driver) use ($element_or_by, $selected) {
  453. try {
  454. $element = $driver->findElement($element_or_by);
  455. return $element->isSelected() === $selected;
  456. } catch (StaleElementReferenceException $e) {
  457. return null;
  458. }
  459. }
  460. );
  461. }
  462. }
  463. }
  464. /**
  465. * An expectation for whether an alert() box is present.
  466. *
  467. * @return WebDriverExpectedCondition<?WebDriverAlert> Condition returns WebDriverAlert if alert() is present,
  468. * null otherwise.
  469. */
  470. public static function alertIsPresent()
  471. {
  472. return new static(
  473. function (WebDriver $driver) {
  474. try {
  475. // Unlike the Java code, we get a WebDriverAlert object regardless
  476. // of whether there is an alert. Calling getText() will throw
  477. // an exception if it is not really there.
  478. $alert = $driver->switchTo()->alert();
  479. $alert->getText();
  480. return $alert;
  481. } catch (NoAlertOpenException $e) {
  482. return null;
  483. }
  484. }
  485. );
  486. }
  487. /**
  488. * An expectation checking the number of opened windows.
  489. *
  490. * @param int $expectedNumberOfWindows
  491. * @return WebDriverExpectedCondition
  492. */
  493. public static function numberOfWindowsToBe($expectedNumberOfWindows)
  494. {
  495. return new static(
  496. function (WebDriver $driver) use ($expectedNumberOfWindows) {
  497. return count($driver->getWindowHandles()) == $expectedNumberOfWindows;
  498. }
  499. );
  500. }
  501. /**
  502. * An expectation with the logical opposite condition of the given condition.
  503. *
  504. * @param WebDriverExpectedCondition $condition The condition to be negated.
  505. * @return mixed The negation of the result of the given condition.
  506. */
  507. public static function not(WebDriverExpectedCondition $condition)
  508. {
  509. return new static(
  510. function (WebDriver $driver) use ($condition) {
  511. $result = call_user_func($condition->getApply(), $driver);
  512. return !$result;
  513. }
  514. );
  515. }
  516. }