After loading a page I have code that runs and hides and shows various items based on data returned by an xhr.
My integration test looks something like this:
it "should not show the blah" do
page.find('#blah').visible?.should be_true
end
When I manually go to the page in the context this test runs, #blah is not visible as I expect. I suspect that Capybara is looking at the initial state of the page (invisible in this case), evaluating the state of the DOM and failing the test before the JS runs.
Yes, I set the :js => true
on the containing describe block :)
Any ideas would be greatly appreciated! I'm hoping I don't have to put an intentional delay in here, that feels flaky and will slow things down.
What visible means is not obvious
The failure may come from a misunderstanding of what is considered visible or not as it is non-obvious, not driver portable, and under-documented. Some tests:
HTML:
The only thing Rack test considers as invisible is inline
display: none
(not internal CSS since it does not do selectors):Poltergeist has a similar behavior, but it can deal with internal CSS and Js
style.display
manipulation:Selenium behaves quite differently: if considers an empty element invisible and
visibility-hidden
as well asdisplay: none
:Another common catch is the default value of
visible
:false
(sees both visible and invisible elements),true
Capybara.ignore_hidden_elements
option.Reference.
Full runnable test on my GitHub.
You might want to look at this post, which gives a sample method for waiting until all ajax requests are complete:
The other answers on here are the best way to "wait" for the element. However I have found this didn't work for the site I am working on. Basically the element that needed clicking was visible before the function behind that was fully loaded. This is in fractions of a second but I found my test ran so quick on occasion that it clicked the button and nothing happened. I managed to work around it by doing this make-shift boolean expression:
Basically it uses the capybara default wait time to look for something that should appear, if it isnt there it will retry your click.
Again I will say that the
should have_selector
method should be tried first but if it just wont work try thisI think that the
find
statement here is the one with the implicit wait, so Capybara will wait until the element is on the page, but won't wait for it to become visible.Here, you would want Capybara to wait for the visible element to appear, which should be achievable by specifying the
visible
option:I haven't tried it, but the
ignore_hidden_elements
configuration option might be useful here as well, if you wantedfind
to always wait for visible elements.If you want to check that an element is on the page but is not visible,
visible: false
won't work as you might expect. Had me stumped for a bit.Here's how to do it:
The accepted answer is a bit outdated now as 'should' is deprecated syntax. These days you'd be better off doing something along the lines of
expect(page).not_to have_css('#blah', visible: :hidden)