I'm learning Ruby and using Watir to create a coupon clipping project. I'm having trouble looping through the process though - ruby

I'm trying to write a script in Ruby that will automatically clip coupons on a webpage for me. This page being:
Stop and Shop Coupons Page
What I have so far will open the browser (Firefox) and go to the coupons page on my account, but will only click one coupon and then the script closes. I've tried while loops, I've tried exists? and everything I could find online and I can't get it to clip continuously for all instances of the button '+ load to card'.
I wrote a script for the Publix website a while ago using the site:
Publix Coupon Page
and it worked just fine. To "clip" I just used:
b.buttons(:class => 'dc-clip-btn').each do |b|
b.click
sleep 2
end
I needed the "sleep" because sometimes the page would hang on the clip and the script would close. When I tried this same on the Stop & Shop page, it didn't work at all. I had to change 'button' to 'link' and ':class' to ':text' to even get it to clip one.
require 'rubygems'
require 'watir'
require 'watir-webdriver'
b = Watir::Browser.new :firefox, :profile => 'default'
b.goto 'https://stopandshop.com/dashboard/coupons-deals/#/coupons-and-deals/exclusive-coupons'
l = b.link :text => '+ load to card'
sleep 3
l.when_present.click
I've tried
l.exists?
l.click
Which will only work on one instance. I've trued the when_present as shown above. I've even used a while loop to "do" l.click. I've exhausted my resources at this point, as well as my patience. Any help is greatly appreciate. Thank you!
EDIT:
I've found that if I include :index => 1 at the end of the line
l = b.link :text => '+ load to card', :index => 1
then it will navigate to that specific spot in the array and click that link. So, I guess at this point I need help trying to get it to traverse the array and click all of those links.
EDIT 2: I was hoping to be able to post whether the suggestions worked, however I started running into an issue suddenly where when the site loads, I'm logged in as usual but then suddenly it logs me out for no reason and redirects to
https://stopandshop.com/?DPSLogout=true
EDIT 3: The Edit 2 issue was fixed. It was a permissions/cookies issue in my browser. However, none of the suggestions are working.
SOLUTION
while l.exists? do
l.click
l = b.link :text => '+ load to card', :index => 0+1
end

You should be able to iterate through the links like so:
coupons = b.links(text: '+ load to card')
coupons.each do |coupon|
coupon.click
end

Related

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 Webdriver - Need to wait / sleep while page redirects (refreshes)

