Element is not clickable error Ruby / Watir - ruby

In my test, I am attempting to hit etsy.com, do a search, click on a result, and add the item to my cart. I'm able to do everything up until the point where I attempt to click on the 'add to cart' button. The code below actually works in the IRB so I know my locator is solid, but when I run the test I get an element is unclickable at point error
C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/selenium-webdriver-3.6.0/lib/selenium/webdriver/remote/response.rb:71:in 'assert_ok': unknown error: Element is not clickable at point (930, 586) (Selenium::WebDriver::Error::UnknownError)
(Session info: chrome=61.0.3163.100)
Here's my test
require 'watir'
# test that a user can search for and add an item to shopping cart
b = Watir::Browser.new :chrome
begin
b.goto "http://etsy.com"
b.text_field(:id => 'search-query').set 'bacon is my spirit animal coaster'
b.button(:value => 'Search').present?
b.button(:value => 'Search').click
b.p(:text => /Bacon Spirit Animal Coaster/).click
b.select_list(:id => 'inventory-variation-select-0').option(:text => 'Single ($8.00)').select
b.button(:text => /Add to cart/).click
if b.text.include?("item in your cart")
puts "Test passed!"
else
puts "Test failed!"
end
ensure
b.close
end
And here is the page HTML for the button.
<button class="btn-transaction" type="submit">
<div class="btn-text">Add to cart</div>
<div class="ui-toolkit">
<div class="btn-spinner spinner spinner-small display-none"></div>
</div>
</button>

Depending on the browser width (and likely other factors), there may be dialogs floating over the add to cart button. For example, when the test failed for me, there was a get started dialog on top of the button. Chrome attempts to click by a location. If another element is on top of your element at that location, Chrome will throw the exception.
The easiest solution is to bypass Chrome's check by directly triggering the click event:
# Watir > 6.8.0:
b.button(:text => /Add to cart/).click! # note the exclamation mark
# Watir < 6.8.0:
b.button(:text => /Add to cart/).fire_event(:onclick)
Other solutions that may conditionally work:
Maximize the browser before clicking the button - browser.window.maximize. This can move the floating element away from the button.
Close the floating dialog.

Related

Ruby Shoes: how to replace button text with an image/icon

I am trying to write a small Shoes app which contains a button. For example
Shoes.app :title => "Buttons" do
button_next = button "Next"
button_prev = button "Previous"
end
Now, instead of the texts "Next" or "Previous" there should be icons on the buttons: a green arrow, showing to the right for the button_next and a green arrow showing to the left for the button_prev.
Of couse I already have the icons as .jpg-files but I can't figure out how to replace the text with the icons on the buttons.
For now I found out this way:
Shoes.app do
next_image = image "next.jpg", :width => 50, :height => 35
next_image.click do
alert "Hey!"
end
end
It works in the way that I can click the image and a new window, saying "Hey!" appears. But it is not ok, because I miss the typical button-appearance like changing of the color when hovering over it, or the press-down-effect when clicking on it.
So my question is: how can I create a real button in Ruby Shoes and replace the name of the button with an icon? Any ideas?

Ruby Watir radio checkbox

i m trying to set the checkbox on a radio control with the .set? option. it returns false but I'm unable to set the checkbox.
<div class="">
<input name="radiostorage" id="zrs" value="2" type="radio">
<label for="zrs">Zone-redundant storage (ZRS)</label>
</div>
have tried with label(for: 'zrs').set .click .parent.click .parent.set, also directly trying to click on the input , but nothing happens, any clue on that
TIA
Given the way that the radio button is implemented, it will not be considered visible. You will get an exception trying to set it directly:
browser.radio(id: 'zrs').set
#=> element located, but timed out after 2 seconds, waiting for #<Watir::Radio: located: true; {:id=>"zrs", :tag_name=>"input", :type=>"radio"}> to be present (Watir::Exception::UnknownObjectException)
Instead of setting it directly, you can click its associated label, which is what an actual user would do:
browser = Watir::Browser.new
browser.goto('https://pricing-calculator.bluekiri.cloud/')
p browser.radio(id: 'zrs').set?
#=> false
browser.label(for: 'zrs').click
p browser.radio(id: 'zrs').set?
#=> true
How about
radio = browser.radio(id: 'zrs')
radio.set? #=> false
radio.set
radio.set? #=> true
See http://www.rubydoc.info/gems/watir-webdriver/Watir/Radio

Click drop down menu

I have a span:
<span class="ToolbarLinkButton" id="ComparisonReports" onclick="function_which_shows_dropdown_menu">
When I click on it I get drop down menu:
<div id="divPopupTemplateComparisonReports">
<div class="ToolbarButtonMenu">
<div class="ToolbarLinkButton" id="ComparisonReportsView" onclick="some_functions">
But when I try to click on element (id="ComparisonReportsView"), it says that: "Selenium::WebDriver::Error::ElementNotVisibleError: Cannot click on element"
on(Main) do |page|
page.spnComprReptVer_element.fire_event ("onclick")
page.divComprReptView_element.click
sleep 2
end
And when via fire_event it says that step passed but nothing was executed (no menu item clicked).
on(Main) do |page|
page.spnComprReptVer_element.fire_event ("onclick")
page.divComprReptView_element.fire_event ("onclick")
sleep 2
end
How I can click on it somehow other way, or what I can use?
I do not know your definition for divComprReptView_element but I assume it has #when_present just use it and give it a block to execute click(e.g. page.divComprReptView_element.when_present.click).

