Tuesday, April 19, 2016

Behat spin method not finding Selennium selector

Leave a Comment

Given I have the following scenario taken from the Behat docs:

@javascript Scenario: Searching for a page with autocompletion   Given I am on "/wiki/Main_Page"   When I fill in "search" with "Behavior Driv"   And I wait for the suggestion box to appear   Then I should see "Behavior Driven Development" 

And my FeatureContext class extends MinkContext and has the following methods:

/**  * @Given /^I wait for the suggestion box to appear$/  */ public function iWaitForTheSuggestionBoxToAppear() {     $this->spin(function (FeatureContext $context) {         return $context->assertElementOnPage('.suggestions-result');     }, 15);      return true; }  public function spin ($lambda, $wait = 15) {     for ($i = 0; $i < $wait; $i++)     {         try {             if ($lambda($this)) {                 return true;             }         } catch (Exception $e) {             // do nothing         }          sleep(1);     }      $backtrace = debug_backtrace();      throw new Exception(         "Timeout thrown by " . $backtrace[1]['class'] . "::" . $backtrace[1]['function'] . "()\n" .         $backtrace[0]['file'] . ", line " . $backtrace[0]['line']     ); } 

And my Behat config is set to this:

default:   extensions:     Behat\MinkExtension:       base_url: http://en.wikipedia.org       goutte: ~       selenium2:         browser: phantomjs 

Why am I finding that the function I pass to spin never returns true? It works fine if I pass in a selector that exists when the page first loads, such as body, but I'm expecting this to spot that the autocomplete results (or rather the markup containing a result) is available.

Am I going wrong somewhere?

The logs from the selennium server show the selector attempting to find the element:

20:44:40.924 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:41.161 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:42.218 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:42.445 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:43.454 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:43.696 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:44.724 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:44.962 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:45.969 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:46.249 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:47.273 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:47.519 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:48.529 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:48.816 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:49.829 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:50.075 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:51.082 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:51.306 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:52.314 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:52.540 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:53.546 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:53.768 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:54.773 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:54.994 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:56.011 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:56.226 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:57.234 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:57.479 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:58.485 INFO - Executing: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]]) 20:44:58.720 INFO - Done: [find elements: By.xpath: //html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' suggestions-result ')]] 20:44:59.837 INFO - Executing: [delete session: d95ac5c9-6969-4ecb-b8f2-aafc6f8b82a5]) [INFO  - 2016-04-08T20:44:59.866Z] ShutdownReqHand - _handle - About to shutdown 20:45:00.425 INFO - Done: [delete session: d95ac5c9-6969-4ecb-b8f2-aafc6f8b82a5] 

1 Answers

Answers 1

We gave up on using the spin function in the end, as we encountered the same problem.

One thing that we have found to work, is Implicit Waits.

You can stick this into your context and use them like this:

public function turnOnImplicitWait() {     // Set up implicit timeouts     $driver = $this->getSession()->getDriver()->getWebDriverSession();     $driver->timeouts()->implicit_wait(array("ms" => 10000)); }  public function turnOffImplicitWait() {     // Set up implicit timeouts     $driver = $this->getSession()->getDriver()->getWebDriverSession();     $driver->timeouts()->implicit_wait(array("ms" => 0)); }  /**  * @Given /^I set (?:|the )implicit wait to ([\d]+)? (m|mins?|s|seconds?|ms|milliseconds)?(?:| .*)$/  */ public function setImplicitWait($time, $msormins) {     $driver = $this->getSession()->getDriver()->getWebDriverSession();     if ($msormins == "min" | $msormins == "mins") {         $time = $time * 60000;     } elseif ($msormins == "s" | $msormins == "seconds") {         $time = $time * 1000;     } elseif ($msormins == "ms" | $msormins == "milliseconds") {         $time = $time * 1;     }     $driver->timeouts()->implicit_wait(array("ms" => $time)); } 

You could also whack this into your Feature Context, and it will be set for each Scenario:

 /**  * @BeforeScenario  */ public function implicitlyWait($event) {     // Set up implicit timeouts     $driver = $this->getSession()->getDriver()->getWebDriverSession();     $driver->timeouts()->implicit_wait(array("ms" => 10000)); } 

Just a note: Turn off the implicit wait for the steps that expect not to see an element, and you should be fine. Turn it back on after it has successfully not seen the element. Not doing this will make it hang for the length of the implicit wait.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment