Iterate over links' array with Capybara - ruby

I'm trying to take a screenshot of the last three links found on a menu of a page.
all('.menu-left a').last(3).each do |e|
txt = e.text
puts txt
e.click
puts "clicked!"
page.save_screenshot(txt + ".png")
page.evaluate_script('window.history.back()')
end
Unfortunately I get:
/usr/local/lib/ruby/gems/2.0.0/gems/capybara-webkit-1.0.0/lib/capybara/webkit/node.rb:132:in `invoke': Capybara::Webkit::NodeNotAttachedError (Capybara::Webkit::NodeNotAttachedError)
from /usr/local/lib/ruby/gems/2.0.0/gems/capybara-webkit-1.0.0/lib/capybara/webkit/node.rb:4:in `visible_text'
from /usr/local/lib/ruby/gems/2.0.0/gems/capybara-2.2.0/lib/capybara/node/element.rb:61:in `block in text'
from /usr/local/lib/ruby/gems/2.0.0/gems/capybara-2.2.0/lib/capybara/node/base.rb:81:in `synchronize'
from /usr/local/lib/ruby/gems/2.0.0/gems/capybara-2.2.0/lib/capybara/node/element.rb:57:in `text'
How can I iterate over the links' array, click on it, take the screenshot, go back and repeat?

By clicking a link (causing page change), the references to the elements become invalid.
Save the href attributes somewhere and visit them instead of clicking elements. (If the elements are a tags).
If the clicking elements cause javascript code executed, you need to re-evaluate the css selectors to get elements again.

Related

watir element click intercepted:

I'm trying to click on a button that contains the words "Add To Cart" using ruby/watir.
If I use
cart = browser.link(text: 'Add To Cart')
if cart.present?
cart.click
It works (item gets added to cart) but I get a element click intercepted: Element ... is not clickable at point (441, 20). Other element would receive the click: (Selenium::WebDriver::Error::ElementClickInterceptedError
I'm new to ruby/watir so any help would be greatly appreciated.
Try this code whether it works. If it's not working then as you have stated, even after the error, it works, So I assume we have to issue the click on the element which is overlaying the target element. So Paste the entire error message. The error message must contain the element which is actually obscuring.
require 'watir'
b = Watir::Browser.new
cart = browser.link(text: 'Add To Cart')
if cart.present?
b.wait_while { cart.obscured? }
cart.click
end
Update
Okay, there are other two ways you have to try.
One is to use JavaScript.
cart.click!
Or click the element which is overlaying your element.From your error the element is division with class attribute 'row'. If you have more detail about that element, you can locate that element by yourself. But now, with the given detail, I form the locator.
b.div(class: 'row').click
there are few ways you can figure what is going on
try looking around the element
check if watir sees more than one link, this should produce 1
browser.as(text: 'Add To Cart').count
then try to click every element if it has more than 1
browser.as(text: 'Add To Cart')[0].click
browser.as(text: 'Add To Cart')[1].click
or try to click its parent, link can be behind overlay
browser.a(text: 'Add To Cart').parent.click
then check if same can be acomplished by clicking parent element directly
browser.div(class: 'wishlist_cart_button').click
or you can try with different approach, find element by some other attribute
browser.a(href: /setCurrentId/).click
also maybe there is a parent element with id so you can find the cart button easier
browser.element(id: "asdf").a(text: "Add To Cart").click
browser.element(id: "asdf").as.last.click
if everything above fails, then click it with selenium, since watir is worried about click being intercepted
browser.driver.action.move_to(browser.a(text: 'Add To Cart').wd).click.perform
hope something helps :D

How to iterate with more than one element on the page

I have several buttons to click on the same page. How do I iterate and click on each of them?
def btnConectar()
elements = all("button[data-control-name='srp_profile_actions']").count
puts elements
first("button[data-control-name='srp_profile_actions']").click
find("section[class=modal]")
find("button[class='button-primary-large ml1']").click
end
all returns an Array like Capybara::Result object. You can iterate through that using the standard ruby enumerable methods.
all("button[data-control-name='srp_profile_actions']").each do |el|
el.click
find("section[class=modal]") # Not sure what this is for - if it's an expectation/assertion it should be written as such
click_button(class: %w(button-primary-large ml1)
end
That will work as long as clicking on the button doesn't cause the browser to move to another page.
If clicking does cause the browser to move to another page then all the rest of the elements in the Capybara::Result object will become stale (resulting in a stale element reference error on the next iteration) and you won't be able to iterate any more. If that is your case then details on what exactly you're doing will be necessary. Questions like does the original button still exist on the page after clicking the button-primary-large button, or can you iterate by just clicking the first matching button over and over? If it does still exist is it changed in any way to indicate it's already been clicked, or is the number/order of buttons on the page guaranteed to be stable? It would probably help to understand if you posted a fragment of the HTML for the first and second iteration.
def btnConectar()
page.all("button[data-control-name='srp_profile_actions']").each do |el|
while page.has_css?("button[data-control-name='srp_profile_actions']")
el.click #Click the button
find("section[class=modal]") #Modal mapping
click_button(class: %w(button-primary-large ml1)) #Click the button
sleep 3
end
end
end

Ruby Watir -- Trying to loop through links in cnn.com and click each one of them

I have created this method to loop through the links in a certain div in the web site. My porpose of the method Is to collect the links insert them in an array then click each one of them.
require 'watir-webdriver'
require 'watir-webdriver/wait'
site = Watir::Browser.new :chrome
url = "http://www.cnn.com/"
site.goto url
box = Array.new
container = site.div(class: "column zn__column--idx-1")
wanted_links = container.links
box << wanted_links
wanted_links.each do |link|
link.click
site.goto url
site.div(id: "nav__plain-header").wait_until_present
end
site.close
So far it seems like I am only able to click on the first link then I get an error message stating this:
unable to locate element, using {:element=>#<Selenium::WebDriver::Element:0x634e0a5400fdfade id="0.06177683611003881-3">} (Watir::Exception::UnknownObjectException)
I am very new to ruby. I appreciate any help. Thank you.
The problem is that once you navigate to another page, all of the element references (ie those in wanted_links) become stale. Even if you return to the same page, Watir/Selenium does not know it is the same page and does not know where the stored elements are.
If you are going to navigate away, you need to collect all of the data you need first. In this case, you just need the href values.
# Collect the href of each link
wanted_links = container.links.map(&:href)
# You have each page URL, so you can navigate directly without returning to the homepage
wanted_links.each do |link|
site.goto url
end
In the event that the links do not directly navigate to a page (eg they execute JavaScript when clicked), you will need to collect enough data to re-locate the elements later. What you use as the locator will depend on what is known to be static/unique. As an example, I will assume that the link text is a good locator.
# Collect the text of each link
wanted_links = container.links.map(&:text)
# Iterate through the links
wanted_links.each do |link_text|
container = site.div(class: "column zn__column--idx-1")
container.link(text: link_text).click
site.back
end

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.

Ruby: Selenium: Webpage has strange page behavior for list, want to loop through each link in list

So I have the following code:
list = [#array of xpaths pointing to each of the 41 links]
begin
list.each do |entry|
wait.until {browser.find_element(xpath: entry)}
browser.find_element(xpath: entry).click
... #do what needs to be done inside link
browser.find_element(xpath: #location of back button) #goes back to list
end
wait.until{browser.find_element(css: ".next>a")}
browser.find_element(css: ".next>a").click
# ^ clicks the next button to get to next page
sleep 2
end while browser.find_element(class_name: "next").displayed?
# ^ end when there is no next button because were on the last page.
I am looping through each link on the page, doing what I need to do with it, and returning to the list. When all 41 links have been hit on the page, I tell it to load the next page. The issue is that for some reason going back to the list always goes back to the first page. So if I am on the third page and I click the link, do what I have to do, and return to the list I am back on the first page of the list. Anyone have an ideas on how to deal with this?

Resources