I am using webdriver with FF38, but leaving the browser open window after my script is done. I find that dialogs no longer open in that window, if I continue after the testing.
The script is meant to automate forms input rather than doing it by hand, but the website does use dialog boxes to express choices -- (for example, deleting data that the script has just entered, so that I can rerun the script without overwriting information)
Is there a way to disconnect the webdriver dialog handling after I'm done?
I'm feeling a little foolish, but my searches haven't born fruit, so I may be using the wrong words in my search, given my newness to ruby and webdriver.
Example would be this:
require "watir-webdriver"
l_Browser = Watir::Browser.new :firefox
l_Browser.goto "http://www.w3schools.com/js/tryit.asp?filename=tryjs_alert"
# Click the button that opens the dialog
l_Browser.div(:class => "container").div(:class => "iframecontainer"). \
div(:class => "iframewrapper").iframe(:id => "iframeResult"). \
button(:onclick => "myFunction()").click
The result is that a popup will appear, but no popups will appear further attempts to click on the button once the script is done.
This includes even if no popup is triggered during the script (ie:, last line commented out)... Once the script is finished running, no popups appear in a watir webdriver opened window. (They will open if I click on the button while the script is running, but not after)
Based on the answer below, I am using:
begin
b = Watir::Browser.new :firefox
File.open('d:\\MARK.TXT', 'w') {|f| f.write(YAML.dump(b)) }
# Load MessageBox and wait here
b = YAML.load(File.read('d:\\MARK.TXT'))
ensure
if !b.nil?
b.close()
end
end
... but it currently allows for errors that can be ignored... I just don't know how wise it is to ignore them in the long run:
D:/Ruby193/lib/ruby/gems/1.9.1/gems/childprocess-0.5.6/lib/childprocess/windows/handle.rb:50:in `exit_code': The handle is invalid. (6) (ChildProcess::Error)
from D:/Ruby193/lib/ruby/gems/1.9.1/gems/childprocess-0.5.6/lib/childprocess/windows/process.rb:41:in `exited?'
from D:/Ruby193/lib/ruby/gems/1.9.1/gems/childprocess-0.5.6/lib/childprocess/abstract_process.rb:147:in `poll_for_exit'
from D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/firefox/binary.rb:59:in `quit'
from D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/firefox/launcher.rb:62:in `quit'
from D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/firefox/bridge.rb:75:in `quit'
from D:/Ruby193/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.46.2/lib/selenium/webdriver/common/driver.rb:165:in `quit'
from D:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-webdriver-0.7.0/lib/watir-webdriver/browser.rb:136:in `close'
from D:/Users/risendevil/Documents/Aptana Studio 3 Workspace/Ruby Test/Default.rb:19:in `<main>'
Versions:
Firefox 38.0.5
selenium (0.2.11)
selenium-webdriver (2.46.2, 2.45.0)
watir-webdriver (0.7.0)
I learned something new answering your question: Turning an object into text is called serialization. Turning text into an object is called deserialization.
And here's a gist of you want to do, specifically.
The important part is
my_object = SomeObject.new
my_object.some_method # => returns your expected result
File.open('path/to/some.file', 'w') {|f| f.write(YAML.dump(my_object)) }
# Do whatever you want
my_object_reloaded = YAML.load(File.read('path/to/some.file'))
my_object_reloaded.some_method # => returns your expected result
You could even do this directly to your browser:
b = Watir::Browser.new
b.goto 'http://google.com' # => goes to Google
File.open('path/to/some.file', 'w') {|f| f.write(YAML.dump(b)) }
b = nil
# Do whatever you want, wait as long as you want.
# (Disclaimer: There are probably major limitations to 'as long as you want'.)
b = YAML.load(File.read('path/to/some.file'))
b.goto 'http://yahoo.com' # => goes to Yahoo
require "watir-webdriver"
l_Browser = Watir::Browser.new :firefox
l_Browser.goto "http://www.w3schools.com/js/tryit.asp?filename=tryjs_alert"
l_Browser.iframe(:id => 'iframeResult').button(:xpath => "//button[text()='Try it']").when_present.click # click on "Try it" button
l_Browser.alert.close # closing popup
Related
I'm using mechanize to fill out a form, but I want to review it on the webpage before submission. The goal is to open a browser with the pre-filled form.
require 'mechanize'
mechanize = Mechanize.new
page = mechanize.get('https://www.linuxtoday.com/contribute.html')
form = page.form_with :name => 'upload'
form.sub_name = "mbb"
form.email = "mbb#mbb.com"
form.author_name = "Mr Potatohead"
form.title = "Mr Potatohead writes Ruby"
form.link = "https://potato.potato"
form.body = "More text"
`open #{page.uri}`
Calling out to the operating system to open the site is, of course, empty form. I don't see a page.open or similar method available. Is there a way to achieve this (using mechanize or other gems)?
That won't work because setting form fields doesn't even update the DOM.
If you want to review the form data you can inspect form.request_data
As others have mentioned in the comments try selenium, you'll need chrome or firefox driver installed, here's example with chrome to get you started:
require 'selenium-webdriver'
require 'pry' # optional
driver = Selenium::WebDriver.for :chrome
driver.navigate.to 'https://www.linuxtoday.com/contribute.html'
form = driver.find_element(id: 'upload')
form.find_element(id: 'sub_name').send_keys 'mbb'
form.find_element(id: 'email').send_keys 'mbb#mbb.com'
binding.pry # or sleep 60
driver.quit
For more instructions see documentation
I have done a lot of research before asking this questions but unable to find an answer.
I am trying to automate a website using Ruby Selenium + Webdriver. I am having an issue with the script hanging once new window opened. I am unable to focus on new window or do anything else.
Here is the code that opens up new window:
<a id="theField" class="RightTextHeading" onclick="javascript:openTheWindow('someInfo.aspx?type=','300','300');if(window.document.RetValue == '5'){window.parent.LoadinIframe('someStuff.aspx?info=N&Stuff=','Some Data here > Full View','false');}; return false;" href="../MoreStuff/#" style="text-decoration: none;">ClickMe <span class="context"> opens an overlay</span></a>
Here is my ruby code:
require 'rubygems'
require 'watir-webdriver'
require 'selenium-webdriver'
prefs = {
:download => {
:prompt_for_download => false,
:default_directory => '.'
}
}
client = Selenium::WebDriver::Remote::Http::Default.new
#client.timeout = 600 # seconds - default is 60
client.timeout = 30 # seconds - default is 60
d = Selenium::WebDriver.for :chrome, :prefs => prefs, :http_client => client
b = Watir::Browser.new d
saved_cookies = b.cookies.to_a
b.goto'https://somewebsite.com'
begin
b.iframe(:id => 'iframeBody').a(:id => "somelink").click
rescue
puts 'Rescue'
end
sleep 2
puts "before"
#if b.window(:title=>"The new window").exists?
#puts " Test passed. New window opened!"
#else
#puts " Test Failed! No window found"
#end
#b.window(:title => /The new window/).use do
#b.window.last.use do
# puts "here"
#end
#puts b.window(:title => "The new window").exists?
puts b.windows.size
puts "after"
#b.close
I have commented out different things I attempted to make this work.
It seems that Ruby just sits and waits after the new window is opened and I do not know how to get it out of the waiting state.
If I do not begin/rescue, the code stops execution until it times out.
When I am trying to rescue I can get control back but still unable to focus on the new window.
Any ideas are appreciated?
Please let me know if you have additional questions.
Thanks,
-Andrey
Im not entirely sure what your trying to do with the test, but the answer on how to do something with the new window is already in your code to some extent
#b.window.last.use do
should be
#b.windows.last.use
or
#browser.windows.last.use
Will have your test start using the new window once it appears.
Depending on what your trying to do, may change where in your code that line should go. But that will let you access and interact with the new window.
I am trying to automate an online survey on a website but I get this error each time:
Selenium::WebDriver::Error::UnknownError: unknown error: Element is not clickable at
point (561, 864). Other element would receive the click: a id="habla_oplink_a"
class="habla_oplink_a_normal hbl_pal_header_font_size hbl_pal_title_fg "
What I need to understand is how I can scroll to a certain point of the page so that my script can resume filling out the survey on the page.
This is my code that manages to fill out a portion of the survey but fails when it reaches a row which is not in view inside the browser (a row that requires the user to scroll down to):
buttons = browser.elements(:class => "assessment-choice")
buttons.each do |button|
button.click
end
I would also like to be able to change my code so that it only selects a specific option but the HTML on the page is not very friendly.
This is the webpage I am looking at: https://staging2.clearfit.com/assessment/assessment/95867fb272df436352a0bd5fbdd
The HTML of one of the options on the survey:
<a id="answers_79_0" class="assessment-choice" onmouseover="answerOver(this)" onmouseout="answerOut(this)" onclick="setAssessmentAnswer(this, 3, '0', '79', '#answers_49839163')">Strongly<br>Agree</a>
Using execute_script
To scroll to an element, you will need to execute javascript:
browser.execute_script('arguments[0].scrollIntoView();', button)
This can be seen to be working in the following script. Without the line to scroll, a chat tab overlays one of the buttons causing an exception.
require 'watir-webdriver'
browser = Watir::Browser.new :chrome
browser.goto 'https://staging2.clearfit.com/assessment/assessment/95867fb272df436352a0bd5fbdd'
buttons = browser.elements(:class => "assessment-choice")
buttons.each do |button|
browser.execute_script('arguments[0].scrollIntoView();', button)
button.click
end
Using the watir-scroll gem
Note that you can install the watir-scroll gem to make the scrolling line nicer. The gem allows the line to simply be:
browser.scroll.to button
The script would then look like:
require 'watir-webdriver'
require 'watir-scroll'
browser = Watir::Browser.new :chrome
browser.goto 'https://staging2.clearfit.com/assessment/assessment/95867fb272df436352a0bd5fbdd'
buttons = browser.elements(:class => "assessment-choice")
buttons.each do |button|
browser.scroll.to button
button.click
end
Firstly, this should be unnecessary. According to the spec, all element interactions require implicit scrolling to the element. If something does prevent this from happening, though, you can use this Selenium method instead of a javascript implementation:
buttons = browser.elements(:class => "assessment-choice")
buttons.each do |button|
button.wd.location_once_scrolled_into_view
button.click
end
public
def scroll_to(param)
args = case param
when :top, :start
'window.scrollTo(0, 0);'
when :center
'window.scrollTo(window.outerWidth / 2, window.outerHeight / 2);'
when :bottom, :end
'window.scrollTo(0, document.body.scrollHeight);'
when Array
['window.scrollTo(arguments[0], arguments[1]);', Integer(param[0]), Integer(param[1])]
else
raise ArgumentError, "Don't know how to scroll to: #{param}!"
end
#browser.execute_script(*args)
end
public
# This method pulls the object on the page you want to interact with, then it 'jumps to it'.
def jump_to(param)
# Leveraging the scroll_to(param) logic, this grabs the cooridnates,
# and then makes them an array that is able to be located and moved to.
# This is helpful when pages are getting too long and you need to click a button
# or interact with the browser, but the page 'Cannot locate element'.
location = param.wd.location
location = location.to_a
$helper.scroll_to(location)
end
Then you just call jump_to(element) and it "Jumps" to it.
This is how I got around it- not sure if that is a normal way. The problem is it goes to point (0,0); working on a version that moves to it to center screen.
I am trying to write a crawler that crawls all links from loaded page and logs all request and response headers along with response body in some file say XML or txt. I am opening all links from first loaded page in new browser window so I wont get this error:
Element not found in the cache - perhaps the page has changed since it was looked up
I want to know what could be the alternate way to make requests and receive response from all links and then locate input elements and submit buttons form all opened windows.
I am able to do above to some extent except when opened window has common site searh box like one on this http://www.testfire.net in the upper right corner.
What I want to do is I want to omit such common boxes so that I can fill other inputs with values using i.send_keys "value" method of webdriver and dont get this error
ERROR: Element not found in the cache - perhaps the page has changed since it was looked up.
What is the way to detect and distinguish input tags from each opened window so that value does not get filled repeatably in common input tags that appear on most pages of website.
My code is following:
require 'rubygems'
require 'selenium-webdriver'
require 'timeout'
class Clicker
def open_new_window(url)
#driver = Selenium::WebDriver.for :firefox
#url = #driver.get " http://test.acunetix.com "
#link = Array.new(#driver.find_elements(:tag_name, "a"))
#windows = Array.new(#driver.window_handles())
#link.each do |a|
a = #driver.execute_script("var d=document,a=d.createElement('a');a.target='_blank';a.href=arguments[0];a.innerHTML='.';d.body.appendChild(a);return a", a)
a.click
end
i = #driver.window_handles
i[0..i.length].each do |handle|
#driver.switch_to().window(handle)
puts #driver.current_url()
inputs = Array.new(#driver.find_elements(:tag_name, 'input'))
forms = Array.new(#driver.find_elements(:tag_name, 'form'))
inputs.each do |i|
begin
i.send_keys "value"
puts i.class
i.submit
rescue Timeout::Error => exc
puts "ERROR: #{exc.message}"
rescue Errno::ETIMEDOUT => exc
puts "ERROR: #{exc.message}"
rescue Exception => exc
puts "ERROR: #{exc.message}"
end
end
forms.each do |j|
begin
j.send_keys "value"
j.submit
rescue Timeout::Error => exc
puts "ERROR: #{exc.message}"
rescue Errno::ETIMEDOUT => exc
puts "ERROR: #{exc.message}"
rescue Exception => exc
puts "ERROR: #{exc.message}"
end
end
end
#Switch back to the original window
#driver.switch_to().window(i[0])
end
end
ol = Clicker.new
url = ""
ol.open_new_window(url)
Guide me how can I get all requeat and response headers with response body using Selenium Webdriver or using http.set_debug_output of ruby's net/http ?
Selenium is not one of the best options to use to attempt to build a "web-crawler". It can be too flakey at times, especially when it comes across unexpected scenarios. Selenium WebDriver is a great tool for automating and testing expectancies and user interactions.
Instead, good old fashioned curl would probably be a better option for web-crawling. Also, I am pretty sure there are some ruby gems that might help you web-crawl, just Google search it!
But To answer the actual question if you were to use Selenium WebDriver:
I'd work out a filtering algorithm where you can add the HTML of an element that you interact with to an variable array. Then, when you go on to the next window/tab/link, it would check against the variable array and skip the element if it finds a matching HTML value.
Unfortunately, SWD does not support getting request headers and responses with its API. The common work-around is to use a third party proxy to intercept the requests.
============
Now I'd like to address a few issues with your code.
I'd suggest before iterating over the links, add a #default_current_window = #driver.window_handle. This will allow you to always return back to the correct window at the end of your script when you call #driver.switch_to.window(#default_current_window).
In your #links iterator, instead of iterating over all the possible windows that could be displayed, use #driver.switch_to.window(#driver.window_handles.last). This will switch to the most recently displayed new window (and it only needs to happen once per link click!).
You can DRY up your inputs and form code by doing something like this:
inputs = []
inputs << #driver.find_elements(:tag_name => "input")
inputs << #driver.find_elements(:tag_name => "form")
inputs.flatten
inputs.each do |i|
begin
i.send_keys "value"
i.submit
rescue e
puts "ERROR: #{e.message}"
end
end
Please note how I just added all of the elements you wanted SWD to find into a single array variable that you iterate over. Then, when something bad happens, a single rescue is needed (I assume you don't want to automatically quit from there, which is why you just want to print the message to the screen).
Learning to DRY up your code and use external gems will help you achieve a lot of what you are trying to do, and at a faster pace.
I'm trying to automate the process of searching for alternative telephone numbers using SayNoTo0870 . Every time one searches for an alternate number or name it brings up the '/companysearch.php' page.
Clearly this page has no reference, and in my mind you can't just link to this page.
What I'm hoping to do is use the code below, to automate the opening of a browser, searching of a name/number, stripping out the HTML and then providing the top 5 results. I've got the automation part down, but clearly when trying to save the webpage using Hpricot it only brings up the 'Sorry nothing can be found page' because I can't link directly to the search result page.
Here is my code thus far:
(I've removed comments to shorten it)
require 'rubygems'
require 'watir'
require 'hpricot'
require 'open-uri'
class OH870
def searchName(name)
browser = Watir::Browser.new
browser.goto 'http://www.saynoto0870.com/search.php'
browser.text_field(:name => 'search_name').set name
browser.button(:name => 'submit').click
end
def searchNumber(number)
browser = Watir::Browser.new
browser.goto 'http://www.saynoto0870.com/search.php'
browser.text_field(:name => 'number').set number
browser.button(:name => 'submit').click
end
def loadNew(website)
doc = Hpricot(open(website))
puts(doc)
end
def strip_tags
stripped = website.gsub( %r{</?[^>]+?>}, '' )
puts stripped
end
end # class
class Main < OH870
puts "What is the name of the place you want?"
website = 'http://www.saynoto0870.com/companysearch.php'
question = gets.chomp
whichNumber = OH870.new
whichNumber.searchName(question)
#result = OH870.new
#withoutTags = website.strip_tags
#result.loadNew(withoutTags)
end
Now I'm not sure whether there's a way of "asking watir to follow through to the companysearch.php page and dump the results without having to pass this page as a variable.
I wonder if anyone has any suggestions here?
With WATIR, minus the extraneous libraries, here's all it takes to accomplish what you've described (using the 'name' test case only). I've pulled it out of the function format since you already know how to do that, and this will be a clearer test case path.
require 'watir'
#browser = Watir::Browser.new :firefox #open a browser called #browser
#browser.goto "http://(your search page here)" #go to the search page
#browser.text_field(:name => 'name').value = "Awesome" #fill in the 'name' field
#browser.button(:name => 'submit').click #submit the form
If all goes well, we should now be looking at the search results. WATIR already knows it's on a new page - we don't have to specify a URL. In the case that the results are in a frame, we do need to access that frame before we can view its content. Let's pretend they're in a DIV element with an ID of "search_results":
results = #browser.div(:id => "search_results").text
resultsFrame = #browser.frame(:index => 1) #in the case of a frame
results = resultsFrame.div(id => "search_results).text
As you can see, you do not need to save the entire page to parse the results. They could be in table cells, they could be in a different div per line, or a new frame. All are easily accessible with WATIR to be stored in a variable, array, or immediately written to the console or log file.
#results = Array.new #create an Array to store our results
#browser.divs.each do |div| #for each div element on the page
if div.id == "search_results" #if the div ID equals "search_results"
#results << div.text #add it to our array named #results
end
end
Now, if you just wanted the top 5 there are many ways to access them.
#results[0] #first element
#results[0..4] #first 5 elements
I'd also suggest you look into a few programming principles like DRY (Don't Repeat Yourself). In your function definitions where you see that they share code, like opening the browser and visiting the same URL - you can consolidate those:
def search(how, what)
#browser = Watir::Browser.new :firefox
#browser.goto "(that search url again)"
#browser.text_field(:name => how).value = what
etc...
end
search("name", "Hilton")
search("number", "555555")
Since we know that the two available text_field names are "name" and "number", and those make good logical sense as a 'how', we can parameterize them and use a single function for both the Search by Name and Search by Number test cases. This is more efficient, as long as the test cases remain similar enough to be shared.