WebDriver Selenium ReadTimeout on Find_Elements - ruby

I've built a test pack that runs thru hundreds of pages. I'm using find_elements to check the rendering of the page. This should just return an array and continue the test. However I'm getting ReadTimeout after the max client timeout:
Net::ReadTimeout: Net::ReadTimeout
/home/ken/.rvm/gems/ruby-2.2.2/gems/selenium-webdriver-2.53.0/lib/selenium/webdriver/remote/http/default.rb:107:in `response_for'
/home/ken/.rvm/gems/ruby-2.2.2/gems/selenium-webdriver-2.53.0/lib/selenium/webdriver/remote/http/default.rb:58:in `request'
/home/ken/.rvm/gems/ruby-2.2.2/gems/selenium-webdriver-2.53.0/lib/selenium/webdriver/remote/http/common.rb:59:in `call'
/home/ken/.rvm/gems/ruby-2.2.2/gems/selenium-webdriver-2.53.0/lib/selenium/webdriver/remote/bridge.rb:649:in `raw_execute'
/home/ken/.rvm/gems/ruby-2.2.2/gems/selenium-webdriver-2.53.0/lib/selenium/webdriver/remote/bridge.rb:627:in `execute'
/home/ken/.rvm/gems/ruby-2.2.2/gems/selenium-webdriver-2.53.0/lib/selenium/webdriver/remote/bridge.rb:606:in `find_elements_by'
/home/ken/.rvm/gems/ruby-2.2.2/gems/selenium-webdriver-2.53.0/lib/selenium/webdriver/common/search_context.rb:84:in `find_elements'
I don't want WebDriver to wait, just continue along.
How can I catch or bypass this so that my test completes?

If you just want to keep cycling through your list of pages, you can use a begin/rescue/end block to recover from the timeout (and possibly print out an appropriate message). Here's a contrived example that looks for a page element that doesn't exist:
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
driver.get 'http://www.iana.org/domains/reserved'
begin
element = driver.find_element(:id, "element_does_not_exist")
rescue => e
puts "element is not found"
end
# a single-line alternative:
# element = driver.find_element(:id, "element_does_not_exist") rescue
driver.quit

Related

How to hook after example has execution result and status with :aggregated_failures flag

I'm maintaining a standalone test automation suite written in Rspec & Capybara and SitePrism (No Rails).
Recently I started integrating it with Testrail for reporting - I used rspec-testrail gem for that but I had to modify it a bit, because I also wanted to send Slack notifications with test progress and report.
Anyway, the integration works smoothly, except the fact that example processing is relying on example having an exception and lack of exception causes setting the test status as Passed on Testrail.
As it appears, after :each nor after :example in Rspec.configure doesn't guarantee that the example has finished running.
I also tried around :example and around :each as described here, but to no avail.
I inspected contents of example.metadata and it looks that example.metadata[:execution_result] has only started_at variable, but a finished example would have also finished_at and status variables, according to the docs
My suspicion (after reading the relish docs) is that :aggregated_failures is the cause of different metadata structure and multiple expects running in threads that are later merged into one backtrace.
Do you know how can I wait for the example to finish or how to hook into the state where it's finished?
Or maybe I should create a custom formatter where I would hook after example notifications printed to the console (I would like to keep the stacktrace there).
My code is as follows:
Test (both assertions are failing):
require 'spec_helper'
feature 'Sign in' do
let(:login_page) { LoginPage.new }
let(:user) { { email: ENV['ADMIN_EMAIL'], password: ENV['ADMIN_PASSWORD'] } }
scenario 'is successful and user is redirected to dashboard for user with correct credentials', testrail_id: 5694 do
login_page.load
login_page.form.email.set(user[:email])
login_page.form.password.set(user[:password])
login_page.form.submit_btn.click
expect(login_page.sidebar).to have_jobs(text: "some_nonexistenttext")
login_page.logout
expect(current_url).to have_content "google.com"
end
end
Console output from the above test:
Failures:
1) Sign in is successful and user is redirected to dashboard for user with correct credentials
Got 2 failures:
1.1) Failure/Error: expect(login_page.sidebar).to have_jobs(text: "blala")
expected #has_jobs?({:text=>"some_nonexistenttext"}) to return true, got false
# ./spec/auth/login_spec.rb:13:in `block (3 levels) in <top (required)>'
1.2) Failure/Error: expect(current_url).to have_content "google.com"
expected to find text "google.com" in "https://example.com/"
# ./spec/auth/login_spec.rb:15:in `block (3 levels) in <top (required)>'
Finished in 53.91 seconds (files took 1.45 seconds to load)
4 examples, 1 failure
Failed examples:
rspec ./spec/auth/login_spec.rb:8 # Sign in is successful and user is redirected to dashboard for user with correct credentials
Spec helper:
require 'rubygems'
require 'capybara/rspec'
require 'selenium-webdriver'
require 'site_prism'
require 'slack-notifier'
require_relative '../config'
require_relative '../lib/testrail'
...
RSpec.configure do |config|
config.define_derived_metadata do |meta|
meta[:aggregate_failures] = true
end
config.example_status_persistence_file_path = 'examples.txt'
config.before :all do
testrail_initialize_test_run!
end
config.after :example, testrail_id: proc { |value| !value.nil? } do |example|
RSpec::Testrail.process(example)
end
end
processing method (slightly modified from original)
def process(example)
if example.exception
status = 5
message = example.exception.message
slack_notifier.publish(message_text "Failed")
elsif example.skipped? || example.pending?
puts 'Example skipped or pending'
status = 10
message = 'Pending or not implemented'
else
status = 1
message = ''
end
client.send_post("add_result_for_case/#{testrun['id']}/#{example.metadata[:testrail_id]}",
status_id: status,
comment: message)
end
So basically all I had to was to use a reporter listener and process notifications inside it :)
config.reporter.register_listener RSpec::Testrail::Listener.new, :start, :example_failed, :example_passed, :example_pending, :stop

