Controlling new tab to operate using Watir? (Ruby) - ruby

I'm using watir for automated testing and after running through some tables, a chart then gets opened up in a new tab. But watir doesn't seem to recognise the new current tab and continues to search through the original browser tab.
Is there any way of telling watir which tab you want to be using?

Watir does not care if a new page opens in a new window or in a new tab, so use window switching API to switch to the new tab:
browser.window(:title => "annoying popup").use do
browser.button(:id => "close").click
end
More information: http://watirwebdriver.com/browser-popups/

You can use this code
browser.windows.last.use
this will set watir focus to newly or last opened tab or window, and after completion of use of this new tab/window just tell watir to close that tab/window
browser.windows.last.close

There are 3 primary selectors for windows:
:title - typically the easiest
:url - often used with a Regexp value
:element - a unique element might be the least brittle (new as of Watir 6.18!)
browser.window(title: 'new window')
browser.window(url: /my_page.html/)
browser.window(element: browser.div(id: 'my-element'))
Locating by index is no longer supported
More information: Watir Browser Windows

#browser.windows[x].use
Replace 'x' with the tab number you'd like to use. #browser.windows is a Watir Collection, which can be treated like an Array for this purpose.

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.

Press TAB and then ENTER key in Selenium WebDriver with Ruby

I am doing automated testing using Selenium WebDriver with Ruby. I need to click a button. I cannot get the button element by id or css or xpath as the button is transparent. I would like to use Tab and Enter key to press the button.
I can use Tab key to get the button as below:
#element.send_keys :tab
#element --> any javascript element visible in the browser
But how do I use the Enter key on the button?
Basically I need to achieve press Tab key and then press Enter key to click the button.
I am using Selenium WebDriver #driver = Selenium::WebDriver.for :firefox
In Ruby user1316's code looks like
driver.action.send_keys(elementVisible, :tab).send_keys(elementVisible, :return).perform
Keeping in mind the excerpt :
I can use tab key to get the button as
#element.send_keys :tab
#element --> any javascript element visible in
the browser
but how do i use the enter key on the button??
In order to use the enter key on the button, you could try one of the solution provided using Ruby here. This basically talks about sending the :return value and not the :enter value i.e #element.send_keys :return and some additional information.
UPDATED:
I could provide some code in Java which tries to implement the problem conceptually using the info provided here. You could try to translate for the corresponding Ruby Selenium API.
The Code:
Actions builder = new Actions(driver);
builder.sendKeys( elementVisible, Keys.TAB).sendKeys(Keys.RETURN);
Action submitTheTransperentButton = builder.build();
submitTheTransperentButton.perform();
use Selenium::WebDriver::Keys::KEYS[:tab]
ref: https://www.rubydoc.info/gems/selenium-webdriver/Selenium/WebDriver/Keys
send ENTER in ruby:
#browser.action.send_keys("\n").perform

How to get focus to a new popup window which doesnt have name,id or unique title in selenium

