1

I have an html container with a link on my page which is hidden

<div id=”container” style=”display: none”> <a href=”/somelink” id=”inner-link”>Redirect Here</a> </div>

An external button, toggles the containers visibility via the jQuery .show() method

<a id=”toggle-container”>Show panel</a>

$(“#toggle-container”).on(“click”, function(){ $(“#container”).show(); });

All is peachy and runs fine in the browser, but for some reason, when I try to test this behaviour with capybara + poltergeist like so:

# Click the link, this should show the container
click_link(“toggle-container”)

# Click the link inside the container, this should cause a redirect
click_link(“inner-link”)

The test doesn’t fail, but the redirect link doesn’t get clicked by capybara. This is strange because Capybara acts like it finds the #inner-link element but the redirect never happens (I also captured a screenshot to verify this - the container is shown and the link isn’t clicked). I’ve managed to solve this by adding sleep 1 function before clicking the redirect link.

# Click the link, this should show the container
click_link(“toggle-container”)
sleep 1
# Click the link inside the container, this should cause a redirect
click_link(“inner-link”)

This is very strange, I can't figure out why sleep would cause the test to go green..
Is it possible that Capybara runs faster than the JS code? if so, what is the proper way to tackle this behavior?

mork
  • 89
  • 1
  • 10
  • Please verify your click_link example - click_link takes text, id, title or nested images alt attribute. It does not take a css selector. I'm assuming your example should be click_link("toggle-container") and click_link('inner-link') - If you are passing strings with # in front that explains why things aren't working for you - If you are not passing with '#' in front, then have you set Capybara.ignore_hidden_elements = false by any chance? – Thomas Walpole Nov 23 '15 at 20:05
  • Depending on the driver you're using, this could also happen if the reveal uses any kind of animation, in which case it's usually best to disable those animations in the test environment - also note your top html is invalid since you're opening a div but closing a form – Thomas Walpole Nov 23 '15 at 20:14
  • @TomWalpole You're right. I edited the question. In my code it appears without the #. I want to emphasise that the test is running and passing, it's just not doing what it's suppose to do which is click the button which leads to a redirect. – mork Nov 24 '15 at 10:08
  • I just noticed from the tag that you're using poltergeist -- Poltergeist has an issue with clicking on things that are moving when they appear - so if you do have CSS transition/animation occuring when you show container that could definitely be your issue - see https://github.com/teampoltergeist/poltergeist/issues/286 . There's not much poltergeist can do about it because of the way phantomjs works, best solution is to disable all animations in the testing environment – Thomas Walpole Nov 24 '15 at 19:42
  • Did you ever get to the bottom of this? I have a bunch of tests that fail unless I put sleeps after the "click_links". Very annoying. Only happens with orderly gem, but might be that that is the only type of test that I use "click_link" for. None of the comments or answers seem relevant to my case, though I guess it's always good to check again. – codenoob Apr 23 '21 at 20:30

1 Answers1

4

I've been running into the same problem as you, when using Capybara, and according to this question and this answer, the best alternative to this problem is using

expect(page).to have_content 'Success'

or just

page.should have_content

in-between any clicks that trigger Javascript. Both will wait the default_wait_time specified by Capybara (which can be changed with Capybara.default_wait_time = 5) to find the element you're looking for and THEN continue (note that if Capybara finds the element before the time is reached, it continues normally).

Still, as to the reason itself, I suspect the same thing as you: that adding that small delay allows the Capybara web driver to "wait" until the JS finishes executing to proceed normally.

As a final note, here's an article from the creator of Capybara, where (when talking about why he removed the wait_until command) he explains that using page.should have_content and such is the way to go. Also, here's another article explaining why this is the "best" solution, and the problems it solves.

Community
  • 1
  • 1
Squirrel
  • 392
  • 7
  • 15
  • 1
    click_link also has the waiting behavior, so it should wait for the link to be visible before clicking it - unless you have overridden the default behavior of ignoring invisible elements, or potentially if the element is shown via some sort of animation – Thomas Walpole Nov 23 '15 at 20:07
  • Capybara supposably finds the link, but it doesn't really click on it. So expect to have_content is passing and still nothing happens. – mork Nov 24 '15 at 08:15