WebDriverExpectedCondition.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  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. protected function __construct(callable $apply)
  34. {
  35. $this->apply = $apply;
  36. }
  37. /**
  38. * @return callable A callable function to be executed by WebDriverWait
  39. */
  40. public function getApply()
  41. {
  42. return $this->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 static 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 static 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 mb_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 static Condition returns whether current page title matches the regular expression.
  77. */
  78. public static function titleMatches($titleRegexp)
  79. {
  80. return new static(
  81. function (WebDriver $driver) use ($titleRegexp) {
  82. return (bool) preg_match($titleRegexp, $driver->getTitle());
  83. }
  84. );
  85. }
  86. /**
  87. * An expectation for checking the URL of a page.
  88. *
  89. * @param string $url The expected URL, which must be an exact match.
  90. * @return static Condition returns whether current URL equals given one.
  91. */
  92. public static function urlIs($url)
  93. {
  94. return new static(
  95. function (WebDriver $driver) use ($url) {
  96. return $url === $driver->getCurrentURL();
  97. }
  98. );
  99. }
  100. /**
  101. * An expectation for checking substring of the URL of a page.
  102. *
  103. * @param string $url The expected substring of the URL
  104. * @return static Condition returns whether current URL contains given string.
  105. */
  106. public static function urlContains($url)
  107. {
  108. return new static(
  109. function (WebDriver $driver) use ($url) {
  110. return mb_strpos($driver->getCurrentURL(), $url) !== false;
  111. }
  112. );
  113. }
  114. /**
  115. * An expectation for checking current page URL matches the given regular expression.
  116. *
  117. * @param string $urlRegexp The regular expression to test against.
  118. * @return static Condition returns whether current URL matches the regular expression.
  119. */
  120. public static function urlMatches($urlRegexp)
  121. {
  122. return new static(
  123. function (WebDriver $driver) use ($urlRegexp) {
  124. return (bool) preg_match($urlRegexp, $driver->getCurrentURL());
  125. }
  126. );
  127. }
  128. /**
  129. * An expectation for checking that an element is present on the DOM of a page.
  130. * This does not necessarily mean that the element is visible.
  131. *
  132. * @param WebDriverBy $by The locator used to find the element.
  133. * @return static Condition returns the WebDriverElement which is located.
  134. */
  135. public static function presenceOfElementLocated(WebDriverBy $by)
  136. {
  137. return new static(
  138. function (WebDriver $driver) use ($by) {
  139. return $driver->findElement($by);
  140. }
  141. );
  142. }
  143. /**
  144. * An expectation for checking that there is at least one element present on a web page.
  145. *
  146. * @param WebDriverBy $by The locator used to find the element.
  147. * @return static Condition return an array of WebDriverElement once they are located.
  148. */
  149. public static function presenceOfAllElementsLocatedBy(WebDriverBy $by)
  150. {
  151. return new static(
  152. function (WebDriver $driver) use ($by) {
  153. $elements = $driver->findElements($by);
  154. return count($elements) > 0 ? $elements : null;
  155. }
  156. );
  157. }
  158. /**
  159. * An expectation for checking that an element is present on the DOM of a page and visible.
  160. * Visibility means that the element is not only displayed but also has a height and width that is greater than 0.
  161. *
  162. * @param WebDriverBy $by The locator used to find the element.
  163. * @return static Condition returns the WebDriverElement which is located and visible.
  164. */
  165. public static function visibilityOfElementLocated(WebDriverBy $by)
  166. {
  167. return new static(
  168. function (WebDriver $driver) use ($by) {
  169. try {
  170. $element = $driver->findElement($by);
  171. return $element->isDisplayed() ? $element : null;
  172. } catch (StaleElementReferenceException $e) {
  173. return null;
  174. }
  175. }
  176. );
  177. }
  178. /**
  179. * An expectation for checking than at least one element in an array of elements is present on the
  180. * DOM of a page and 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 WebDriverBy $by The located used to find the element.
  184. * @return static Condition returns the array of WebDriverElement that are located and visible.
  185. */
  186. public static function visibilityOfAnyElementLocated(WebDriverBy $by)
  187. {
  188. return new static(
  189. function (WebDriver $driver) use ($by) {
  190. $elements = $driver->findElements($by);
  191. $visibleElements = [];
  192. foreach ($elements as $element) {
  193. try {
  194. if ($element->isDisplayed()) {
  195. $visibleElements[] = $element;
  196. }
  197. } catch (StaleElementReferenceException $e) {
  198. }
  199. }
  200. return count($visibleElements) > 0 ? $visibleElements : null;
  201. }
  202. );
  203. }
  204. /**
  205. * An expectation for checking that an element, known to be present on the DOM of a page, is visible.
  206. * Visibility means that the element is not only displayed but also has a height and width that is greater than 0.
  207. *
  208. * @param WebDriverElement $element The element to be checked.
  209. * @return static Condition returns the same WebDriverElement once it is visible.
  210. */
  211. public static function visibilityOf(WebDriverElement $element)
  212. {
  213. return new static(
  214. function () use ($element) {
  215. return $element->isDisplayed() ? $element : null;
  216. }
  217. );
  218. }
  219. /**
  220. * An expectation for checking if the given text is present in the specified element.
  221. * To check exact text match use elementTextIs() condition.
  222. *
  223. * @codeCoverageIgnore
  224. * @deprecated Use WebDriverExpectedCondition::elementTextContains() instead
  225. * @param WebDriverBy $by The locator used to find the element.
  226. * @param string $text The text to be presented in the element.
  227. * @return static Condition returns whether the text is present in the element.
  228. */
  229. public static function textToBePresentInElement(WebDriverBy $by, $text)
  230. {
  231. return self::elementTextContains($by, $text);
  232. }
  233. /**
  234. * An expectation for checking if the given text is present in the specified element.
  235. * To check exact text match use elementTextIs() condition.
  236. *
  237. * @param WebDriverBy $by The locator used to find the element.
  238. * @param string $text The text to be presented in the element.
  239. * @return static Condition returns whether the partial text is present in the element.
  240. */
  241. public static function elementTextContains(WebDriverBy $by, $text)
  242. {
  243. return new static(
  244. function (WebDriver $driver) use ($by, $text) {
  245. try {
  246. $element_text = $driver->findElement($by)->getText();
  247. return mb_strpos($element_text, $text) !== false;
  248. } catch (StaleElementReferenceException $e) {
  249. return null;
  250. }
  251. }
  252. );
  253. }
  254. /**
  255. * An expectation for checking if the given text exactly equals the text in specified element.
  256. * To check only partial substring of the text use elementTextContains() condition.
  257. *
  258. * @param WebDriverBy $by The locator used to find the element.
  259. * @param string $text The expected text of the element.
  260. * @return static Condition returns whether the element has text value equal to given one.
  261. */
  262. public static function elementTextIs(WebDriverBy $by, $text)
  263. {
  264. return new static(
  265. function (WebDriver $driver) use ($by, $text) {
  266. try {
  267. return $driver->findElement($by)->getText() == $text;
  268. } catch (StaleElementReferenceException $e) {
  269. return null;
  270. }
  271. }
  272. );
  273. }
  274. /**
  275. * An expectation for checking if the given regular expression matches the text in specified element.
  276. *
  277. * @param WebDriverBy $by The locator used to find the element.
  278. * @param string $regexp The regular expression to test against.
  279. * @return static Condition returns whether the element has text value equal to given one.
  280. */
  281. public static function elementTextMatches(WebDriverBy $by, $regexp)
  282. {
  283. return new static(
  284. function (WebDriver $driver) use ($by, $regexp) {
  285. try {
  286. return (bool) preg_match($regexp, $driver->findElement($by)->getText());
  287. } catch (StaleElementReferenceException $e) {
  288. return null;
  289. }
  290. }
  291. );
  292. }
  293. /**
  294. * An expectation for checking if the given text is present in the specified elements value attribute.
  295. *
  296. * @codeCoverageIgnore
  297. * @deprecated Use WebDriverExpectedCondition::elementValueContains() instead
  298. * @param WebDriverBy $by The locator used to find the element.
  299. * @param string $text The text to be presented in the element value.
  300. * @return static Condition returns whether the text is present in value attribute.
  301. */
  302. public static function textToBePresentInElementValue(WebDriverBy $by, $text)
  303. {
  304. return self::elementValueContains($by, $text);
  305. }
  306. /**
  307. * An expectation for checking if the given text is present in the specified elements value attribute.
  308. *
  309. * @param WebDriverBy $by The locator used to find the element.
  310. * @param string $text The text to be presented in the element value.
  311. * @return static Condition returns whether the text is present in value attribute.
  312. */
  313. public static function elementValueContains(WebDriverBy $by, $text)
  314. {
  315. return new static(
  316. function (WebDriver $driver) use ($by, $text) {
  317. try {
  318. $element_text = $driver->findElement($by)->getAttribute('value');
  319. return mb_strpos($element_text, $text) !== false;
  320. } catch (StaleElementReferenceException $e) {
  321. return null;
  322. }
  323. }
  324. );
  325. }
  326. /**
  327. * Expectation for checking if iFrame exists. If iFrame exists switches driver's focus to the iFrame.
  328. *
  329. * @param string $frame_locator The locator used to find the iFrame
  330. * expected to be either the id or name value of the i/frame
  331. * @return static Condition returns object focused on new frame when frame is found, false otherwise.
  332. */
  333. public static function frameToBeAvailableAndSwitchToIt($frame_locator)
  334. {
  335. return new static(
  336. function (WebDriver $driver) use ($frame_locator) {
  337. try {
  338. return $driver->switchTo()->frame($frame_locator);
  339. } catch (NoSuchFrameException $e) {
  340. return false;
  341. }
  342. }
  343. );
  344. }
  345. /**
  346. * An expectation for checking that an element is either invisible or not present on the DOM.
  347. *
  348. * @param WebDriverBy $by The locator used to find the element.
  349. * @return static Condition returns whether no visible element located.
  350. */
  351. public static function invisibilityOfElementLocated(WebDriverBy $by)
  352. {
  353. return new static(
  354. function (WebDriver $driver) use ($by) {
  355. try {
  356. return !$driver->findElement($by)->isDisplayed();
  357. } catch (NoSuchElementException $e) {
  358. return true;
  359. } catch (StaleElementReferenceException $e) {
  360. return true;
  361. }
  362. }
  363. );
  364. }
  365. /**
  366. * An expectation for checking that an element with text is either invisible or not present on the DOM.
  367. *
  368. * @param WebDriverBy $by The locator used to find the element.
  369. * @param string $text The text of the element.
  370. * @return static Condition returns whether the text is found in the element located.
  371. */
  372. public static function invisibilityOfElementWithText(WebDriverBy $by, $text)
  373. {
  374. return new static(
  375. function (WebDriver $driver) use ($by, $text) {
  376. try {
  377. return !($driver->findElement($by)->getText() === $text);
  378. } catch (NoSuchElementException $e) {
  379. return true;
  380. } catch (StaleElementReferenceException $e) {
  381. return true;
  382. }
  383. }
  384. );
  385. }
  386. /**
  387. * An expectation for checking an element is visible and enabled such that you can click it.
  388. *
  389. * @param WebDriverBy $by The locator used to find the element
  390. * @return static Condition return the WebDriverElement once it is located, visible and clickable.
  391. */
  392. public static function elementToBeClickable(WebDriverBy $by)
  393. {
  394. $visibility_of_element_located =
  395. self::visibilityOfElementLocated($by);
  396. return new static(
  397. function (WebDriver $driver) use ($visibility_of_element_located) {
  398. $element = call_user_func(
  399. $visibility_of_element_located->getApply(),
  400. $driver
  401. );
  402. try {
  403. if ($element !== null && $element->isEnabled()) {
  404. return $element;
  405. }
  406. return null;
  407. } catch (StaleElementReferenceException $e) {
  408. return null;
  409. }
  410. }
  411. );
  412. }
  413. /**
  414. * Wait until an element is no longer attached to the DOM.
  415. *
  416. * @param WebDriverElement $element The element to wait for.
  417. * @return static Condition returns whether the element is still attached to the DOM.
  418. */
  419. public static function stalenessOf(WebDriverElement $element)
  420. {
  421. return new static(
  422. function () use ($element) {
  423. try {
  424. $element->isEnabled();
  425. return false;
  426. } catch (StaleElementReferenceException $e) {
  427. return true;
  428. }
  429. }
  430. );
  431. }
  432. /**
  433. * Wrapper for a condition, which allows for elements to update by redrawing.
  434. *
  435. * This works around the problem of conditions which have two parts: find an element and then check for some
  436. * condition on it. For these conditions it is possible that an element is located and then subsequently it is
  437. * redrawn on the client. When this happens a StaleElementReferenceException is thrown when the second part of
  438. * the condition is checked.
  439. *
  440. * @param WebDriverExpectedCondition $condition The condition wrapped.
  441. * @return static Condition returns the return value of the getApply() of the given condition.
  442. */
  443. public static function refreshed(self $condition)
  444. {
  445. return new static(
  446. function (WebDriver $driver) use ($condition) {
  447. try {
  448. return call_user_func($condition->getApply(), $driver);
  449. } catch (StaleElementReferenceException $e) {
  450. return null;
  451. }
  452. }
  453. );
  454. }
  455. /**
  456. * An expectation for checking if the given element is selected.
  457. *
  458. * @param mixed $element_or_by Either the element or the locator.
  459. * @return static Condition returns whether the element is selected.
  460. */
  461. public static function elementToBeSelected($element_or_by)
  462. {
  463. return self::elementSelectionStateToBe(
  464. $element_or_by,
  465. true
  466. );
  467. }
  468. /**
  469. * An expectation for checking if the given element is selected.
  470. *
  471. * @param mixed $element_or_by Either the element or the locator.
  472. * @param bool $selected The required state.
  473. * @return static Condition returns whether the element is selected.
  474. */
  475. public static function elementSelectionStateToBe($element_or_by, $selected)
  476. {
  477. if ($element_or_by instanceof WebDriverElement) {
  478. return new static(
  479. function () use ($element_or_by, $selected) {
  480. return $element_or_by->isSelected() === $selected;
  481. }
  482. );
  483. } else {
  484. if ($element_or_by instanceof WebDriverBy) {
  485. return new static(
  486. function (WebDriver $driver) use ($element_or_by, $selected) {
  487. try {
  488. $element = $driver->findElement($element_or_by);
  489. return $element->isSelected() === $selected;
  490. } catch (StaleElementReferenceException $e) {
  491. return null;
  492. }
  493. }
  494. );
  495. }
  496. }
  497. }
  498. /**
  499. * An expectation for whether an alert() box is present.
  500. *
  501. * @return static Condition returns WebDriverAlert if alert() is present, null otherwise.
  502. */
  503. public static function alertIsPresent()
  504. {
  505. return new static(
  506. function (WebDriver $driver) {
  507. try {
  508. // Unlike the Java code, we get a WebDriverAlert object regardless
  509. // of whether there is an alert. Calling getText() will throw
  510. // an exception if it is not really there.
  511. $alert = $driver->switchTo()->alert();
  512. $alert->getText();
  513. return $alert;
  514. } catch (NoAlertOpenException $e) {
  515. return null;
  516. }
  517. }
  518. );
  519. }
  520. /**
  521. * An expectation checking the number of opened windows.
  522. *
  523. * @param int $expectedNumberOfWindows
  524. * @return static
  525. */
  526. public static function numberOfWindowsToBe($expectedNumberOfWindows)
  527. {
  528. return new static(
  529. function (WebDriver $driver) use ($expectedNumberOfWindows) {
  530. return count($driver->getWindowHandles()) == $expectedNumberOfWindows;
  531. }
  532. );
  533. }
  534. /**
  535. * An expectation with the logical opposite condition of the given condition.
  536. *
  537. * @param WebDriverExpectedCondition $condition The condition to be negated.
  538. * @return mixed The negation of the result of the given condition.
  539. */
  540. public static function not(self $condition)
  541. {
  542. return new static(
  543. function (WebDriver $driver) use ($condition) {
  544. $result = call_user_func($condition->getApply(), $driver);
  545. return !$result;
  546. }
  547. );
  548. }
  549. }