Search code examples
seleniumselenium-webdrivercapybaraselenium-chromedrivercapybara-webkit

Waiting function for CSS element in Capybara


There are waiting and non-waiting functions in Capybara. I am trying to use the first as much as possible.

Is there a way to use find (or one of its derivatives) to look for a CSS element that appears asynchronously? Unfortunately, function page.has_css? is a non-waiting function.


Solution

  • Your claim that page.has_css? is a non-waiting function is not correct. page.has_css? will wait up to Capybara.default_max_wait_time seconds for an element to appear on the page and return true or false based on whether or not the element is on the page within that time. Therefore, given Capybara.default_max_wait_time = 5

    if page.has_css?("div#my_div")
       puts "on page"
    else
       puts "not on page"
    end
    

    will wait for up to 5 seconds. As soon as a div with id of "my_div" is visible on the page it will print "on page". If a matching div doesn't become visible within 5 seconds it will print "not on page". If you want it to wait longer for a specific call you can override default_max_wait_time by passing the :wait option

    if page.has_css?("div#my_div", wait: 10)  # will wait up to 10 seconds
      ...
    

    If rather than wanting a boolean response you want to ensure the element exists you can do any of

    page.assert_selector(:css, 'div#my_div') # :css is the default so can usually be omitted
    page.assert_css('div#my_div') # minitest
    expect(page).to have_css('div#my_div') # RSpec
    

    which will wait for the element to appear as previously, but raise an exception rather than returning false if the element does not appear

    If you need the actual element you can use find which will also wait. So

    el = page.find(:css, 'div#my_div') # :css is the default and can usually be omitted
    

    will wait for the element to appear and return the element when found. If the element is not found within default_max_wait_time seconds it will raise an exception.

    Note: Basically, the only non-waiting methods are all and first and even those can be made to wait if you pass in any of the count options (:count, :minimum, :maximum, :between), although the elements returned from them would still be non-reloadable and can therefore have further behavior effects if used for scoping, etc. Even methods like click_link, click_button, etc will wait since they are implemented as find(...).click, etc