How to use rspec-retry with a Selenium Net::ReadTimeout error (Ruby)

Can someone please give me a example of how to use rspec-retry with the selenium-webdriver. I am trying to get it to reattempt the navigation when there is a Net::ReadTimeout error. I found an example here but I am new to Ruby and don't think I am using it right.
What I have tried.
require 'selenium-webdriver'
require 'rspec/retry'
Selenium::WebDriver::PhantomJS.path = 'phantomjs.exe'
driver = Selenium::WebDriver.for :phantomjs
driver.manage.timeouts.page_load = 300
driver.navigate.to "http://google.com"
RSpec.configure do |config|
# show retry status in spec process
config.verbose_retry = true
# Try five times (retry 4 times)
config.default_retry_count = 5
# Only retry when Selenium raises Net::ReadTimeout
config.exceptions_to_retry = [Net::ReadTimeout]
end
puts(driver.title)
driver.quit
It sounds like you may not be using rspec at all, but just want the retry behavior that is provided by the rspec-retry gem. If that's the case, you could just use ruby's rescue and retry keywords to achieve the same thing.
For example, the following code will retry the navigation 1 time if the navigation throws a Net::ReadTimeout
require 'selenium-webdriver'
Selenium::WebDriver::PhantomJS.path = 'phantomjs.exe'
driver = Selenium::WebDriver.for :phantomjs
driver.manage.timeouts.page_load = 300
attempts = 0 # has to be outside the begin/rescue to avoid infinite loop
begin
driver.navigate.to "http://google.com"
rescue Net::ReadTimeout => e
if attempts == 0
attempts += 1
retry
else
raise
end
end

Preventing timeout when connecting to a URL

I want to see the time taken to access a url using Benchmark in the code below. I also tried to do the same thing without benchmark. That is, get time at start of test and end of test, subtract the two to get the time. Both methods end in the same timeout error.
require 'open-uri'
require 'benchmark'
response = nil
puts "opening website with benchmark..."
puts Benchmark.measure{
response = open('http://mywebsite.com')
}
puts "Done !"
status = response.status
puts status
Error:
opening website with benchmark...
C:/ruby/lib/ruby/1.8/timeout.rb:64:in `rbuf_fill': execution expired (Timeout::Error)
from C:/ruby/lib/ruby/1.8/net/protocol.rb:134:in `rbuf_fill'
from C:/ruby/lib/ruby/1.8/net/protocol.rb:116:in `readuntil'
from C:/ruby/lib/ruby/1.8/net/protocol.rb:126:in `readline'
from C:/ruby/lib/ruby/1.8/net/http.rb:2028:in `read_status_line'
from C:/ruby/lib/ruby/1.8/net/http.rb:2017:in `read_new'
from C:/ruby/lib/ruby/1.8/net/http.rb:1051:in `request'
from C:/ruby/lib/ruby/1.8/open-uri.rb:248:in `open_http'
from C:/ruby/lib/ruby/1.8/net/http.rb:543:in `start'
from C:/ruby/lib/ruby/1.8/open-uri.rb:242:in `open_http'
from C:/ruby/lib/ruby/1.8/open-uri.rb:616:in `buffer_open'
from C:/ruby/lib/ruby/1.8/open-uri.rb:164:in `open_loop'
from C:/ruby/lib/ruby/1.8/open-uri.rb:162:in `catch'
from C:/ruby/lib/ruby/1.8/open-uri.rb:162:in `open_loop'
from C:/ruby/lib/ruby/1.8/open-uri.rb:132:in `open_uri'
from C:/ruby/lib/ruby/1.8/open-uri.rb:518:in `open'
from C:/ruby/lib/ruby/1.8/open-uri.rb:30:in `open'
from C:/code/test.rb:7
from C:/ruby/lib/ruby/1.8/benchmark.rb:293:in `measure'
from C:/code/test.rb:6
When I try to connect to this URL in my browser, it takes about 2-3 minutes to access, all the time.
I searched google, but found no useful answers to my problem. I know that I have to
change the timeout setting for something, but not able to figure out which one. Can someone please help ?
Use the :read_timeout option, specified in seconds, e.g.,
open('foo.com', :read_timeout => 10)
http://ruby-doc.org/stdlib-1.8.7/libdoc/open-uri/rdoc/OpenURI/OpenRead.html
The BufferedIO class that Net::HTTP uses for the connection that open-uri then uses for the request has a read_timeout attribute set to 60 seconds.
The Net::HTTP class provides a setter read_timeout for that.
Unfortunately, the way open-uri sets up that request doesn't provide you with a way to get at that setting before the request or the easily override the default of 60.
You will probably need to use Net::HTTP yourself.
link = URI.parse(url)
request = Net::HTTP::Get.new(link.path)
response = Net::HTTP.start(link.host, link.port) {|http|
http.read_timeout = 100 #Default is 60 seconds
http.request(request)
}
Code stolen from this answer
edit: or upgrade to 1.9 which supports the :read_timeout = x option Dave Newton noted.

