I've written a Ruby script to automate some user operations using IE.
I'm using Selenium Web Driver for IE. Below is my code.
require 'selenium-webdriver'
browser = Selenium::WebDriver.for :ie
first_window = browser.window_handle
browser.switch_to.frame(browser.find_element(:id=> 'outerFrame'))
browser.switch_to.frame(browser.find_element(:id=> 'innerFrame'))
table_rows = browser.find_element(:id=> 'AllItems').find_element(:tag_name=> 'table').find_elements(:tag_name=> 'tr')
count_cell = table_rows.at(table_rows.length-1).find_elements(:tag_name=> 'td').at(1).find_element(:tag_name=> 'a')
count_cell.click
sleep(5)
all_windows = browser.window_handles
new_window = browser.window_handles.last
browser.switch_to.window(new_window)
btn = browser.find_element(:id=> 'btn_export')
btn.click
At one point, after clicking a button, a new page is opened. Now, when I try to switch to the new window, I get the following error.
C:/Ruby21/lib/ruby/2.1.0/net/http.rb:879:in 'initialize': No
connection could be made because the target machine actively refused
it. - connect(2) for "127.0.0.1" port 5555 (Errno::ECONNREFUSED)
from C:/Ruby21/lib/ruby/2.1.0/net/http.rb:879:in 'open'
from C:/Ruby21/lib/ruby/2.1.0/net/http.rb:879:in 'block in connect'
from C:/Ruby21/lib/ruby/2.1.0/timeout.rb:75:in 'timeout'
from C:/Ruby21/lib/ruby/2.1.0/net/http.rb:878:in 'connect'
from C:/Ruby21/lib/ruby/2.1.0/net/http.rb:863:in 'do_start'
from C:/Ruby21/lib/ruby/2.1.0/net/http.rb:852:in 'start'
from C:/Ruby21/lib/ruby/2.1.0/net/http.rb:1375:in 'request'
from C:/Ruby21/lib/ruby/gems/2.1.0/gems/selenium-webdriver-2.48.1/lib/selenium/webdriver/remote/http/default.rb:107:in 'response_for'
from C:/Ruby21/lib/ruby/gems/2.1.0/gems/selenium-webdriver-2.48.1/lib/selenium/webdriver/remote/http/default.rb:58:in
'request'
from C:/Ruby21/lib/ruby/gems/2.1.0/gems/selenium-webdriver-2.48.1/lib/selenium/webdriver/remote/http/common.rb:59:in
'call'
from C:/Ruby21/lib/ruby/gems/2.1.0/gems/selenium-webdriver-2.48.1/lib/selenium/webdriver/remote/bridge.rb:664:in
'raw_execute'
from C:/Ruby21/lib/ruby/gems/2.1.0/gems/selenium-webdriver-2.48.1/lib/selenium/webdriver/remote/bridge.rb:642:in
'execute'
from C:/Ruby21/lib/ruby/gems/2.1.0/gems/selenium-webdriver-2.48.1/lib/selenium/webdriver/remote/bridge.rb:216:in
'switchToWindow'
from C:/Ruby21/lib/ruby/gems/2.1.0/gems/selenium-webdriver-2.48.1/lib/selenium/webdriver/common/target_locator.rb:81:in
'window'
from script.rb:18:in ''
I tried my bit to resolve the error, by modifying firewall and added rules for port 5555. Even then issue persists. I found some already exsting questions on this, but most of them are related to Java or .Net. How can I resolve this error? Can anyone point me in the right direction?
I am not a ruby expert, but I have seen similar problems happening. I have a Python-ic solution. All you need to do is Ruby-fy the code. https://gist.github.com/ab9-er/08c3ce7d2d5cdfa94bc7
def change_window(browser):
"""
Simple window switcher without the need of playing with ids.
#param browser: Current browser instance
"""
curr = browser.current_window_handle
all_handles = browser.window_handles
for handle in list(set([curr]) - set(all_handles)):
return browser.switch_to_window(handle)
Try switching back to the top level browsing context before switching to a new window.
browser.switch_to.default_content
current_window = browser.window_handle
new_window = browser.window_handles.find { |win| win != current_window }
browser.switch_to.window(new_window)
It should do this implicitly, so if it isn't, it's likely a bug. If this works, please let me know so I can see if we need to file a bug report.
Related
I'm using the Selenium Webdriver gem to try to click on the facebook chat bar, sometimes it work and sometimes it doesn't. When it does not work it returns the Selenium Element not visible error, but it clearly is visible. I'm not sure what's wrong with my code.
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome # instantiates a google chrome session
driver.navigate.to 'https://www.facebook.com/' # takes you to facebook.com
emailBar = driver.find_element(:id,"email") #finds email input bar
passwordBar = driver.find_element(:id,"pass") #find password input bar
loginButton = driver.find_element(:id,"u_0_n") #finds login button
emailBar.send_keys "austinspreadsheet#gmail.com" # puts in the email
passwordBar.send_keys "YOURPASSWORD" # puts in the password
loginButton.click # clicks the login button
#THIS IS THE CODE BLOCK THAT DOES NOT WORK
links = driver.find_elements(:class,"fbNubButton") # finds the chat bar
#driver.manage.timeouts.page_load = 10
links[0].click # opens the chat bar
links[1].click # NOTE that sometime it clicks and sometimes it doesn't but if you click both chat box classes it usually works, so the error is ok
I have tried not clicking both chat links and it works less when I do that.
I am using Selenium with Python. In case like yours the issue is related to waiting until all the elements in the page are full loaded.
The basic behavior of Selenium offers you Explicit and Implicit Waits. So basicly you can force the system to wait a default number of second or wait until an element is loaded.
From Selenium documentation (http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp)
Explicit wait
An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code. The worst case of this is Thread.sleep(), which sets the condition to an exact time period to wait. There are some convenience methods provided that help you write code that will wait only as long as required. WebDriverWait in combination with ExpectedCondition is one way this can be accomplished.
require 'rubygems' # not required for ruby 1.9 or if you installed without gem
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.get "http://somedomain/url_that_delays_loading"
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
begin
element = wait.until { driver.find_element(:id => "some-dynamic-element") }
ensure
driver.quit
end
Implicit wait
An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available. The default setting is 0. Once set, the implicit wait is set for the life of the WebDriver object instance.
require 'rubygems' # not required for ruby 1.9 or if you installed without gem
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.manage.timeouts.implicit_wait = 10 # seconds
driver.get "http://somedomain/url_that_delays_loading"
element = driver.find_element(:id => "some-dynamic-element")
The answer that aberna gives you on this thread has a lot of great information but it isn't going to solve your issue. If you use the Explicit wait method that aberna suggests, you also probably need to make sure the element is visible. Using .findElements on its own doesn't guarantee clickability/visibility . You could try to use expectedconditions .visibilityOfElementLocated which will also check for visibility as well as presence.
Or, alternatively, you can check for presence of the element on the DOM using .findElement but then use the expectedconditions.visibilityOf to check for the visibility part of it.
I am using sleep(5) before run main logic
I was facing the same issue. Solution that worked for me was to maximise my browser window. This solved many of failing specs.
Capybara.current_session.driver.browser.manage.window.maximize
I'm using Capybara to fill in a form and download the results.
It's a bit slow when filling in the form, and I want to check if JavaScript is the culprit.
How do I turn off JavaScript?
The Ruby code was something similar to, but not the same as, the following (the following won't reproduce the error message, but it is somewhat slow).
require "capybara"
url = "http://www.hiv.lanl.gov/content/sequence/HIGHLIGHT/highlighter.html"
fasta_text = [">seq1", "gattaca" * 1000, ">seq2", "aattaca" * 1000].join("\n")
session = Capybara::Session.new(:selenium)
# Code similar to this was run several times
session.visit(url)
session.fill_in('sample', :with => fasta_text)
session.click_on('Submit')
And the error I was getting (with my real code, but not the code I have above) was
Warning: Unresponsive script
A script on this page may be busy, or it may have stopped responding.
You can stop the script now, open the script in the debugger, or let
the script continue.
Script: chrome://browser/content/tabbrowser.xml:2884
I wasn't running Capybara as part of a test or as part of a spec.
To confirm that the code I wrote currently has JavaScript enabled (which is something I want to disable), doing
url = "http://www.isjavascriptenabled.com"
session = Capybara::Session.new(:selenium)
session.visit(url)
indicates that JavaScript is enabled.
Capybara only uses JavaScript if you've specified a javascript_browser:
Capybara.javascript_driver = :poltergeist
And if you've specified js: true as metadata in your spec:
context "this is a test", js: true do
Check for both of those things. If they're not there and the test is not running in a browser or using Poltergeist, then it's probably not using JavaScript.
I have some JavaScript in my app that detects when the network connection goes away and temporarily caches data in local storage, to be synced with the server when the connection is re-established.
I've been trying to find a way to test this end-to-end using Capybara, but I can't seem to find any way of either temporarily disabling the app server or switching the headless browser into offline mode. FWIW I'm using Poltergeist as the driver.
Does anyone have an idea how this could be tested? (I can test the JavaScript app using sinon to fake the server going away, but I'd like to be able to test it end-to-end with a headless browser if possible).
If you stumbled on this question looking for a way to test offline / progressive web apps with Capybara and Chrome Headless, here's how:
params = {
cmd: 'Network.emulateNetworkConditions',
params: {
offline: true,
latency: 0,
downloadThroughput: 0,
uploadThroughput: 0
}
}
page.driver.browser.send(:bridge).send_command(params)
My team has stubbed out the Rack app to simulated errors from the server. It works well enough (in Firefox). Here are some relevant excerpts from the code:
class NoResponseRack
attr_reader :requests
def initialize disconnected_mode
#disconnected_mode = disconnected_mode
#requests = []
#sleeping_threads = []
end
def call(env)
#requests.push(env)
case #disconnected_mode
when :elb_pool_empty
#sleeping_threads << Thread.current
sleep 65
#sleeping_threads.delete Thread.current
[504, {}, ['']]
when :server_maintenance
[200, {}, ['status_message=Atlas is down for maintenance.']]
else
[999, {}, [""]]
end
end
def wakeup_sleeping_threads
#sleeping_threads.each &:wakeup
#sleeping_threads.clear
end
end
def go_disconnected_with_proxy disconnected_mode=:server_error
if $proxy_server_disconnected
puts 'going DISconnected'
$current_proxy = NoResponseRack.new disconnected_mode
rack_mappings.unshift([nil, "", /^(.*)/n, $current_proxy])
$proxy_server_disconnected = false
end
end
def rack_app
Capybara::current_session.driver.app
end
def rack_mappings
rack_app.instance_variable_get(:#mapping)
end
About the only way I can think of would be to allow the host to be overridden in your tests, and give it a bogus host (something like localhost:31337).
Maybe have a look at http://robots.thoughtbot.com/using-capybara-to-test-javascript-that-makes-http and see if anything jumps out.
I found also another option. To start Chrome with
options.add_argument('--host-resolver-rules=MAP * ~NOTFOUND')
I saw this in chromium docs because this flag was missing from google-chrome --help.
Which link also means that you can also use your own proxy server to simulate different conditions as well.
I am trying to use ruby and Mechanize to parse data on foursquare's website. Here is my code:
require 'rubygems'
require 'mechanize'
agent = Mechanize.new
page = agent.get('https://foursquare.com')
page = agent.click page.link_with(:text => /Log In/)
form = page.forms[1]
form.F12778070592981DXGWJ = ARGV[0]
form.F1277807059296KSFTWQ = ARGV[1]
page = form.submit form.buttons.first
puts page.body
But then, when I run this code, the following error poped up:
C:/Ruby192/lib/ruby/gems/1.9.1/gems/mechanize-2.0.1/lib/mechanize/form.rb:162:in
`method_missing': undefined method `F12778070592981DXGWJ='
for #<Mechanize::Form:0x2b31f70> (NoMethodError)
from four.rb:10:in `<main>'
I checked and found that these two variables for the form object "F12778070592981DXGWJ" and "F1277807059296KSFTWQ" are changing every time when I try to open foursquare's webpage.
Does any one have the same problem before? your variables change every time you try to open a webpage? How should I solve this problem?
Our project is about parsing the data on foursquare. So I need to be able to login first.
Mechanize is useful for sites which don't expose an API, but Foursquare has an established REST API already. I'd recommend using one of the Ruby libraries, perhaps foursquare2. These libraries abstract away things like authentication, so you just have to register your app and use the provided keys.
Instead of indexing the form fields by their name, just index them by their order. That way you don't have to worry about the name that changes on each request:
form.fields[0].value = ARGV[0]
form.fields[1].value = ARGV[1]
...
However like dwhalen said, using the REST API is probably a much better way. That's why it's there.
I am able to use watir-webdriver with IE, but I would prefer to use Firefox.
Problem: I need a proxy.
By googling around, I found some code snippets, but I am not able to put all them together.
This is what I produced up to now, please let me know what am I missing:
require 'watir-webdriver'
FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("network.proxy.http", "proxy.myplace.com");
profile.setPreference("network.proxy.http_port", 8080);
WebDriver driver = new FirefoxDriver(profile);
browser = Watir::Browser.new :firefox
browser.goto( "http://www.google.com/" )
I get this error message:
I:/watir/webdriver/webdrivertest.rb:3: syntax error, unexpected tCONSTANT, expec
ting keyword_do or '{' or '('
FirefoxProfile profile = new FirefoxProfile();
Also, I don't know how to use the variable called 'driver'
Call the underlying Selenium WebDriver.
I've used this technique to set a path to Firefox 3.6 so I can test with both Firefox 4 and 3.6:
Selenium::WebDriver::Firefox.path = ENV['FIREWATIRPATH']
browser = Watir::Browser.new :firefox
So to do what you're trying to do:
profile = Selenium::WebDriver::Firefox::Profile.new
proxy = Selenium::WebDriver::Proxy.new(:http => "http://proxy.org:8080")
profile.proxy = proxy
# You have to do a little more to use the specific profile
driver = Selenium::WebDriver.for :firefox, :profile => profile
browser = Watir::Browser.new(driver)
Look at: Selenium Ruby Bindings and Webdriver FAQ for more info.
What problem are you having with the Proxy line?
You could try this:
profile = Selenium::WebDriver::Firefox::Profile.new
profile["network.proxy.type"] = 1
profile["network.proxy.http"] = "proxy.myplace.com"
profile["network.proxy.http_port"] = 8080
The idea is to see what your settings are in about:config and duplicating them in code.
profile = Selenium::WebDriver::Firefox::Profile.new
profile.proxy = Selenium::WebDriver::Proxy.new :http => '12.12.12.12:8888', :ssl => '15.15.15.15:443'
browser = Watir::Browser.new :firefox, :profile => profile
The base problem in your original question is right in the error message
webdrivertest.rb:3: syntax error, unexpected tCONSTANT, expecting keyword_do or '{' or '('
The ruby interpreter is seeing something on the third line of your script that looks like a constant, in a place it's expecting something else.
I suspect it's the start of the line where ruby expects a variable name, and you have a classname. Ruby expects variables named starting with an uppercase to be a constant. which is fine for defining a class, but not creating an instance of one, since the instance won't be a constant.
It also looks like you are trying to do a new invocation using a 'new' keyword ala some other language, instead of using a .new method on whatever object you want to make a new one of, the ruby way.
Compare the code in the answer by Mike where he does
profile = Selenium::WebDriver::Firefox::Profile.new
verses what you were trying to do on line 3
FirefoxProfile profile = new FirefoxProfile();
See how different they are? His is the way to do it.