Cannot find link using Capybara and Rspec while writing an integration test - ruby

I am trying to find a link by CSS classes and ids but always getting an error: Capybara::ElementNotFound: Unable to find css ...
The actual piece of code is:
find('#bucket_resources_containers > #user_base_widget.widget >
div.widget_header > div.right.may-
edit.control.button.add.icon.add_options > a.tasksy.options').click
The page source is: enter image description here

You gave us the answer in your comment, the element was not visible.
Short answer: find_link(selector, visible: :all).click
As capybara shows in the documentation:
By default Capybara will only locate visible elements. This is because a real user would not be able to interact with non-visible elements.
Only locate visible elements is an smart design of capybara, it avoids thinking that a user would be able to find the element.
The find_link method documentation doesn't help much when finding for hidden links because it only show these options: wait, href, id, title, alt, class:
#find_link([locator], options = {}) ⇒ Capybara::Node::Element
But you see on the finding documentation there was a visible option:
find_link('Hello', :visible => :all).visible?
find_link(class: ['some_class', 'some_other_class'], :visible => :all).visible?
This option visible comes from #all method, where you can see here. It can have these values:
true - only finds visible elements.
false - finds invisible and visible elements.
:all - same as false; finds visible and invisible elements.
:hidden - only finds invisible elements.
:visible - same as true; only finds visible elements.
So, in your case, you could use visible: false, if you really mean it to be hidden, or visible: :all if you don't care about the visibility.

Related

How to check for visibility if the class exists in capybara?

With capybara and minitest, how would you check for visibility of a element if the element exists on the page? The class isn't always guaranteed to be there, so I need to check if it is on the page first.
All I can think of is:
assert find(".class-name").visible? if has_css?(".class-name", :wait=>0)
Are there any other ways of doing this?
By default Capybara only finds visible elements, so
if has_css?(".class-name", wait: 0)
will only return true if the element is visible on the page
If you want to verify the element is either not on the page, or if it is in the source of the page it must be visible then you could do something like
assert_css('.class-name') if has_css?('.class-name', visible: :all)
or just
refute_css('.class-name', visible: :hidden) # ensure there is no non-visible element with the class name

How to find a css element on the page if it is display: none?

I'm running automated testing in Ruby.
I'm trying to write a script that finds id with display:none (visible only in mobile form), and clicks it.
Here is my code:
def open_menu
page.find[:css, "a[id='mobile-nav-link']", visible: false].click
end
It gives me an error:
Selenium::WebDriver::Error::InvalidSelectorError:
invalid selector: No selector specified
A quick search reveals similar code using round brackets, not square. I.e.:
def open_menu
page.find(:css, "a[id='mobile-nav-link']", visible: false).click
end
Selenium only interacts with elements the way a user would.
If the link is only visible in mobile, I would suggest one of the following.
View the page via the mobile URL.
It's possible that you may be able to use Ruby's javascript execute to either update the control to be visible, or set the value that indicates you are viewing the page via a mobile device.
Updating the control to be visible
This link discusses how to set an element to visible using javascript execute: Selenium Webdriver - click on hidden elements
This link discusses how to use ruby's javascript execute: How to execute Javascript in Ruby written Webdriver test?
Put the two together, and you get something like this?
def open_menu
elem = page.find[:css, "a[id='mobile-nav-link']", visible: false]
js = "arguments[0].style.height='auto' arguments[0].style.visibility='visible';"
driver.execute_script(js , elem)
page.find[:css, "a[id='mobile-nav-link']", visible: true].click
end
I'm not entirely familiar with Ruby syntax, so I make no guarantees it will work copy/paste.

I can not locate proper element - click on link Ruby

I tried to click on link (see screenshots)
http://imgur.com/q66g7z6
http://imgur.com/KNF1y7z
I tried using few examples
e.g
#browser.button(:class=> '//*[#class="login"]//ul/li[0]/a').click
and
browser.button(:xpath=> "//a[#data-viewmodel='PagesAsync/RegisterPrivate/RegisterPrivateViewModel']").click
but is not correct
I can see the message that unable to locate element
Can somebody help?
The main problem is that you are telling Watir to look for a button when you actually want a link. While the UI may be styled to look like a button, you will notice that the HTML has a a tag instead.
The first example, which also has the wrong locator type, should be:
#browser.link(:xpath => '//*[#class="login"]//ul/li[0]/a').click
The second example should be:
browser.link(:xpath => "//a[#data-viewmodel='PagesAsync/RegisterPrivate/RegisterPrivateViewModel']").click
Note that the second example would be more Watir-like if you use the normal attribute locators:
browser.link(data_viewmodel: 'PagesAsync/RegisterPrivate/RegisterPrivateViewModel').click
There are two options. One is get your developers to add better IDs.
If that is not possible, try this:
how does ruby webdriver get element with hyphen in <name, value> pair
It worked for me in several similar situations.
I wonder how you can find a button by using an xpath to a link. It is also not clear whether you use browser or #browser. You would need to look into how the browser instance is defined, which likely is one of these:
#browser = Watir::Browser.new :chrome
###or###
browser = Watir::Browser.start 'example.com', :firefox
and if you haven't create a browser instance, then you would need to do it before you can use Watir-Webdriver. ;)
As for your question, you could try searching using the text if it is unique like this, though it may be a brittle test:
#browser.div(:class => 'login').link(:text => /For priva/).click
but I would recommend to double check the number of elements found using the div and link locators like this to make sure you got the right element:
#browser.divs(:class => 'login').length
#browser.div(:class => 'login').links(:text => /For priva/).length

Watir-webdriver throws 'not clickable' error even when element is visible, present

I am trying to automate tests in Ruby using the latest Watir-Webdriver 0.9.1, Selenium-Webdriver 2.53.0 and Chrome extension 2.21. However the website that I am testing has static headers at the top or sometimes static footers at the bottom. Hence since Watir auto-scrolls an element into view before clicking, the elements get hidden under the static header or the static footer. I do not want to set desired_capabitlites (ElementScrollBehavior) to 1 or 0 as the websites I am testing can have both - static header or static footer or both.
Hence the question are:
1) Why does Watir throw an exception Element not clickable even when the element is visible and present? See ruby code ( I have picked a random company website for an example) and the results below.
2) How can I resolve this without resorting to ElementScrollBehaviour?
Ruby code:
require 'watir-webdriver'
browser = Watir::Browser.new :chrome
begin
# Step 1
browser.goto "shop.coles.com.au/online/mobile/national"
# Step 2 - click on 'Full Website' link at the bottom
link = browser.link(text: "Full website")
#check if link exists, present and visible?
puts link.exists?
puts link.present?
puts link.visible?
#click on link
link.click
rescue => e
puts e.inspect
ensure
sleep 5
end
puts browser.url
browser.close
Result:
$ ruby link_not_clickable.rb
true
true
true
Selenium::WebDriver::Error::UnknownError: unknown error: Element is not clickable at point (460, 1295). Other element would receive the click: div class="shoppingFooter"...div
(Session info: chrome=50.0.2661.75)
(Driver info: chromedriver=2.21.371459 (36d3d07f660ff2bc1bf28a75d1cdabed0983e7c4),platform=Mac OS X 10.10.5 x86_64)>
http://shop.coles.com.au/online/mobile/national
thanks!
You can do a click at any element without getting it visible. Check this out:
link.fire_event('click')
BUT It is very very very not good decision as far as it will click the element even if it is not actually visible or in case when it is just impossible to click it (because of broken sticky footer for example).
That's why much better to wait the fooler, scroll the page and then click like:
browser.div(id: "footerMessageArea").wait_until_present
browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
link.click
The sticky footer is blocking webdriver from performing the click, hence the message that says 'other element would receive the click'.
There are several different ways you can get around this.
Scroll down to the bottom of the page before the click
Hide/Delete the sticky footer before any/all link clicks
Focus on an element below the element you want to click before you perform the click
I Guess your element is visible in the screen.
Before clicking on the element first you have to scroll the webpage so that element is visible then perform the click. Hope it should work.
I had similar issue,
I just used following javascript code with watir:
link = browser.link(text: "Full website")
#browser.execute_script("arguments[0].focus(); arguments[0].click();", link)
Sometimes I have to use .click! which i believe is the fire_event equivalent. Basically something is layered weird, and you just have to go around the front end mess.

SitePrism: sometimes find elements, sometimes doesn't while Capabara can

I am using Capybara and Selenium for testing my website. I also use with Site Prism for Page Object model. I can make every thing work now, however, I don't understand why sometimes actions with page elements donot work, while using "natively" Capybara work.
For example, I have a Page object:
class MyPage < SitePrism::Page
element :sign_in_link, :css, 'a.signin-link'
element :join_link, :css, "a.join-link"
end
and its implementation:
#mypage = MyPage.new
#mypage.sign_in_link.click
# It works at first, then after some repeated test round, it doesn't work sometimes, with error: NoMethodError <br>
While I use:
find(:css, 'a.signin-link').click #=> always work, but not Page Object model
So, why it happens? Have anyone experienced this problem?
By default site_prism disables Capybaras implicit waiting behavior while finding elements. This means to have the same behavior as your capybara example you would need to do
#mypage = MyPage.new
#mypage.wait_for_sign_in_link
#mypage.sign_in_link.click
You can read more about this in the site_prism README under "Using Capybara Implicit Waits"
Another options is to use site prisms "Load Validations" feature to ensure pages are loaded before starting to click on their elements

Resources