I want to get focus or select an window which pop-up's on click to the link and the link has following tags in html
<a target="_restaurant_50" href="/impersonate/50">View Dashboard</a>
if i put window name as _restaurant_50 it gives the following error in IDE
Window does not exist. If this looks like a Selenium bug, make sure to read http://seleniumhq.org/docs/04_selenese_commands.html#alerts-popups-and-multiple-windows for potential workarounds.
How can i get the focus on this window please help...
I tried all the ways specified on net such as get all windows*, select by title but it gives the parent title only, webdriver PHP switch window, etc.
the number 50 is as per the number in database list.
I am using selenium with PHP.
Details:
Array Names before click
(
[0] => selenium_main_app_window
)
Array Ids before Click
(
[0] => undefined
)
Array Names After click
(
[0] => selenium_main_app_window
)
Array Ids After click
(
[0] => undefined
)E
Update:
I tried opening the url using openWindow("url",Windowname) which gets open on click. It worked but it opens a new page doesnt follow the logged in session it asks again for logging in
Thanks in Advance
I am not familiar with the PHP selenium drivers but the way I did this with Java was to get a list of Window Names (or IDs) before the click, perform the click, get the new list and select the window that wasn't there before. Note that there is a selenium command to get all known window names and ids.
Also, if the issue is just that the number is generated from the database, you could get the target attribute from the link, and then use that to select the window it opens.
I was am able to do the above by following Steps.
we have
<a target="_restaurant_50" href="/impersonate/50">View Dashboard</a>
use
as=getAttribute(//xpath#href)
openWindow(as,MyWindow);
selectWindow("MyWindow");
windowFocus();
This also works for the dynamic links.
Thanks to ALL for your valuable help.

How can I know what element is clicked in IE?

I'm automating IE with watir, and I want to know what html element(s) are clicked (selected). Can this be done using watir? win32ole? In a last chance, without ruby?
Something like:
Click a button -> button with id=213 and class=btn_class was clicked.
Click a text field -> text field with id=123 and value=my_text was clicked.
Try one of the recorders, Selenium IDE for example.
I'm not sure if I completely understand either, but would a custom function like this work?
def click(item, how, what)
#browser.item(how, what).click
puts "#{item} with #{how}->#{what} was clicked"
end
click("button", ":id", "awesome")
Edit: If you're attempting to identify page elements so that you can then use them in a Watir script, the Developer Toolbar is perfect for this application, much like Firebug for Firefox.
http://www.microsoft.com/download/en/details.aspx?id=18359
Your comment to me & your response to Zeljko appear to contradict each other. If you want to use WATIR for this task, the code above will execute a mouse click and post the information to console. The only other way to get information is to locate the object in WATIR and fish for more details:
object = #browser.button(:name, /myButton/)
object.id
object.title
object.status
object.height, etc.
or
#browser.divs.each do |div|
puts div.id, div.title
end
I'd recommend a strong look at the capabilities of the various developer tools, such as are provided with Chrome, Firefox, and IE. those are generally the best means to get this kind of information.
Watir is really about driving the browser, and getting info out of the DOM. it's not really setup to report on manual interactions with the browser.

In Ruby, with selenium, difficulty clicking Google Search

I get this far, opening the firefox browser, navigating to google, and finding the google search element
irb(main):001:0> require 'selenium-webdriver'
=> true
irb(main):002:0> driver = Selenium::WebDriver.for:firefox
=> #<Selenium::WebDriver::Firefox::Marionette::Driver:0x..fb3c81796cc82b708 browser=:firefox>
irb(main):003:0> driver.navigate().to("http://www.google.com")
=> nil
irb(main):188:0> driver.find_element(:name, "q").send_keys "fff"
=> nil
irb(main):112:0> driver.find_element(:name, "btnK");
=> #<Selenium::WebDriver::Element:0x5fb450f4379c50ce id="d767311c-27a2-3544-8f11-e4edc9736588">
irb(main):113:0> driver.find_element(:name, "btnK").attribute('value');
=> "Google Search"
But I can't manage to click it!
irb(main):114:0> driver.find_element(:name, "btnK").click
Traceback (most recent call last):
16: from /usr/local/lib/ruby/gems/2.5.0/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/remote/w3c/bridge.rb:552:in `execute'
15: from /usr/local/lib/ruby/gems/2.5.0/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/remote/bridge.rb:166:in `execute'
14: from /usr/local/lib/ruby/gems/2.5.0/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/remote/http/common.rb:62:in `call'
13: from /usr/local/lib/ruby/gems/2.5.0/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/remote/http/default.rb:104:in `request'
12: from /usr/local/lib/ruby/gems/2.5.0/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/remote/http/common.rb:84:in `create_response'
11: from /usr/local/lib/ruby/gems/2.5.0/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/remote/http/common.rb:84:in `new'
10: from /usr/local/lib/ruby/gems/2.5.0/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/remote/response.rb:32:in `initialize'
9: from /usr/local/lib/ruby/gems/2.5.0/gems/selenium-webdriver-3.141.0/lib/selenium/webdriver/remote/response.rb:69:in `assert_ok'
8: from clickElement#chrome://marionette/content/listener.js:1209:5
7: from navigate#chrome://marionette/content/listener.js:409:13
6: from navigate/<#chrome://marionette/content/listener.js:410:13
5: from clickElement/<#chrome://marionette/content/listener.js:1210:14
4: from interaction.clickElement#chrome://marionette/content/interaction.js:130:11
3: from webdriverClickElement#chrome://marionette/content/interaction.js:159:11
2: from ElementNotInteractableError#chrome://marionette/content/error.js:286:5
1: from WebDriverError#chrome://marionette/content/error.js:178:5
Selenium::WebDriver::Error::ElementNotInteractableError (Element <input name="btnK" type="submit"> could not be scrolled into view)
irb(main):115:0>
It says that the element "could not be scrolled into view" !
I can do driver.find_element(:tag_name, "body").send_keys :page_down; which would page down. Which is mentioned Looking at ruby selenium documentation for send_keys https://www.rubydoc.info/gems/selenium-webdriver/Selenium%2FWebDriver%2FElement%3Asend_keys . I see a list of key codes https://www.rubydoc.info/gems/selenium-webdriver/Selenium/WebDriver/Keys#KEYS-constant . And also listed https://github.com/SeleniumHQ/selenium/blob/master/rb/lib/selenium/webdriver/common/keys.rb . Or I can page down manually. But scrolling (at least in the normal sense of the term) doesn't seem to be the issue, I still get that error. Maybe it's in a frame I can switch to and I don't know which.
The button is of course visible. It's just a regular google search page.
I can find the button fine but I can't see how to click it, as .click isn't working for me.
added
in reply to a comment asking me if the google suggestions box is obfuscating the button. I can see in the browser that the button isn't obfuscated 'cos sometimes I have done escape manually, or clicked the background window(to get rid of that. I am using IRB so running each statement manually so I have time to do that). But I also did escape with the code, and escape works to get rid of the suggestion box, but still same error when trying to click the button
While discussing this problem in the comments, I wrote some C# code to demonstrate how we wait for clickable in C#
new WebDriverWait(Driver, TimeSpan.FromSeconds(5)).Until(ExpectedConditions.ElementToBeClickable(By.Name("btnK"))).Click();
In the process of writing the C# code I posted, I think I see what the issue is. When you start typing in the search box, a dropdown appears that contains the suggested searches. This covers the "Google Search" button that you are trying to click... BUT another "Google Search" button appears at the bottom of the dropdown itself. You should print a count of the (:name, "btnK") element(s)... I'm assuming it will print 2 (if a proper wait is added). From there, you just need to click the one that is on top.
Another option would be to send a \r\n at the end of your search string and avoid this whole issue... or you could just navigate to the final search URL and save even more headaches and time.
Added note from barlop
To clarify, this has nothing to do with the suggestions popup showing(and having to get rid of the popup).. and nothing to do with having a wait (Since I was working with IRB, I was naturally waiting). And I'd already clicked outside or hit escape to get rid of the popup. The issue was, and Jeff's answer alerted me to this - Even after the popup is gone, there are still two buttons with that btnK name. So, using find_elements rather than find_element, and running .click on the second one works! (Also, using find_elements(plural) for the name attribute makes sense, since as noted in an answer herehttps://stackoverflow.com/questions/5518458/does-a-name-attribute-have-to-be-unique-in-a-html-document. the name attribute is not unique / not a unique identifier.
This is what I told you to use WATIR, If you had used WATIR, this problem wouldn't have arrived. The problem in your code, it's not waiting for visibility. Recently Chrome Driver has added implicit wait for click as well, so it would wait for visibility if you set the implicit wait. Otherwise move to WATIR which is a good wrapper which doesn't wait via driver, In WATIR waiting for element status happens from local language binding, so use this selenium code
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
driver.manage.timeouts.implicit_wait = 10
driver.navigate().to("http://www.google.com")
driver.find_element(:name, "q").send_keys "fff"
driver.find_element(:name, "btnK").click
Remember this selenium code wouldn't work for firefox because implicit wait for click is not added yet for firefox.
Since WATIR is handling the timing from local language binding, it doesn't matter whether you use Chrome or Firefox, it would perfectly work
WATIR Code (Default is Chrome)
require 'watir'
b=Watir::Browser.new
b.goto 'www.google.com'
b.text_field(name: 'q').set 'fff'
b.button(name: 'btnK').click
If you want to drive Firefox
b=Watir::Browser.new :firefox
But you can do the click with javascript (sending javascript to the browser).
b=driver.find_element(:name, "btnK")
driver.execute_script("arguments[0].click();",b)
Jeff explains why the javascript method(selenium with javascript), works on either button but the non-javascript method(selenium without javascript) works only on one button, he wrote "Both of the buttons would work, the JS click will click on any element no matter where it is... or if it's visible, etc. Selenium was designed to interact with the page as a user would so it was unable to click on the element due to the error."

Resources