ruby watir-webdriver hover error - ruby

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

Related

WATIR: Is there a reason why browser scrolling won't work?

I'm trying to use browser.scroll.to :bottom but nothing happens.
I know that it works because I've tried it on public facing sites such as the BBC and Wikipedia, but for some reason, these scroll commands don't work on our in-house browser based app.
Does anyone know of any reasons or settings that could be preventing this from happening?
Things such as browser.refresh and browser.window.maximize work fine but the scrolling literally refuses to budge.
Here's what my code looks like:
require 'watir'
require_relative 'regression_config_bob01.rb'
require 'date'
require 'faker'
require 'slack-notifier'
require 'watir-scroll'
user_name = "blah"
password = "blah"
test_env = "the Site"
browser = Watir::Browser.new
browser.goto(test_env)
# Login
browser.text_field(:name => 'P101_USERNAME').set user_name
browser.text_field(:tabindex=> '2').set password
browser.link(:text => "Log in").click
sleep 20
browser.wd.action.scroll_by(0, 1000).perform # Suggested Scroll line
print "done"
sleep 30
temporary_exp.rb:62:in <main>': undefined method scroll_by' for #<Selenium::WebDriver::W3CActionBuilder:0x000000014ac54bd0 #bridge=#<Selenium::WebDriver::Remote::W3C::Bridge:0x000000014ac1e440 #capabilities=#<Selenium::WebDriver::Remote::W3C::Capabilities:0x000000014ac1e940 #capabilities={:proxy=>nil, :browser_name=>"chrome", :browser_version=>"106.0.5249.119", :platform_name=>"mac os x", :accept_insecure_certs=>false, :page_load_strategy=>"normal", :implicit_timeout=>0, :page_load_timeout=>300000, :script_timeout=>30000, :remote_session_id=>nil, :accessibility_checks=>nil, :profile=>nil, :rotatable=>nil, :device=>nil, "chrome"=>{"chromedriverVersion"=>"105.0.5195.52 (412c95e518836d8a7d97250d62b29c2ae6a26a85-refs/branch-heads/5195#{#853})", "userDataDir"=>"/var/folders/hb/h_0h2t79183fkkppsr6r19nc0000gn/T/.com.google.Chrome.BV85VD"}, "goog:chromeOptions"=>{"debuggerAddress"=>"localhost:50818"}, "networkConnectionEnabled"=>false, "setWindowRect"=>true, "strictFileInteractability"=>false, "unhandledPromptBehavior"=>"dismiss and notify", "webauthn:extension:credBlob"=>true, "webauthn:extension:largeBlob"=>true, "webauthn:virtualAuthenticators"=>true}>, #session_id="8c59128dd44054681f62819d2fed25cf", #http=#<Watir::HttpClient:0x000000014ab6e298 #open_timeout=60, #read_timeout=nil, #server_url=#<URI::HTTP http://127.0.0.1:9515/>, #proxy=nil, #http=#<Net::HTTP 127.0.0.1:9515 open=true>>, #file_detector=nil, #escaper=#URI::RFC2396_Parser:0x000000014b0cbbc8, #manage=#<Selenium::WebDriver::W3CManager:0x000000014ab640b8 #bridge=#<Selenium::WebDriver::Remote::W3C::Bridge:0x000000014ac1e440 ...>, #window=#<Selenium::WebDriver::Window:0x000000014aa17ca0 #bridge=#<Selenium::WebDriver::Remote::W3C::Bridge:0x000000014ac1e440 ...>>>>, #devices=[#<Selenium::WebDriver::Interactions::PointerInput:0x000000014ac54f40 #name="mouse", #actions=[], #kind=:mouse>, #<Selenium::WebDriver::Interactions::KeyInput:0x000000014ac54d38 #name="keyboard", #actions=[]>], #async=false> (NoMethodError)
The current scroll implementation is using javascript to move the page around. For some reason your app is not responding to the JS commands in the normal way.
Selenium has recently released native scrolling via the drivers that Watir has not yet been updated. Take a look at the Selenium documentation on it: https://www.selenium.dev/documentation/webdriver/actions_api/wheel/?language=ruby
To use this in watir, you just need to add the line to the top: driver = browser.wd
So to scroll down by 2000 pixels, you can do:
driver = browser.wd
driver.action
.scroll_by(0, 2000)
.perform
like Titus said, Watir is a wrapper for Selenium and lets you write shorter and prettier code, like
browser.scroll.to :bottom
browser.scroll.to :top
browser.element(id: "asd").scroll.to
but when (for any reason) it doesn't work you can use Selenium syntax directly by sending commands to browser.wd instead browser like this:
browser.wd.action.scroll_by(0, 1000).perform #this scrolls bottom
browser.wd.action.scroll_by(0, -1000).perform #this scrolls top
browser.wd.action.scroll_to(browser.wd.find_element(id: "asd")).perform
but instead of writing browser.wd every time you need to talk to driver directly, you can type driver = browser.wd so your code is more clear:
driver = browser.wd
driver.action.scroll_by(0, 1000).perform #this scrolls bottom
driver.action.scroll_by(0, -1000).perform #this scrolls top
some_element = driver.find_element(id: "asd")
driver.action.scroll_to(some_element).perform
There are countless examples where using Watir is more efficient than talking to driver directly, you just happened to encounter an edge case.
Also try avoiding sleep when possible, instead, wait for something to show, like:
browser.element(id: 'asd').wait_until(&:present?)
browser.element(id: 'asd').wait_until({ |el| el.text == "Success" })
some_element = browser.element(id: 'asd')
browser.wait_until(30){some_element.present?}
Instead of .element you can use correct subclass like .div, .button, .span etc

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

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

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...

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.

