Why Capybara cant find css? - capybara

I try to write simple feature spec, but I dont understand Capybara behavior. So, I have that code:
> parent.class
=> Capybara::Node::Element
> parent.find(:css, 'button.remove-arrow')
=> Capybara::ElementNotFound: Unable to find css "button.remove-arrow"
from /Users/weare138/.rvm/gems/ruby-2.3.3/gems/capybara-2.11.0/lib/capybara/node/finders.rb:44:in `block in find'
but when i try to do call via web-driver:
> parent.native.find(:css, 'button.remove-arrow')
it return me right answer
=> [#<Capybara::Poltergeist::Node tag="button" path="//HTML[1]/BODY[1]/DIV[1]/SECTION[1]/DIV[1]/FORM[1]/DIV[2]/DIV[2]/DIV[1]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/DIV[1]/DIV[1]/DIV[1]/BUTTON[1]">]
what I do wrong?

The most likely reason is that the node isn't actually visible on the page, which Capybara takes into account, but the driver doesn't. If
parent.find(:css, 'button.remove-arrow', visible: :false)
finds the element it would confirm that visibility is indeed the difference. If not then the actual HTML/CSS would be needed to know why.

Related

ElementNotVisibleError when using headless chrome for testing in rails

I test following assumption And I click on the text "2018/2019" within ".year" with capybara/headless_chrome and constantly get the error
element not visible
(Session info: headless chrome=67.0.3396.87)
(Driver info: chromedriver=2.40.565386 (45a059dc425e08165f9a10324bd1380cc13ca363),platform=Mac OS X 10.13.5 x86_64) (Selenium::WebDriver::Error::ElementNotVisibleError)
I've already tried to adjust the window size, as suggested here. But it didn't work.
My step definition:
When(/^(?:|I )click on the text "([^"]*)"(?: within "([^"]*)")?$/) do |link, selector|
begin
page.find(:css, selector).click
end
end
The element is actually visible and found by Capybara
[1] pry(#<Cucumber::Rails::World>)> page.find(:css, ".year")
=> #<Capybara::Node::Element tag="a" path="/html/body/div[2]/div[2]/section/div[2]/div/div[1]/div[1]/div[2]/div/div[2]/ul/li/a">
But click fails
[2] pry(#<Cucumber::Rails::World>)> page.find(:css, ".year").click
Selenium::WebDriver::Error::ElementNotVisibleError: element not visible
Why doesn't click work here?
EDIT:
The HAML of the link is
%ul.facet_values
- unselected.each do |facet_value|
%li.filtered{data: {hayf: {text: facet_value.name.downcase}}}
= link_to facet_value.path, title: facet_value.name, class: 'year' do
=truncate("#{facet_value.name}", length: 24)
- if facet.has_counts?
%span.small="(#{facet_value.count})"
I tried headless testing with Poltergeist and got Poltergeist detected another element with CSS selector 'html body header div.container-fluid' at this position which was solved with .trigger('click') and the test passed.
Since this doesn't work in non-headless Chrome or Poltergeist, then the simplest answer is that the element isn't actually visible. Firstly remove the Capybara.ignore_hidden_elements = false setting since that makes no sense when testing an app, and will screw up all sorts of waiting behaviors. Secondly use save_and_open_screenshot to get a picture of what the page actually looks like before you are trying to click the link.
I'm guessing you'll see that the link isn't actually visible at that point and your test is missing a step a user would have to do to make the link visible, is it in a menu where you have to hover over a different element first? is it in a popup where you have to click on something else first?, does it need to be scrolled to? etc.
Finally, you'll generally have less issues if you stick with Chrome via Selenium. Poltergeist uses PhantomJS which hasn't been updated in quite some time and doesn't support modern JS or CSS which can lead to all sorts of strangeness.

Capybara has_no_css? throws StaleElementReferenceError

I am using has_no_css? to verify if certain elements are no more visible in UI.
ex:- After clicking 'ok' on confirmation popup, popup should no more be visible in UI. To verify that we use
page.has_no_css?('.modal.dialog', visible: true)
Tests failing randomly at has_no_css? with Selenium::WebDriver::Error::StaleElementReferenceError: Element not found in the cache - perhaps the page has changed since it was looked up
I see people talking about this problem in few places(roughly few years old threads)..
https://github.com/jnicklas/capybara/issues/578 << Labeled as 'Waiting for response'
https://groups.google.com/forum/#!topic/ruby-capybara/O3Ib6INOP58
Currently I am catching this exception to overcome this issue.I would love to hear what are you folks who faced this issue doing/done ? Am I overlooking something and just blindly catching exception ?? suggestions please...
we are using capybara (2.3.0)

How to close all the windows before the next test in a test suite?

[7] pry(#<RSpec::Core::ExampleGroup::Nested_1>)> page.execute_script "window.close()"
Selenium::WebDriver::Error::NoSuchWindowError: Script execution failed. Script: window.close();
The window could not be found
[8] pry(#<RSpec::Core::ExampleGroup::Nested_1>)> page.driver.browser.window_handles
=> ["f1-2"]
I had a browser open with two tabs, the above command does close one but the last tab never closes. It is open but when I try to run page.execute_script "window.close()" it gives the above error.
page.driver.browser.window_handles.each do |handle|
page.driver.browser.switch_to.window(handle)
page.execute_script "window.close()"
end
The above code was working for me sometime back but doesnt work anymore. It gives the same error.
UPDATE:
When I use,
page.driver.browser.window_handles.each do |handle|
page.driver.browser.switch_to.window(handle)
page.driver.browser.close
end
it gives the following error Selenium::WebDriver::Error::UnknownError: 'auto_id' does not refer to an open tab
Two ways you can do it
In line with your technique using JS. You would first need to switch back to your first browser window (window_handle) and then perform "window.close()". (Not Preferred) (Not sure why its not working now for you, did you upgrade server version or different browser?)
Simply use #driver.quit (Preferred)
Update
Just write this once. This will close all windows.
after(:each) do
#driver.quit
end
If you want to close only one browser tab/window/popup, switch to that window_handle and then perform
#driver.close();
page.driver.browser.close closes current tab towards the end and the last (second) tab closes itself after each example.
in case if you are using cucumber, you can the use the BEFORE/AFTER hooks .please refer similar question on stackoverflow
for some more on cucumber,please refer this Cucumber Hooks

Rails + Capybara: clicking link with evaluate_script freezes webdriver

I run the following in my js: true request spec:
page.evaluate_script("$('#sign-up').click();")
That opens the modal successfully. However, the webdriver freezes at that point, regardless of what comes next in the spec. After a long pause, I get:
Failure/Error:
Timeout::Error:
Timeout::Error
# ./spec/requests/my_spec.rb:14:in `block (3 levels) in <top (required)>'
I want to use evaluate_script instead of 'click_on' in this case, because there is no href attribute on that particular link (click_on doesn't work). How do I get it to work without timing out?
It's due to a bug in Selenium. Found the answer here: https://groups.google.com/forum/?fromgroups=#!topic/ruby-capybara/YcZwyPdMJFU
It doesn't hang when replacing page.evaluate_script with:
page.driver.browser.execute_script

How do I confirm a javascript popup with Capybara?

I've tried several examples found online, but with no luck. I am looking to confirm the confirm message of a delete link. The last attempt was the code below, but that resulted in an Capybara::NotSupportedByDriverError error.
def confirm_dialog
page.evaluate_script('window.confirm = function() { return true; }')
end
Adding an answer for those hitting this in 2016 and beyond. You can now use Capybara directly to accept a confirmation box. You do this by wrapping the code that causes the confirmation box to appear in the accept_confirm function.
accept_confirm do
click_link 'Destroy'
end
First of all switch to using Selenium as the driver by putting an #javascript tag in front of your scenario.
The following code in your cucumber step will then confirm the dialogue:
page.driver.browser.switch_to.alert.accept
# or
page.driver.browser.switch_to.alert.dismiss
# or
page.driver.browser.switch_to.alert.text
As #NobbZ said, this question has been asked and answered before here: How to test a confirm dialog with Cucumber?.
More selenium documentation available here too: http://code.google.com/p/selenium/wiki/RubyBindings#JavaScript_dialogs
for capybara-webkit:
page.driver.browser.accept_js_confirms
page.driver.browser.reject_js_confirms
which is still working, but the documentation says also:
page.driver.accept_js_confirms!
page.driver.accept_js_confirms!
See https://github.com/thoughtbot/capybara-webkit , search "accept_js_confirms"
I've had timing issues with browser dialogs in a CI environment so I'm polling for a dialog before accepting it:
def accept_browser_dialog
wait = Selenium::WebDriver::Wait.new(:timeout => 30)
wait.until {
begin
page.driver.browser.switch_to.alert
true
rescue Selenium::WebDriver::Error::NoAlertPresentError
false
end
}
page.driver.browser.switch_to.alert.accept
end
I had to use a sleep in the webkit test since it would fail everynow and then otherwise.
Here is what I came up with after reading everyones posts:
if page.driver.class == Capybara::Selenium::Driver
page.driver.browser.switch_to.alert.accept
elsif page.driver.class == Capybara::Webkit::Driver
sleep 1 # prevent test from failing by waiting for popup
page.driver.browser.accept_js_confirms
else
raise "Unsupported driver"
end
try to add :js => true to your test.
RSpec’s metadata feature can be used to switch to a different driver.
Use :js => true to switch to the javascript driver, or provide a
:driver option to switch to one specific driver. For example:
it 'will use the default js driver' :js => true do
...
end
In Capybara its very simple to accept the model window. Even we can do the same in selenium but its little tough for people who are not aware about selenium.
page.accept_modal #This will accept the modal window
page.dismiss_modal #This will Reject/Dismiss the modal window
I would guess that you have to add selenium to your gem-file and configure it and capybara that capybara uses selenium as the driver.
I think also that How to test a confirm dialog with Cucumber? is very similar to your question, especially the accepted answer.

Resources