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.
Related
No matter what I try to do, the browser tries to run the test too fast before it has a chance to find the element that I am looking for. If I put in a simple "sleep 2", it has a chance for the drop down menu to drop and load and successfully find the element. But I am wanting to learn to use the Selenium Wait command. I have tried numerous combinations of the below and looked all over the web for documentation or perhaps examples. I have found plenty of firefox and people say that some of the things below worked perfectly in firefox, but for me and my project team mates, we can not get any of the waits, implicit or explicit, to pause long enough for it to detect the element. The element does not exist until the drop down menu is fully dropped, then it can detect it. It doesn't take 2 seconds but it seems that none of my wait commands will actually make it wait. Like I said, I have tried numerous different things and almost all of them are below. If anyone can help guide me, i would appreciate it. Here is some of the code I have tried:
def setup
#driver = Selenium::WebDriver.for :chrome
#driver.get "https://website.herokuapp.com/"
#wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
# #driver = Selenium::WebDriver.for:chrome
# #driver.manage.timeouts.implicit_wait = 30
# #wait = Selenium::WebDriver::Wait.new(:timeout => 15)
# #wait = Selenium::WebDriver::Wait.new(:timeout => 10)
# #driver.manage.timeouts.implicit_wait = 10
# #wait = Selenium::WebDriver::Wait.new(timeout: 10)
#driver.manage.window.maximize()
# #driver.navigate.to("https://website.herokuapp.com/")
end
def test_user_name_is_present
login()
#driver.find_element(:class, "navbar-toggle").click()
# user = #driver.find_element(:class, "dropdown-toggle").text
# #wait.until{#driver.find_element(:class, "dropdown-toggle")}
#driver.find_element(:class, "dropdown-toggle")
#wait.until { #driver.find_element(:class => "dropdown-toggle") }
user = #driver.find_element(:class, "dropdown-toggle").text
assert_equal(true, user.include?('HEATHER'), "no user")
end
I'm more familiar with JavaScript or Java bindings.
But what about:
def test_user_name_is_present
login()
#driver.find_element(:class, "navbar-toggle").click()
#wait.until { #driver.find_element(:class => "dropdown-toggle").displayed? }
user = #driver.find_element(:class, "dropdown-toggle").text
assert_equal(true, user.include?('HEATHER'), "no user")
end
Our team uses this, just add to your test_helper.rb if using rails
def wait_for_ajax(sleep_sec = 4)
assert page.has_no_content?(:css, 'body.loading')
sleep sleep_sec if sleep_sec
end
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
I'm pretty new to ruby and am trying to implement a Tk application that will display a window prompting for input at a certain interval. In between the interval I want the window to not display in any taskbars, etc. and so I've implemented the following code that seems to work perfectly the first time through, but after the window displays the second time and I enter text in the TkEntry and click the TkButton the window is dismissed and never returns. I've tried putting in some "puts" calls at key locations to see what is happening and it seems that it never even makes it past the call to "displayUi".
*EDIT:
I'm running ruby 1.9.3p385 (2013-02-06) [i386-mingw32] on a Windows 7 system (in case that makes any difference)
Any help (even if it's providing a different mechanism to accomplish the same goal) would be appreciated, but please keep in mind that I'm a ruby noobie. Thanks!
require "tk"
class Sample
attr_accessor :root, :active
#active = false
def initialize
# init
end
def entry (task)
# do some work here
#active = false
end
def displayUi ()
#active = true
if (#root.nil?)
#root = TkRoot.new { title "Sample App" }
else
# already running just restart
Tk.restart
end
TkLabel.new(#root) {
text 'Sample Text'
pack { padx 15; pady 15; side 'left' }
}
statusInput = TkEntry.new(#root) {
pack('side'=>'left', 'padx'=>10, 'pady'=>10)
}
statusInput.focus
response = TkVariable.new
statusInput.textvariable = response
TkButton.new(#root, :text => "Ok", :command => proc { entry(response.value); #root.destroy }) {
pack('side'=>'left', 'padx'=>10, 'pady'=>10)
}
Tk.mainloop
end
end
i=0
st = Sample.new
while (true)
if (!st.active)
st.displayUi()
end
sleep(1)
end
I'm trying to write simple test. My problem is, that i want to wait until the page is loaded completly. At the moment i'm waiting until some elements are presen, but that is not really what i want. Is it possible to make something like this:
driver = Selenium::WebDriver.for :chrome
driver.navigate.to url
driver.wait_for_page_to_load "30000"
With Java isn't problem, but how to make it with ruby?
This is how the Selenium docs () suggest:
require 'rubygems'
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.get "http://google.com"
element = driver.find_element :name => "q"
element.send_keys "Cheese!"
element.submit
puts "Page title is #{driver.title}"
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { driver.title.downcase.start_with? "cheese!" }
puts "Page title is #{driver.title}"
driver.quit
If that is not an option you can try the suggestion from this SO post though it would require some Javascript on top of the Ruby/Rails.
It seems that wait.until is being/has been phased out. The new suggested process it to look for the page to have an element you know will be there:
expect(page).to have_selector '#main_div_id'
As far as I understand webdriver, you dont need to wait for page loads because WebDriver has a blocking API but you can sure set a page load timeout.
driver.manage.timeouts.page_load = 10 # seconds
So in Ruby, whenever you use get to open a URL, the ruby script proceeds ONLY when the page completely loads.
So in your case you would simply do :-
driver.get url
That's not needed with WebDriver anymore.
WebElement click() and Actions click() both "wait for page load" if needed automatically.
You can use imclicit and explicit (in this order) wait instead (described at seleniumhq) if you need to wait for some ajax content for instance.
There have been instances where either AJAX or CSS changes caused my tests to fail at times. I added these methods to my static driver instance so that I can have the test wait for certain conditions if needed. (c#)
TimedWait in the WaitForCssChange Method is basically just a Threading.Thread.Sleep This is not the most beautiful way I guess, but it works well for my needs.
For Ajax wait:
public static void WaitForAjax()
{
var wait = new WebDriverWait(Driver.Instance, TimeSpan.FromSeconds(25));
wait.Until(d => (bool)(d as IJavaScriptExecutor).ExecuteScript("return jQuery.active == 0"));
}
For CSS Changes:
public static void WaitForCssChange(IWebElement element, string value)
{
int counter = 0;
while (true)
{
if(element.GetAttribute("style").Contains(value) || counter > 50)
{
break;
}
TimedWait(20);
counter++;
}
}
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.