I'm using the Ruby selenium-webdriver gem to create a web-crawling/scraping script. The page that I'm scraping is loaded via AJAX and displays information for a certain account. If you select a second account number on a dropdown menu, the page redirects very briefly to another URL and back to the original URL, just with different information loaded via AJAX. I want to be able to scrape info for both the account numbers listed on the dropdown options. The problem is that Selenium performs the scrape faster than the page can redirect/reload on the dropdown click, so I don't end up getting the second account's information.
def crawl_page
browser = Selenium::WebDriver.for :firefox
browser.manage.timeouts.implicit_wait = 10 # seconds
browser.navigate.to 'http://www.foobar.com'
account_dropdown = Selenium::WebDriver::Support::Select.new(browser.find_element(:id, 'account'))
account_dropdown.options.each do |option|
option.click
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
# this wait is not working because option is selected before redirect/refresh:
wait.until { option.selected? }
html = browser.page_source
scrape_page(html)
end
browser.quit
end
I've tried putting a sleep(3) on the line after the click, but get the following error message:
[remote server] resource://fxdriver/modules/web_element_cache.js:8180:in `fxdriver.cache.getElementAt': Element not found in the cache - perhaps the page has changed since it was looked up (Selenium::WebDriver::Error::StaleElementReferenceError)
I've also tried using Selenium's explicit wait code, but the ids of the elements appear to dynamically change on the updated page so something like:
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
wait.until { browser.find_element(:id, 'titlexyz').displayed? }
results in an error message that says it's timed out and can't find the element:
~lib/selenium/webdriver/common/wait.rb:57:in `until': timed out after 10 seconds (Unable to locate element: {"method":"id","selector":"titlexyz"}) (Selenium::WebDriver::Error::TimeOutError)
Is there some way to get it to sleep or wait without having to look for a specific element on the page?
OK, so I finally figured it out thanks to SiKing's answer. The trick was to count the number of options for the dropdown menu, and put that into a .times loop. Then on each iteration, I instantiated a new Selenium object for the dropdown menu, found the correct option number and clicked it. I also put the script to sleep for 5 seconds to give it a chance to do the reload/redirect.
def crawl_page
browser = Selenium::WebDriver.for :firefox
browser.navigate.to 'http://www.foobar.com'
account_dropdown = Selenium::WebDriver::Support::Select.new(browser.find_element(:id, 'account'))
count = account_dropdown.options.count
count.times do |option_num|
account_dropdown = Selenium::WebDriver::Support::Select.new(browser.find_element(:id, 'account'))
account_dropdown.options[option_num].click
sleep 5
html = browser.page_source
scrape_page(html)
end
browser.quit
end
I do not do ruby, so I cannot help you with the ruby syntax.
Every time a page reloads (in your code every time you do option.click), all WebElements (your account_dropdown.find_elements(:css, 'option')) that you have are no longer valid! You will have to base your loop on something else - perhaps the count of the items in the pulldown - and find each of the elements you want to interact with inside the loop!

Ruby interface Shoes and auto testing tool Watir

I installed and used Watir to do auto testing for my web pages successfully. After this, I tried to create a Shoes interface for my testing code. I want to click on a button and then run my Watir testing code.
My testing code works if I run it in terminal. However, it stops at the step "require 'watir-webdriver'" if I involve Shoes. So, I can see the alerted 1 and 2, but never 3 and nothing after. My code is here:
Shoes.app do
def xxxx(from, to)
alert "1"
puts "my message abcdefg"
alert "2"
require 'watir-webdriver'
alert "3"
browser = Watir::Browser.new
browser.goto 'http://my.page.url.......'
alert "4"
# login
browser.link(:text => 'Login').click
browser.text_field(:id => 'username').set 'xxxx'
browser.text_field(:id => 'password').set 'yyyy'
browser.button(:text => 'Login').click
# some other staff... nothing wrong here
browser.close()
end
# build the interface
#s = stack :width=>200, do
username = edit_line
password = edit_line
button "Login" do
xxxx(1, 2) # just call the function
end
end
#left=(#s.parent.width-#s.style[:width])/2
#s.move(#left,0)
end
Am I using Shoes wrong? I don't get any error at all, but it just stopped. What other interface would you suggest? I need an interface to let the user load a txt file and then perform the testing based on the information in the file.
Thanks a lot.
Well, shoes won't load watir-webdriver and shoes4 has this issue 'Unable to activate selenium-webdriver-2.42.0, because rubyzip-0.9.9 conflicts with rubyzip (~> 1.0)'...
No solution so far...

ruby watir-webdriver hover error

SOLUTION: I downgraded Firefox to version 27.01 and my test is now working again. Firefox 28.0 may have some native mouse move problems. I was receiving the same error when trying Richard's suggestions below.
PROBLEM:
I have some basic code that was working last week but now it is not working. Not sure if my Firefox updated and is causing the issue or if this is bad programming and should not be done either way.
Here is part of my code.
require 'watir-webdriver'
require 'watir-webdriver/extensions/select_text'
require 'tiny_tds'
browser = Watir::Browser.new :firefox
browser.goto "http://localhost:42706/playerAddEdit/Create"
def self.createNewPlayer(playerInfo, browser)
printf("%s3 createNewPlayer\n", playerInfo)
playerInfo.each do |line|
info = line.split(/,/)
browser.text_field(:name => 'FName').set info[0]
browser.text_field(:name => 'LName').set info[1]
browser.text_field(:name => 'Handicap').set info[2]
browser.button(:id => 'submit').hover
browser.button(:id => 'submit').click
browser.a(:text => "Create New").wait_until_present
browser.a(:text => "Create New").click
browser.input(:id => 'FName').wait_until_present
end
end
The error occurs on the "browser.button(:id => 'submit').hover" line of code, which was working.
The error generated is partially:
Selenium::WebDriver::Error::InvalidElementStateError: Cannot perform native interaction: Could not load native events component.
My questions are why would it stop working and is it bad practice to do this? I got in the habit of using hover when I was testing some dropdown's and it helped out. (If I comment out the .hover line everything works fine.)
I think you can replace the hover line with this:
browser.action.move_to(browser.find_element(:id => "submit")).perform
Or replace the two lines with this:
browser.action.move_to(browser.find_element(:id => "submit")).click().perform

Clicking group of links in watir

I am new to ruby, and I am trying to work with watir. I think I got the basics, but I am having trouble clicking all links whose id matches a regex. I tried this;
require "watir-webdriver"
browser = Watir::Browser.new :ff
browser.goto "http://mysite.com"
browser.links(:id, /asd[0-7]/).each do |adv|
adv.click
sleep 1
end
But it doesn't seem to be clicking the links. I am doing something wrong here? Links are opening in new windows, so looping through them is no problem. But I couldn't make the loop work.
This kind of investigation is better in IRB. Anyway, you should validate that you have links to click.
require "watir-webdriver"
browser = Watir::Browser.new :ff
browser.goto "https://rvm.io/"
links = browser.links(:href => /gemsets/)
links.count
I changed mine up to use a site I can access and has links.

Resources