Sleep in a Capybara AJAX test, needed?

In the code below, if I have the sleep 1, the test passes. Without the sleep, the test reliably fails. Calling hover on the_image triggers the ajax. Maybe I’m setting up the last expect incorrectly? Or are there cases where sleep is needed?

    the_image = find(:xpath, "//a[@data-image-id='#{}']/..")
    expect(page).to have_xpath("//a[@data-image-id='#{}']/../a[contains(@class, 'thumb-download')]")
    sleep 1
    expect(find(:xpath, "//a[@data-image-id='#{}']/../a[contains(@class, 'thumb-download')]")[:href]).to match(/https:/)

I don’t know if it is the best solution but you can apply this.

@Guirec_Corbel I tried that, but for some reason, it didn’t work for me.

In general you should not have to add explicit sleep calls in capybara feature specs as it has built in logic for waiting for ajax requests, and retrying find and has_content calls within a given period of time. You can read up on the specifics of this in the Async & AJAX section of the docs.

That said, it looks like you are using the expected methods, ie find and have_xpath, which should activate this waiting logic. With that in mind, you might want to try bumping up the overall Capybara wait timeout setting:

# in spec/spec_helper.rb
Capybara.default_wait_time = 3 # default is 2

Whereas sleep 1 is guaranteed to add 1 sec to your spec run time, bumping Capybara’s timeout threshold will only use as much time as needed.

@christoomey, my timeout was already set fairly high (like 8 seconds). Maybe there is some bug in Capybara that I’m hitting.

expect(find(:xpath, "//a[@data-image-id='#{}']/../a[contains(@class, 'thumb-download')]")[:href]).to match(/https:/)

Chris is right : find will wait. However, you’re only calling find for the link. Is it possible the selector for that link is present before the href attribute is populated with a value that will match?

That is true. The link already exists with the value of “#”. How can I convert the selector to check the value of the link?