How do you get window titles, ids, and names in selenium-webdriver?

Im trying to implement the following methods from selenium-webdriver (ruby)
get_all_window_ids
get_all_window_titles
get_all_window_names
I ran Selenium IDE and exported my script to Ruby Test::Unit. Saved it as .rb
Opened my script for editing using Aptana Studio 3
Initial code snippet as follows:
require "rubygems"
require "selenium-webdriver"
require "test/unit"
class SwitchToPopup3 < Test::Unit::TestCase
def setup
#driver = Selenium::WebDriver.for :firefox
#base_url = (URL of my test website)
#driver.manage.timeouts.implicit_wait = 30
#verification_errors = []
end
def teardown
#driver.quit
assert_equal [], #verification_errors
end
def test_switch_to_popup3
.
.
puts #driver.get_all_window_ids()
puts #driver.get_all_window_titles()
puts #driver.get_all_window_names()
.
.
end
The error I keep getting is
NoMethodError: undefined method `get_all_window_ids' for # <Selenium::WebDriver::Driver:0x101e4b040 browser=:chrome>
/Users/rsucgang/Documents/Aptana Studio 3 Workspace/Testing/SwitchToPopup2.rb:37:in `test_switch_to_popup3'
I've studied the documentation for the ruby bindings for selenium-webdriver
http://selenium.googlecode.com/svn/trunk/docs/api/rb/Selenium/Client/GeneratedDriver.html#get_all_window_titles-instance_method
Ultimately my goal here is to run my automation script:
Click on a link that opens a new window with target=_blank and no windowID available (does not implement JS)
Identify the names of all opened windows in the browser
switch to a new pop-up window using the switchToWindow(name) method
continue running my script on that pop-up window
I've googled and researched this on the internet and I have not gotten any much information.
Thanks and please let me know if you need more information.
OSL Mac OSX 10.7.3
Ruby: ruby 1.8.7 (2010-01-10 patchlevel 249) [universal-darwin11.0]
Browser: Firefox 9.0.1 (Mac)
Chrome: Chrome 17.0.963.79 (Mac)
Selenium-Server: Ruby gem 2.20.0
Justin, you have a good approach. But there is a gotcha in assuming that the window handles will return in the correct order. This isn't always the case across all browsers. I outline a slightly different approach in my free weekly Selenium tip newsletter (elemental-selenium.com).
It goes like this:
#driver.get 'http://the-internet.herokuapp.com/windows'
main_window = #driver.window_handle
#driver.find_element(css: '.example a').click
windows = #driver.window_handles
windows.each do |window|
if main_window != window
#new_window = window
end
end
#driver.switch_to.window(main_window)
#driver.title.should_not =~ /New Window/
#driver.switch_to.window(#new_window)
#driver.title.should =~ /New Window/
You can see the full tip here.
The problem is that the get_all_window_ids is for Selenium::Client rather than Selenium::Webdriver. I believe that Selenium::Client is the old version Selenium and the API is not the same as Selenium::Webdriver (see here). Since you are using Selenium::Webdriver, this explains why you get an 'undefined method' error.
For Selenium::Webdriver, the only way I know how to switch between windows is using:
#driver.switch_to.window("<window_handle>")
You can get all the known window_handles by:
#driver.window_handles
#=> Returns all window handles as an array of strings
If you want to switch to the popup you just opened you can do the following. Note that this assumes .window_handles are in the order that the windows were opened, which I believe is true:
#driver.switch_to.window #driver.window_handles.last
To summarize, assuming you only care about accessing the popup (and not about accessing by name) you can do:
#Click control that opens popup
#driver.find_element(:id, 'button that opens popup').click
#Switch to popup
#driver.switch_to.window #driver.window_handles.last
#Do actions in new popup
#driver.find_element(:id, 'id of element in popup').click
Note that if after working with the popup, you will want to return to the original window, then I suggest you do the following. By passing a block to the switch_to.window, the block will be executed in the popup and when the block ends #driver will automatically point back to the original window.
#Click control that opens popup
#driver.find_element(:id, 'button that opens popup').click
#Switch to popup
#driver.switch_to.window( #driver.window_handles.last ){
#Do actions in new popup
#driver.find_element(:id, 'id of element in popup').click
}
#Continue with original window
#driver.find_element(:id, 'button in original window').click

Resources