diff --git a/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php b/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php index 94a9108..117b7f7 100644 --- a/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php +++ b/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php @@ -6,6 +6,8 @@ use Behat\Mink\Exception\ElementHtmlException; use Behat\Mink\Exception\ElementNotFoundException; use Behat\Mink\Exception\UnsupportedDriverActionException; +use Behat\Mink\Selector\Xpath\Manipulator; +use Behat\Mink\Session; use Drupal\Tests\WebAssert; /** @@ -14,6 +16,17 @@ class JSWebAssert extends WebAssert { /** + * @var Manipulator + */ + private $xpathManipulator; + + public function __construct(\Behat\Mink\Session $session, $base_url = '') { + parent::__construct($session, $base_url); + + $this->xpathManipulator = new Manipulator(); + } + + /** * Waits for AJAX request to be completed. * * @param int $timeout @@ -26,21 +39,109 @@ class JSWebAssert extends WebAssert { * be displayed. */ public function assertWaitOnAjaxRequest($timeout = 10000, $message = 'Unable to complete AJAX request.') { - $result = $this->session->wait($timeout, '(typeof(jQuery)=="undefined" || (0 === jQuery.active && 0 === jQuery(\':animated\').length))'); + $condition = <<session->wait($timeout, $condition); if (!$result) { throw new \RuntimeException($message); } } /** + * Waits for the specified selector and returns it when available. + * + * @param string $selector + * selector engine name + * @param string|array $locator + * selector locator + * @param int $timeout + * (Optional) Timeout in milliseconds, defaults to 10000. + * + * @return NodeElement|null + * + * @see ElementInterface::findAll for the supported selectors + */ + protected function waitForElement($selector, $locator, $timeout = 10000) { + $page = $this->session->getPage(); + $xpath = $this->session->getSelectorsHandler()->selectorToXpath($selector, $locator); + $xpath = $this->xpathManipulator->prepend($xpath, $page->getXpath()); + + $condition = "document.evaluate(\"" . str_replace(PHP_EOL, '', $xpath) . "\", document, null, XPathResult.BOOLEAN_TYPE,null).booleanValue"; + $this->assertJsCondition($condition, $timeout); + + return $page->find($selector, $locator); + } + + /** + * Waits for a button (input[type=submit|image|button|reset], button) with + * specified locator and returns it. + * + * @param string $locator + * button id, value or alt + * + * @return NodeElement|null + */ + protected function waitForButton($locator) { + return $this->waitForElement('named', array('button', $locator)); + } + + /** + * Waits for a link with specified locator and returns it when available. + * + * @param string $locator + * link id, title, text or image alt + * + * @return NodeElement|null + */ + protected function waitForLink($locator) { + return $this->waitForElement('named', array('link', $locator)); + } + + /** + * Waits for a field (input, textarea, select) with specified locator and + * returns it when available. + * + * @param string $locator + * input id, name or label + * + * @return NodeElement|null + */ + protected function waitForField($locator) { + return $this->waitForElement('named', array('field', $locator)); + } + + /** + * Wait for an element by its id and returns it when available. + * + * @param string $id + * element id + * @return NodeElement|null + */ + protected function waitForId($id) { + return $this->waitForElement('named', array('id', $id)); + } + + /** * Waits for the jQuery autocomplete delay duration. * * @see https://api.jqueryui.com/autocomplete/#option-delay */ public function waitOnAutocomplete() { - // Drupal is using the default delay value of 300 milliseconds. - $this->session->wait(300); - $this->assertWaitOnAjaxRequest(); + // Wait for the autocomplete to be visible. + $condition = "(jQuery('.ui-autocomplete:visible li').length > 0)"; + return $this->session->wait(10000, $condition); } /**