Ruby Watir: when_present not appropriately waiting until things are present? - ruby

I'm having an issue getting when_present to actually wait until the element is present in certain cases. The problem occurs only intermittently, but it always happens when changing pages.
Example: I want to click save on the current page, then enter text into a field on the subsequent page.
If I do:
$browser.button(:value => "Save").click
sleep 3
$browser.text_field(:label => "Name").when_present.set "Leelluu"
tt works fine.
However, if I do:
$browser.button(:value => "Save").click
$browser.text_field(:label => "Name").when_present.set "Leelluu"
it times out/crashes immediately after clicking "Save".
How do I fix this?
(I know, it seems like I have fixed it by using sleep, but my boss has told me that the sleeps are wasting time. He says I need to remove all of them from the code and find another way.)
Updating with a real-world example..... I enter a search text, then click the search button, then want to select the checkbox next to the leading checkbox on the returned list.
$browser.text_field(:id => /.*search*./).set "Snow Leopard"
$browser.button(:id => "save_filter_PricebookEntry").when_present.click
$browser.checkbox(:id => "allBox").when_present.set
I get an "element not clickable" (even though it has a when_present) on it.
unknown error: Element is not clickable at point (251, 482). Other element would receive the click:
...
(Session info: chrome=31.0.1650.57) (Driver info: chromedriver=2.2,platform=Windows NT 6.1 SP1 x86_64)
["D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/remote/response.rb:51:in `assert_ok'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/remote/response.rb:15:in `initialize'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/remote/http/common.rb:59:in `new'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/remote/http/common.rb:59:in `create_response'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/remote/http/default.rb:66:in `request'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/remote/http/common.rb:40:in `call'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/remote/bridge.rb:634:in `raw_execute'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/remote/bridge.rb:612:in `execute'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/remote/bridge.rb:369:in `clickElement'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/common/element.rb:54:in `click'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-webdriver-0.6.4/lib/watir-webdriver/elements/checkbox.rb:26:in `set'", "D:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-webdriver-0.6.4/lib/watir-webdriver/wait.rb:100:in `method_missing'", "D:/Desktop/jardine/utils.rb:143:in `addQLIs'", "D:/Desktop/jardine/noSleepTest.rb:31:in `block in '", "D:/Desktop/jardine/framework.rb:39:in `execute'", "D:/Desktop/jardine/framework.rb:61:in `block in runTestCases'", "D:/Desktop/jardine/framework.rb:60:in `each'", "D:/Desktop/jardine/framework.rb:60:in `runTestCases'", "jardine.rb:66:in `
'"]

Related

Unable to click download button with web scraper

for whatever reason mechanize is unable to click this export button to automate downloading a public government csv file, i'm trying to automate downloading a fishing report, does anyone have any ideas on how to get it to work?
agent = Mechanize.new
url = 'https://nrm.dfg.ca.gov/FishPlants/'
log :debug, "reading HTML from #{url}"
page = agent.get(url)
log :debug, 'loaded page'
form = page.search('#aspnetForm').first
button = page.search('.application_button').first
log :debug, 'clicking Export button'
response = agent.submit(form, button)
i get a stack trace with the following error
...
form.add_button_to_query(button) if button
^^^^^^^^^^^^^^^^^^^^
/Users/aronlilland/.rvm/gems/ruby-3.1.2/gems/mechanize-2.8.5/lib/mechanize.rb:581:in `submit'
/Users/aronlilland/Documents/dev/fishing-report/tasks/download/fishing_report.rake:27:in `block (2 levels) in <top (required)>'
Tasks: TOP => download:fishing_report
(See full trace by running task with --trace)
the form is confirmed returns successfully, but the button is an input field
the page seems relatively straight forward, so dont know why i'm unable to scrape it - and its also public data
<form method="post" action="./" id="aspnetForm">
<!-- .... -->
<input
type="submit"
name="ctl00$cphContentMiddle$btnExport"
value="Export"
id="ctl00_cphContentMiddle_btnExport"
class="application_button"
>
<!-- .... -->
</form>
agent.submit got the wrong type for form
The issue here could be seen if you had included the beginning of the stack trace:
.../ruby/gems/3.1.0/gems/mechanize-2.8.5/lib/mechanize.rb:581:in `submit': undefined method `add_button_to_query' for #<Nokogiri::XML::Element:0x1ea14 name="form" attributes=
[#<Nokogiri::XML::Attr:0xbd38 name="method" value="post">, ...
Mechanize expects the submit to act on a Mechanize::Form instance, but instead got an instance of Nokogiri::XML::Element, as you can see by adding this to your code:
form.class # => Nokogiri::XML::Element
If you check the docs for the Mechanize::Form class, you can see the example they give to get you the form object is this:
form = page.forms.first # => Mechanize::Form
as opposed to what you used:
form = page.search('#aspnetForm').first
The call to search here is delegated to Nokogiri, and therefore doesn't return the object type you need, but rather a Nokogiri element.
button also has the wrong type
By the way the same applies to this line:
button = page.search('.application_button').first
If you fix the type of form, you'll get into a similar issue with button not being the expected type. Again, there's an example in the docs showing how a button is found:
agent.submit(page.forms.first, page.forms.first.buttons.first)
You'll need to figure out how to find the specific button you need though, I haven't worked with Mechanize before, so I can't offer a suggestion here. Presumably there's a way to convert the button you find through search to a Mechanize::Form::Button instance.

Unable to Locate element in salesforce using watir

Problem 1:
Input:
browser.span(:id => 'ProdSelectionPage_Fav:mainform:pbmain:pSecId:j_id90:txtQuoteDesc').when_present.exist?
Error:
C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/wait.rb:29:in `until': timed out after 60 seconds (Watir::Wait::TimeoutError)
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/element_extensions.rb:18:in `method_missing'
from C:/WebAutomation/Tests/sandbox/attach.rb:52:in `<main>'
Problem 2:
Input:
browser.frame.text_field(:id, /ProdSelectionPage_Fav:mainform:pbmain:pSecId:j_id90:txtQuoteDesc/).when_present.set'gautam raj'
Error:
C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/wait.rb:29:in `until': timed out after 60 seconds (Watir::Wait::TimeoutError)
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/element_extensions.rb:18:in `method_missing'
from C:/WebAutomation/Tests/sandbox/attach.rb:56:in `<main>'
Without 'when_present' and used 'sleep 30' before
Input:
browser.frame.text_field(:id, /ProdSelectionPage_Fav:mainform:pbmain:pSecId:j_id90:txtQuoteDesc/).set'gautam raj'
// tried 'name' instead of 'id' for input
Error:
C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/element.rb:338:in `assert_exists': Unable to locate element, using {:tag_name=>["frame", "iframe"]} (Watir::Exception::UnknownFrameException)
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/frame.rb:21:in `document'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/frame.rb:52:in `__ole_inner_elements'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/locator.rb:204:in `each_element'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/locator.rb:229:in `each'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/locator.rb:217:in `locate'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/input_elements.rb:20:in `locate'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/element.rb:335:in `assert_exists'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/element.rb:484:in `perform_action'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/watir-classic-4.2.0/lib/watir-classic/input_elements.rb:252:in `set'
from C:/WebAutomation/Tests/sandbox/attach.rb:56:in `<main>'
html code:
<input name="ProdSelectionPage_Fav:mainform:pbmain:pSecId:j_id90:txtQuoteDesc" id="ProdSelectionPage_Fav:mainform:pbmain:pSecId:j_id90:txtQuoteDesc" type="text" size="20" maxlength="35">
The problem here is the element you are trying to location never visible to watir.
So with when_present, it will fail with Watir::Wait::TimeoutError error. If you want to click/set the element not visible, it will fail with Watir::Exception::UnknownFrameException error.
The problem here was, when I move to next page, system is throwing error. So, I used below command when I want to move to next page
browser = Watir::Browser.attach(:url, //)
Now, it is working fine

Selenium Webdriver (Ruby) : Cannot click on button - element not found

This is the page code:
<div class="modal-buttons">
<button class="button-orange" ng-click="cancel()">
<span>
Cancel
</span>
<span class="icon cancel"></span>
</button>
<button class="button-orange" ng-click="apply()">
<span>
Apply
</span>
<span class="icon run"></span>
</button>
As you can see - this modal has two buttons and I have tried a dozen different ways - but I just want to click on the button labeled "apply" No matter which route I take - it just keeps saying element not visible.
Here are some of the things I've tried:
# #driver.find_element(:class, "button-orange")[2].click
# #driver.find_element(:xpath, "//div[4]/div/div[2]/div[3]/button[2]").click
# #driver. find_element(:link_text, 'Apply').click
# #driver. find_element(:tag, 'Apply').click
# #driver.find_element(:css, "input[value='Apply']").click();
# #driver.find_element(:css, "input[value='Apply']").click();
# #driver.find_element(:xpath, "//button[contains(text(),'Apply')]").click
# #driver.find_element(:xpath, "//button[contains(text(),'apply')]").click
# #driver.find_element(:xpath, "//input[#value='Apply']").click();
# #driver.find_element(:class, "button-orange.icon-run").click
# #driver.find_element(:css,'a[class$="button-orange"]').click
# #driver.find_element(:xpath, "").clear
The exact error I get is:
Error: test_login_to_chute(LoginToChute)
Selenium::WebDriver::Error::ElementNotVisibleError: element not visible
(Session info: chrome=36.0.1985.125)
(Driver info: chromedriver=2.10.267521,platform=Windows NT 6.3 x86_64)
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/remote/response.rb:51:in `assert_ok'
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/remote/response.rb:15:in `initialize'
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/remote/http/common.rb:59:in `new'
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/remote/http/common.rb:59:in `create_response'
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/remote/http/default.rb:66:in `request'
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/remote/http/common.rb:40:in `call'
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/remote/bridge.rb:634:in `raw_execute'
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/remote/bridge.rb:612:in `execute'
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/remote/bridge.rb:369:in `clickElement'
C:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.42.0/lib/selenium/webdr
iver/common/element.rb:54:in `click'
C:/Analytics/AutomatedTesting/DevEnv/Wonderland/Full Regression/2.login_to_chute
.rb:165:in `test_login_to_chute'
162: #driver.find_element(:xpath, "(//input[#type='text'])[8]").clear
163: #driver.find_element(:xpath, "(//input[#type='text'])[8]").send_
keys "25"
164:
=> 165: #driver.find_element(:xpath, "//div[4]/div/div[2]/div[3]/button[2]").c
lick
Thank you all so much for helping.
Here's what ended up being the deal.
Because the website is all one angular page, it's loading a bunch of things in the background. Including multiple other buttons that aren't actually visible.
So here's what I ended up using:
#driver.find_elements(:xpath, "//button")[-1].click
And I updated my find_element variable to only find visible elements.
def find_visible_element(how, what)
elems = #driver.find_elements(how, what).select { |e| e.displayed? }
len = elems.length
if len == 0
raise "No matches found."
elsif len > 1
raise "Ambiguous match. Found #{len} matches."
end
elems.first
end
There are several reasons behind this error. I was getting the same error and here is how I narrowed down the possible causes.
The Item can be located in the iframe, in this case you have to switch to the iFrame and locate the element
Another reason can be the element is not yet displayed and you are performing operations on it. In this case you can apply explicit wait as below.
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until{browser_driver.find_element(:xpath,'***').displayed?}
Using this chunk in your code can help you to wait for maximum 10 seconds till the item is displayed
It is possible that, your xpath is returning more than 1 web element to the driver i.e. more than 1 element can be located with the same xpaths. In this case make sure that your xpath is more specific and returning only one web element. My issue was solved with 3rd possibility.
Wait unti the javascript modal is fully loaded (using a Wait block, for example)
Also, you have to use the correct selector. Frankly, quite of few of your example selectors don't make any sense in the context of the html you posted.
In Chrome's inspector, make sure what it is that a mouseclick would click on. Have you tried selecting the <span>?
Try some of these:
:css => "button.button-orange[ng-click='apply()']"
:xpath => "//button[#ng-click='apply()']"
:xpath => "//button/span[contains(text(),'Apply')]/.."
:css => "button.button-orange[ng-click='apply()'] > span"
:xpath => "//button[#ng-click='apply()']/span"
:xpath => "//button/span[contains(text(),'Apply')]"
By the way, chrome's element inspector has a find function that can search xpath as well as css too for selector testing.

MongoDB Ruby driver and mongoS

I am trying to use the MongoDB Ruby driver to pull information from a cluster via mongoS. Here is what I've done.
#mongo_client = Mongo::Connection.new('mongoshost', 27320)
#db = #mongo_client.db("thedatabase")
#auth = #db.authenticate("username", "password")
if(#mongo_client)
print "Successfully connected to mongos\n"
else
print "Connection failed"
end
if(#auth == true)
print "Auth successful\n"
else
print "Auth failed"
end
collection = #db.collection("thecollection")
puts collection.find.to_a
When I run this, everything works up until the point that it tries to print the documents in the collection. Here's what my output looks like:
C:\Code\whatever>ruby getdata.rb
Successfully connected to mongos
Auth successful
C:/Ruby200/lib/ruby/gems/2.0.0/gems/bson-1.9.2/lib/bson/bson_c.rb:24:in `deseria
lize': time must be positive (ArgumentError)
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/bson-1.9.2/lib/bson/bson_c.rb:2
4:in `deserialize'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/networkin
g.rb:223:in `read_documents'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/networkin
g.rb:169:in `receive'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/networkin
g.rb:133:in `receive_message'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/cursor.rb
:497:in `block in send_initial_query'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/util/logg
ing.rb:55:in `block in instrument'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/util/logg
ing.rb:20:in `instrument'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/util/logg
ing.rb:54:in `instrument'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/cursor.rb
:493:in `send_initial_query'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/cursor.rb
:478:in `refresh'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/cursor.rb
:124:in `next'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/cursor.rb
:290:in `each'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/cursor.rb
:314:in `to_a'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/mongo-1.9.2/lib/mongo/cursor.rb
:314:in `to_a'
from getdata.rb:27:in `<main>'
The "time must be positive" error had a few search results, but nothing that helped me figure out what the issue is. One of the fields in these documents does hold a negative number for a date, but I'm not sure why that's an issue since it's reading it and not writing (For example, one of the fields looks like so: {"md" : Date(-62135596800000)})
Is this an issue with the driver, is my code bad, or do I need to figure this out in another manner? I'm pretty new to ruby so any help would be appreciated!
Your data is bad as you have already noted. The problem is that the driver is trying to expand the date value ( which is really just a number internally to mongo within a BSON timestamp field ) into a real DateTime object.
When it tries to do this on read, the number is invalid an the inflation fails. If you fix the date value the problem will be corrected.
Note: If you do this in the shell use the ISOate helper to put a correct value in. If you use code then use a DateTime object. Don't use strings as you will mess your data up further.

error when clicking a link using ruby/watir

I am new to ruby/watir and am getting an error when trying to click on a link.
The error is:
C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.0.1/lib/watir-classic/elemen
t.rb:328:in `assert_exists': Unable to locate element, using {:tag_name=>["a"],
:id=>"My Link"} (Watir::Exception::UnknownObjectException)
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.0.1/lib/watir-c
lassic/element.rb:474:in `perform_action'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.0.1/lib/watir-c
lassic/element.rb:354:in `click!'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-4.0.1/lib/watir-c
lassic/element.rb:157:in `click'
from Login.rb:22:in `<main>'
The link that I am trying to click looks like this:
<TD><DIV id=div style="DISPLAY: inline"><A id=Hyperlink href="javascript:RunFullScreen('myURL')">My Link</A></DIV>
Also, I tried to write out all links on the page using 'puts', but nothing was written out when the script finished
I used this code to write out the links (not sure if this is correct or not):
browser.links.each {|link| puts link.attribute_value("text") if link.visible?}
The error says tat you tried to find an object with the following properties: {:tag_name=>["a"], :id=>"My Link"}, but you have show us HTML code with A id=Hyperlink. So to find out that HTML you need to specify properly its attributes:
#b.element :tag_name => 'a', :id => 'Hyperlink'
or
#b.a :id => 'Hyperlink'

Resources