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

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

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

Finding element and entering in Ruby Selenium

I'm new to the Selenium and Ruby and Cucumber/Gherkins world and am trying a simple script to navigate to the Google page, find the search bar and enter a word and press enter or find the "Google Search" element and click.
This is in a Ruby file but formatted in Gherkins as I'm working with it.
require 'rubygems'
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
Given(/^I am on the Google website$/) do
driver.navigate.to "http://www.google.com"
end
When(/^search is entered$/) do
search = driver.find_element(xpath: "//div[#class = 'jhp big']//input[#class = 'gLFyf gsfi']")
search.send_keys "this"
end
Then(/^confirm$/) do
puts "Confirmed"
driver.close
end
So here I'm navigating to the google website using a Selenium WebDriver initialized as driver. Then finding the element using the xpath and sending in the word 'this'.
When I run this, I get this error:
Selenium::WebDriver::Error::NoSuchElementError: no such element: Unable to locate element: {"method":"xpath","selector":"//div[#class = 'jhp big']//input[#class = 'gLFyf gsfi']"}
Also, to click 'enter' I can either do send_keys :enter or find the Search button and use 'click' correct?
Thank you in advance
you have to use implicit wait for driver to wait until element found
Write the following code and then fit into your cucumber model
require 'selenium-webdriver'
driver=Selenium::WebDriver.for :chrome
driver.navigate.to("https://www.google.com/")
driver.manage.timeouts.implicit_wait=10
driver.find_element(name: 'q').send_keys 'raja'
driver.find_element(name: 'btnK').click
But remember, If you WATIR which is a wrapper around selenium binding these kind of waiting is automatic.

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

Capybara with PhantomJS / Poltergeist: Selecting value from drop-down doesn't trigger Ajax call

For non-commercial purposes I am trying to build a scraper. I have worked with PhantomJS before, and it usually works like a charm. However, I have stumbled upon the following problem:
What I want to do:
Go to http://de.soccerway.com/national/germany/bundesliga/2010-2011/regular-season/r11840/
Click on the button 'per Spieltag'
Then select an option from the drop-down menu that holds the matchdays
Wait for Ajax call to be complete and then get the information I need
Unfortunately, I can select the option I want to select, but nothing happens afterwards. I created a mini script to demonstrate this behavior:
require 'capybara/poltergeist'
require 'capybara/dsl'
include Capybara::DSL
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, :js_errors => false)
end
Capybara.default_driver = :poltergeist
Capybara.javascript_driver = :poltergeist
Capybara.default_wait_time = 20
Capybara.ignore_hidden_elements = true
Capybara.current_session.driver.resize(1200, 1000)
visit('http://de.soccerway.com/national/germany/bundesliga/2010-2011/regular-season/r11840/')
# click on button 'per Spieltag'
find(:xpath, ".//a[text() = 'per Spieltag']").click
# drop down menu with matchdays
matchday_selector = find(:xpath, ".//select[#name='page']")
# save screenshot 'before'
save_screenshot('before.png', full: true)
# for demonstration purposes, select option with value '5'
matchday_selector.find(:xpath, ".//option[#value='5']").select_option
# wait some time for ajax call to be complete and save screenshot 'after'
sleep 5
save_screenshot('after.png', full: true)
If you compare the before and after screenshots, you will see that the number of the drop-down menu has changed, but the content of the table didn't. Also, the dropdown menus are not displayed at the correct position, but instead are shown in the top left corner of the screenshot.
If I use Selenium as my default driver, then it works, but I'd rather user PhantomJS because it is much faster in my experience.
How can I get PhantomJS to trigger the Ajax call?
I use PhantomJS 1.9.1, Capybara 2.1.0 and Poltergeist 1.3.0

Resources