Back to Resources

Blog

Posted December 10, 2018

Selenium Tips: Infinite Loops Take Forever

quote

In Selenium, it's a common for the tool to get ahead of the browser. Thus, the element we want to click on does not exist yet - but it will!

We’ll start with a sample html page that pauses four seconds before injecting a link onto the page. In practice, this would probably be a wait for javascript to make a REST API call and push the results into the document.

Our naive test for the link in simple ruby:

element = @driver.find_element :xpath, "//a[text() = 'Sauce Labs']"assert_equal('https://www.saucelabs.com/', element.attribute('href'));

It only fails because the link does not exist on the page (yet). The simple fix, in the terrible_example, is to add a sleep.

Don’t do that.

Our next attempt will be infinite_loop.rb, which uses a while loop to wait for the link text to appear on the page:

#And now we'll do the text for the HREF to appear page_source = @driver.page_source includes_sauce = page_source.include? "Sauce Labs"; while not (includes_sauce)  sleep(0.01);  page_source = @driver.page_source;  includes_sauce = page_source.include? "Sauce Labs"; end

This works just fine, until we have some sort of error where the text never appears - the exact kind of bug our software is looking for. Now when that happens we’ll be stuck in an infinite loop. That’s no good.

We’ll write two functions to do this. First, we can pull body_contains logic into a method:

  def body_contains(driver,expected_content)     source = driver.page_source;     puts "expected ( " +  expected_content + " ) \n\n";     puts "source ( " +  source + " ) \n\n";     puts (source.include? expected_content).to_s();     return source.include? expected_content;   end

Then we can write the containher function:

  #Adapted with permission from other Sauce Labs Examples   def contains_with_timeout(driver, expected, timeout=60)    start = Time.now();    found = false;    puts start.to_s();    puts Time.now().to_s();

 while (Time.now()-start<timeout) and not found        if body_contains(driver, expected)            found = true;        else          sleep(0.25);        end    end    return found;   end

It won’t take much to adapt this so that contains_with_timeout is actually anything_with_timeout, where the comparison method is passed in during the function call.

For now, here’s the code for our wait:

contains_with_timeout(@driver,"Sauce Labs");

Read the code yourself in github as timer.rb. The directory in github contains all three full running example and the sample HTML page. Experiment with changing the timeouts and delays to see the errors fire.

That’s right, I said four.

WAIT, THERE'S MORE!

Selenium webdriver includes Explicit Wait, the fourth example in our set.

That code is as simple as:

#And now we'll do the text for the HREF to appear wait = Selenium::WebDriver::Wait.new(:timeout => 15) # seconds begin    element = wait.until { @driver.find_element(:id => "truth") } ensure

end assert_equal('https://www.saucelabs.com/', element.attribute('href'));

So go ahead, use the webdriver explicit wait.

We just thought you might appreciate knowing how to do it yourself.

Published:
Dec 10, 2018
Topics
Share this post
Copy Share Link
© 2023 Sauce Labs Inc., all rights reserved. SAUCE and SAUCE LABS are registered trademarks owned by Sauce Labs Inc. in the United States, EU, and may be registered in other jurisdictions.