Skipping slow websites when looping through an array of URLs using watir-webdriver

I'm trying to loop through an array of websites in Chrome using watir-webdriver, but I always encounter an error on certain websites. Recently, I have had this problem with http://adage.com. The loop will execute perfectly until it reaches http://adage.com and then it will hang until the following error is displayed:
/Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/protocol.rb:146:in `rescue in rbuf_fill': Timeout::Error (Timeout::Error)
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/protocol.rb:140:in `rbuf_fill'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/protocol.rb:122:in `readuntil'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/protocol.rb:132:in `readline'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/http.rb:2562:in `read_status_line'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/http.rb:2551:in `read_new'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/http.rb:1319:in `block in transport_request'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/http.rb:1316:in `catch'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/http.rb:1316:in `transport_request'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/http.rb:1293:in `request'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/http.rb:1286:in `block in request'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/http.rb:745:in `start'
from /Users/default/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/net/http.rb:1284:in `request'
from /Users/default/.rvm/gems/ruby-1.9.3-p125/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/remote/http/default.rb:82:in `response_for'
from /Users/default/.rvm/gems/ruby-1.9.3-p125/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/remote/http/default.rb:38:in `request'
from /Users/default/.rvm/gems/ruby-1.9.3-p125/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/remote/http/common.rb:40:in `call'
from /Users/default/.rvm/gems/ruby-1.9.3-p125/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/remote/bridge.rb:598:in `raw_execute'
from /Users/default/.rvm/gems/ruby-1.9.3-p125/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/remote/bridge.rb:576:in `execute'
from /Users/default/.rvm/gems/ruby-1.9.3-p125/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/remote/bridge.rb:536:in `getActiveElement'
from /Users/default/.rvm/gems/ruby-1.9.3-p125/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/common/target_locator.rb:60:in `active_element'
from /Users/default/.rvm/gems/ruby-1.9.3-p125/gems/watir-webdriver-0.6.1/lib/watir-webdriver/browser.rb:136:in `send_keys'
from /Users/default/Dropbox/beta_scripts/loop_test.rb:16:in `rescue in <main>'
from /Users/default/Dropbox/beta_scripts/loop_test.rb:11:in `<main>'
I have no idea how to avoid this. I have tried setting timeouts and even sending the ESC key during rescue to stop Chrome from loading the page, but have not had any success. Ultimately, I want to be able to reliably load an array of 500+ websites in succession, but this seems impossible given the likelihood that one of the websites will hang. Is there any way to stop a slow page from loading and move on to the next element in the array?
Below is a shortened version of my code that isolates the problem:
#!/usr/bin/env ruby
require 'watir-webdriver'
b = Watir::Browser.new :chrome
sites = ["twitter.com", "cars.com", "autotrader.com", "rolex.com", "newyorker.com", "adage.com", "theatlantic.com", "pcmag.com"]
sites.each do |uri|
begin
Timeout::timeout(10) do
b.goto uri
end
rescue Timeout::Error => e_time
sleep 5
b.send_keys :escape
p "#{uri} is taking forever to load (#{e_time})"
rescue Exception => e_exception
p e_exception
end
end
b.close
Well I can understand your frustration mate because I have encountered the same when dealing with selenium webdriver. Here it is what you need to do to be 100% sure that your script will run flawless and robust till the end for your 500+ websites.
sites.each do |uri|
!30.times { if ((b.goto uri)rescue false)then break else sleep 1; end }
end
The code above will try to access each website for a maximum of 30sec and then move to the next website.

Watir/Selenium - browser.goto keep getting TimeOut error on Chrome and Firefox

Got a very annoying problem with Watir webdriver..
I have debugged a little, and found out I always get TimeOut::Error on a simple #browser.goto line, even I can visually see the page has loaded fully...
The scenario is like this:
Open a browser, goto a url, click a few links, and then suddenly at one point, the script stops continue browsing, waiting about 30+ seconds and throw errors.
Tried both Chrome and FF: Chrome is much worse, normally a 2nd or 3nd link clicking will trigger; for FF, sometimes takes 10+ page browsing...
Bet there is some environment or comparability issue:
jd#deskbox:~$ uname -am
Linux deskbox 3.0.0-12-generic #20-Ubuntu SMP Fri Oct 7 14:56:25 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
jd#deskbox:~$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
jd#deskbox:~$ rails -v
Rails 3.2.1
jd#deskbox:~$ gem -v
1.8.15
jd#deskbox:~$ gem list|grep webdriver
selenium-webdriver (2.12.0)
watir-webdriver (0.5.3)
Can someone help on this? Source code here:
#!/usr/bin/env ruby
require 'watir-webdriver'
require 'pry'
class Search
attr_accessor :browser, :company_url, :company_name
def initialize()
#browser = Watir::Browser.start 'http://www.google.com', :chrome
end
def visit_company_home_via_google(company)
#company_name = company
#browser.goto "http://www.google.com/search?q=#{company}"
link = #browser.div(:id=>'ires').link
return nil unless link.exists?
#browser.goto link.href
#company_url ||= #browser.url
#company_url
end
def logoff()
#browser.close if #browser
end
end
s = Search.new
puts s.visit_company_home_via_google("github")
puts s.visit_company_home_via_google("Mashable")
puts s.visit_company_home_via_google("Barracuda Networks")
s.logoff
My result is like:
jd#deskbox:~/cuda$ ./search.rb
https://github.com/
/usr/local/lib/ruby/1.9.1/net/protocol.rb:140:in `rescue in rbuf_fill': Timeout::Error (Timeout::Error)
from /usr/local/lib/ruby/1.9.1/net/protocol.rb:134:in `rbuf_fill'
from /usr/local/lib/ruby/1.9.1/net/protocol.rb:116:in `readuntil'
from /usr/local/lib/ruby/1.9.1/net/protocol.rb:126:in `readline'
from /usr/local/lib/ruby/1.9.1/net/http.rb:2219:in `read_status_line'
from /usr/local/lib/ruby/1.9.1/net/http.rb:2208:in `read_new'
from /usr/local/lib/ruby/1.9.1/net/http.rb:1191:in `transport_request'
from /usr/local/lib/ruby/1.9.1/net/http.rb:1177:in `request'
from /usr/local/lib/ruby/1.9.1/net/http.rb:1170:in `block in request'
from /usr/local/lib/ruby/1.9.1/net/http.rb:627:in `start'
from /usr/local/lib/ruby/1.9.1/net/http.rb:1168:in `request'
from /usr/local/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.12.0/lib/selenium/webdriver/remote/http/default.rb:81:in `response_for'
from /usr/local/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.12.0/lib/selenium/webdriver/remote/http/default.rb:43:in `request'
from /usr/local/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.12.0/lib/selenium/webdriver/remote/http/common.rb:39:in `call'
from /usr/local/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.12.0/lib/selenium/webdriver/remote/bridge.rb:450:in `raw_execute'
from /usr/local/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.12.0/lib/selenium/webdriver/remote/bridge.rb:428:in `execute'
from /usr/local/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.12.0/lib/selenium/webdriver/remote/bridge.rb:99:in `get'
from /usr/local/lib/ruby/gems/1.9.1/gems/selenium-webdriver-2.12.0/lib/selenium/webdriver/common/navigation.rb:14:in `to'
from /usr/local/lib/ruby/gems/1.9.1/gems/watir-webdriver-0.5.3/lib/watir-webdriver/browser.rb:61:in `goto'
from ./search.rb:17:in `visit_company_home_via_google'
from ./search.rb:33:in `<main>'
I think there's a bug in Chromedriver that doesn't return the URL correctly. I got your example to work using:
require 'watir-webdriver'
class Search
attr_accessor :browser, :company_name
def initialize
#browser = Watir::Browser.start 'http://www.google.com', :chrome
end
def get_company_url(company, url=nil)
#company_name = company
#company_url = url
#browser.goto "http://www.google.com/search?q=#{company}"
link = #browser.div(:id=>'ires').link
return nil unless link.exists?
#company_url ||= #browser.driver.current_url
end
def logoff()
#browser.close if #browser
end
end
s = Search.new
puts s.get_company_url 'Barracuda Networks'

Resources