Bringing elements behind fixed element into view with page-object gem

My page contains two divs at the top (a header and another section) that are fixed while the rest of the page can be scrolled. I need to hover over a link element and then click on a button that appears when hovering over the link. Since I am using the page-object gem I tried to use scroll_into_view. However the link still remains behind the fixed divs. This prevents the button from showing. Is there anything that can be done to force it into view? Links at the top and bottom of the scrollable area of the page work fine but items in the middle of the page have issues as they appear behind the fixed divs when scrolled. I am using ruby+watir-webdriver with page-object gem.
Unfortunately I can't post the site.
My code looks something like this:
class MyPage
div(:items, :class => 'product_items')
def index_for(product)
index = items_elements.find_index{|x| x.h4_element.text == product}
index
end
def add_product(product)
index = index_for(product)
product = items_elements[index.to_i]
product.link_element(:class => 'product_more_info').when_present.scroll_into_view
product.link_element(:class => 'product_more_info').hover
product.button_element(:class => 'product_info_button').when_present.click
end
end
The links in the middle of the page remain behind the fixed divs. When it hovers it actually triggers a nav dropdown that is in the header since the link is directly behind it. Seems to work for 70% of the links. The 30% in the middle are the issue right now.
I think I have reproduced your problem with the following page. When the div element to hover on is scrolled into view, it appears below the menu. Hovering does not cause the onmouseover to trigger.
<html>
<body>
<div style="position:fixed; left:0; top:0; z-index=99999; border:2px solid red; width:100%">menu</div>
<div class="spacer" style="height:2000px"></div>
<div id="hoverable" onmouseover="document.getElementById('target').style.display = '';">to hover</div>
<button id="target" style="display:none;">the button</button>
<div class="spacer" style="height:2000px"></div>
</body>
</html>
One solution that works (at least for this example page), was to try hovering over the element. If the button did not appear, assume that the menu is in the way, scroll back up the page a bit and try again. Assuming the above page, this could be done with the page object:
class MyPage
include PageObject
div(:hoverable, :id => "hoverable")
button(:target, :id => "target")
def hover()
# Try to hover over the element
hoverable_element.when_present.hover
# If the button element does not appear, the menu must be in the way.
# Scroll back up 100 px so that the div appears below the menu and try again.
unless target_element.visible?
execute_script('window.scrollBy(0,-100);')
hoverable_element.hover
end
# Check that the button appears as expected
p target_element.visible?
#=> true
end
end
Applying the same idea to your page object, the add_product method would become:
def add_product(product)
index = index_for(product)
product = items_elements[index.to_i]
product.link_element(:class => 'product_more_info').hover
unless button_element(:class => 'product_info_button').visible?
execute_script('window.scrollBy(0,-100);')
product.link_element(:class => 'product_more_info').hover
end
product.button_element(:class => 'product_info_button').click
end

How do you automatically confirm a modal in ruby using page-object?

I have a standard rails application with a delete link. This delete link comes up with a browser popup modal (using rails confirm option).
I am currently attempting to test the delete function with Cucumber, Selenium-Webdriver (or Watir-Webdriver, still haven't decided), and the page-object gem.
Once the modal has been triggered, anything I do on the page gives me the following error:
Modal dialog present (Selenium::WebDriver::Error::UnhandledAlertError)
I have been looking all over, but cannot find a way to handle this condition. If possible, I would like to continue using the PageFactory module in the page-object gem.
How can I dismiss/accept the modal?
I figured out a way to do this, but haven't decided upon the exact implementation.
In Javascript you can overwrite any function, which means you can overwrite the confirm
This means that you can run the following code to disable any popups.
def disable_popups
# don't return anything for alert
browser.execute_script("window.alert = function() {}")
# return some string for prompt to simulate user entering it
browser.execute_script("window.prompt = function() {return 'my name'}")
# return null for prompt to simulate clicking Cancel
browser.execute_script("window.prompt = function() {return null}")
# return true for confirm to simulate clicking OK
browser.execute_script("window.confirm = function() {return true}")
# return false for confirm to simulate clicking Cancel
browser.execute_script("window.confirm = function() {return false}")
end
If you put this inside the initalize_page function of a page-object then the dialogs are automatically removed.
def initialize_page
disable_popups
end
Or you could do it right before the pop is triggered
def delete
disable_popups
delete_link # => clicks the link
end
References:
Testing Webpages with Javascript Popups Correctly
Dismissing Pesky Javascript Dialogs with Watir
The page object gem has methods to handle javascript popups - see the original page-object gem post. In your case, I believe you want the confirm method::
(String) confirm(response, frame = nil, &block)
Override the normal confirm popup so it does not occurr.
Examples:
message = #popup.confirm(true) do
#page.button_that_causes_confirm
end
Parameters:
what (bool) — response you want to return back from the confirm popup
frame (defaults to: nil) — optional parameter used when the confirm is nested within a frame
block — a block that has the call that will cause the confirm to display
Returns:
(String) — the message that was prompted in the confirm
There is similar for the alert and prompt popups.
In your page-object, I would define:
class MyPage
link(:delete_link, :id=>'delete')
def delete()
confirm(true){ delete_link }
end
end
Then when you call page.delete, it will click the link and confirm the popup.

Resources