diff --git a/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php b/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php index 94a9108..cc3afb4 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,19 @@ class JSWebAssert extends WebAssert { /** + * A XPath manipulator. + * + * @var \Behat\Mink\Selector\Xpath\Manipulator + */ + protected $xpathManipulator; + + public function __construct(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 +41,115 @@ 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 + * The selector engine name. See ElementInterface::findAll() for the + * supported selectors. + * @param string|array $locator + * The selector locator. + * @param int $timeout + * (Optional) Timeout in milliseconds, defaults to 10000. + * + * @return \Behat\Mink\Element\NodeElement|null + * The page element node if found, NULL if not. + * + * @see \Behat\Mink\Element\ElementInterface::findAll() + */ + 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 + * The button ID, value or alt string. + * + * @return \Behat\Mink\Element\NodeElement|null + * The page element node if found, NULL if not. + */ + 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 + * The link ID, title, text or image alt. + * + * @return \Behat\Mink\Element\NodeElement|null + * The page element node if found, NULL if not. + */ + protected function waitForLink($locator) { + return $this->waitForElement('named', array('link', $locator)); + } + + /** + * Waits for a field with specified locator and returns it when available. + * + * @param string $locator + * The input ID, name or label for the field (input, textarea, select). + * + * @return \Behat\Mink\Element\NodeElement|null + * The page element node if found, NULL if not. + */ + protected function waitForField($locator) { + return $this->waitForElement('named', array('field', $locator)); + } + + /** + * Waits for an element by its id and returns it when available. + * + * @param string $id + * The element ID. + * + * @return \Behat\Mink\Element\NodeElement|null + * The page element node if found, NULL if not. + */ + 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); } /**