8

Apparently, sleep or wait_until are not valid using recent versions of Capybara, according to the webpage updates.

However, I have a set of tests that only work on fast machines if I add a sleep(1) call to the test. That is, a test that looks like:

describe "dosimeters page" do
  before do
    click_link("Dosimeter Read History", :match=>:first)
  end
...

becomes

describe "dosimeters page" do
  before do
    unix_wait
    click_link("Dosimeter Read History", :match=>:first)
  end
...

where I've defined unix_wait as:

def unix_wait
  case RbConfig::CONFIG['host_os']
  when /darwin/
  when /linux-gnu/
    sleep(1)
  end
end

The thing is, I have an old Ubuntu 12.04 quadcore laptop running these tests on Jenkins, and everything works well on it without the unix_wait calls. The tests failed randomly on a hexacore desktop running Ubuntu 13.10 and on a macbook pro laptop, but if I add in the unix_wait call, then the tests pass.

The test failures themselves are indicative of loading failures (ie, css elements missing on some runs, but not on others), and the things being tested actually work when the site is loaded manually.

So what's the appropriate action here? Apparently, sleep isn't allowed during testing, nor is wait_until. However, sleep is working, but it does seem extremely crude to me. Should I be looking at #synchronized? From what I gather from those blog posts, that's already getting called when I call click_link, and the tests are still failing.

What is the accepted protocol here?

I should add, because I think it's important: These are all javascript tests. I'm using capybara-webkit built on qt4 (not qt5). I'm considering switching to poltergeist or some other javascript driver as a debug step.

Ethan Chen
  • 649
  • 1
  • 6
  • 17
mmr
  • 14,781
  • 29
  • 95
  • 145
  • You can try to use webdriver for debugging but I have similar issues in it. – Andrei Botalov Nov 02 '13 at 08:07
  • I got the same problem with capybara-webkit when I use ajax. I don't know if poltergeist could resolve this, but it worth a try. – basgys Nov 03 '13 at 23:21
  • Can you explain more what failures you are seeing? I'm not clear what "css elements missing" truly entails. – Shepmaster Nov 04 '13 at 01:03
  • I'm seeing test failures. Sometimes, the failures are large stack traces where html or css elements are missing and, for some reason, that throws an exception. Most often, though, the tests to find elements or click links or whatever just fail because the element isn't present on the page (yet). The failures go away when enough timing code is added, or if I do something like 'save_and_open_page' – mmr Nov 04 '13 at 01:26
  • In the 2 documentation links you provide, they don't say `sleep` is not valid in Capybara. In fact, that would be very strange since it's a Ruby function and not part of the Capybara DSL. – Romain Paulus Nov 05 '13 at 07:28
  • @RomainPaulus-- you're right in that `sleep` is _valid_, but they're trying to make the point that it shouldn't be necessary, with the suggestion that it may be bad style. With that in mind, I'm trying to figure out how to make tests that are both good style and pass when they should pass. – mmr Nov 05 '13 at 17:10
  • Could you add an example of the failing text? I mean the failing line. – dgilperez Nov 07 '13 at 12:27
  • Also, have you tried using `find` on the page as, per the docs, `find` waits until it has the element on the page before executing... – CDub Nov 07 '13 at 17:14
  • @dgilperez-- I included a failing test in my original post. The `click_link` in `before do` fails with a message that it can't find the link to click. Adding a wait means that it can find the link. @CDub-- as per the docs, `click_link` should do the same thing, but it clearly does not. – mmr Nov 07 '13 at 17:25
  • @mmr your example has the sleep **after** you click the link. How does that fix the problem? – Shepmaster Nov 08 '13 at 23:34
  • @Shepmaster-- good point, edited. The change does not affect the behavior. – mmr Nov 09 '13 at 22:35
  • Could you gather this info to help narrow down the problem: 1) Which version(s) of Capybara and Capybara WebKit you have tried? 2) What is the value of `puts Capybara.default_wait_time` directly before your assertion? 3) How long does the test take to fail? 4) What in your code causes this element to appear after the initial page load? – Shepmaster Nov 10 '13 at 17:55
  • Hi Shepmaster-- most of my answers here are from memory, as it's a holiday here. 1) Most recent for both (2.1, 1.0.0, iirc-- all from bundle update, no restrictions). 2) I've modified this to be from 1 to 10, no change. 3) There are ~10 tests failing (at least, the test failures are random, so in some runs it may be only 4, for instance). The failures do not seem to take the full 1-10 seconds for wait time. 4) I have no idea; I just know that the elements are there when I use save_and_open_page, or just navigate to the page when running the server in development. – mmr Nov 11 '13 at 16:04

2 Answers2

5

In case your not doing this already, in your test assertion if you check for the content on the page it will wait for a set amount of time until that content becomes available.

So, instead of adding a sleep you can add something like

expect(page).to have_content 'Success'

Capybara accommodates Ajax and loading of elements etc. so it will wait implicitly when checking content.

You can alter the default wait time if you need to allow for loading of elements which you know may take longer i.e. 3rd partying queries/logins

Capybara.default_wait_time = 5
Asta
  • 1,569
  • 13
  • 23
  • 1
    Capybara _should_ be accommodating Ajax, but I'm not entirely sure that it is, since these are failures when using `:js => true` during testing. Changing the `default_wait_time` does not really help, but sometimes `save_and_open_page` fixes the issue (albeit causing a window to interrupt work). – mmr Nov 13 '13 at 23:32
  • Asta is right, the problem is you aren't triggering Capybara's wait mechanism, because you aren't checking for content. Asta mentions the check `have_content`, and you are doing no such thing. – kross Nov 20 '13 at 23:04
0

A good alternative of wait_until and sleep is using_wait_time, an example of which is shown below.

using_wait_time 5 do
  page.should have_content '<content>'
end

You can also reload the page, after which you can check whatever conditions you have. This works for me at times.

visit current_url
Ethan Chen
  • 649
  • 1
  • 6
  • 17