Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selenium Webdriver Turbolinks

I am currently writing selenium webdriver tests for a product that utilizes turbolinks (in ruby). When I click a button I have to wait for turbolinks to work. When I test jQuery callbacks I typically wait on my code with:

driver.execute_script 'return jQuery.active == 0'

What can I check via Javascript to verify that Turbolinks is done? Or is there an element I can grab to that can do the same? I see a progress bar on top but I can't find the element anywhere.

EDIT:

I'm able to do something like this:

driver.execute_script "$(document).on('page:load', function () { window.turbolinks = true; });"
driver.execute_script "$(document).on('page:before-change', function () { window.turbolinks = false; });"

on page load and then I can wait on window.turbolinks to be true

wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { driver.execute_script 'return window.turbolinks;' }

Is there a better way of handling this?

like image 990
Enrique Avatar asked Nov 09 '22 09:11

Enrique


1 Answers

Waiting for the page elements to finish loading is a classic Selenium issue with no single best solution. Working with Turbolinks simply compounds this problem.

When I need to know that Turbolinks has finished, listening for the Turbolinks turbolinks:load event (formerly page:load) is the best way I can think of.

If we know the exact line(s) of code that trigger the page load, we can pass this code as a block to a wrapper method that handles all of the wait logic for us, as follows:

def wait_for_page_load(driver)
  # listen for Turbolinks to start and stop
  driver.execute_script('document.addEventListener("turbolinks:before-visit", function() { window.turbolinks_is_busy = true; });')
  driver.execute_script('document.addEventListener("turbolinks:load", function() { window.turbolinks_is_busy = false; });')

  # execute the code that causes the page load
  yield

  # optional short sleep, just to be safe
  sleep(1)

  # wait for the various 'page is loading' indicators, including our custom Turbolinks indicator
  wait = Selenium::WebDriver::Wait.new(:timeout => 60)
  wait.until { driver.execute_script("return document.readyState == 'complete' && jQuery.active == 0 && !window.turbolinks_is_busy;") }
end

Example usage:

wait_for_page_load(@driver) { @driver.find_element(id: 'a#logout').click }

References:

  • https://github.com/turbolinks/turbolinks#observing-navigation-events
  • https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
  • jQuery.active function
like image 80
Ben Amos Avatar answered Nov 15 '22 04:11

Ben Amos