Skip to content

Instantly share code, notes, and snippets.

@refractalize
Last active December 29, 2015 02:29
Show Gist options
  • Save refractalize/7601035 to your computer and use it in GitHub Desktop.
Save refractalize/7601035 to your computer and use it in GitHub Desktop.
Timing and Retry for Selenium
require 'selenium-webdriver'
require 'ap'
class Scope
def find type, query
Element.new self, type, query
end
def where(name, &predicate)
Where.new self, name, predicate
end
def retry_until_timeout
start_time = Time.now.utc
while true
begin
yield
break
rescue Exception => e
puts "we got an exception in retry: #{e}"
if (Time.now.utc - start_time) > timeout
throw e
end
end
end
end
def try_each
retry_until_timeout do
each_element do |element|
yield element
end
end
end
def has
retry_until_timeout do
each_element do |element|
yield element
end
end
end
def click
try_each do |element|
puts "trying click #{element.tag_name}"
element.click
end
end
def text
try_each do |element|
puts "trying text #{element.tag_name}"
element.text
end
end
def send_keys text
try_each do |element|
puts "trying send_keys in #{element.tag_name}"
element.send_keys text
end
end
def type text
try_each do |element|
puts "trying type in #{element.tag_name}"
element.type text
end
end
def timeout
@parent.timeout
end
end
class Element < Scope
def initialize parent, type, query
@parent = parent
@type = type
@query = query
end
def each_element
ex = nil
@parent.each_element do |parent|
puts "finding elements by #{@type}, #{@query}"
parent.find_elements(@type, @query).each do |element|
begin
if element.displayed?
puts "trying element #{element.tag_name}", element
yield element
return
end
rescue Exception => e
ex = e
ap ex
ap ex.backtrace.join "\n"
end
end
end
if ex
ap ex
ap ex.backtrace.join "\n"
raise ex
else
raise Exception.new "no element found for scope #{self}"
end
end
def to_s
"#{@parent}/#{@type}:#{@query}"
end
end
class Where < Scope
def initialize parent, name, predicate
@parent = parent
@name = name
@predicate = predicate
end
def each_element
@parent.each_element do |element|
puts "where trying element #{element.tag_name}", element
if @predicate.call(element)
puts "where using element #{element.tag_name}"
yield element
return
else
puts "where not using element #{element.tag_name}"
end
end
raise Exception.new "no #{@name} could be found"
end
end
class Device < Scope
attr_accessor :timeout
def initialize(capabilities)
@timeout = (capabilities[:timeout] or 5)
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => (capabilities[:server_url] or 'http://127.0.0.1:4723/wd/hub'))
@driver.manage.timeouts.implicit_wait = 0.1
end
def to_s
""
end
def each_element
ex = nil
begin
puts 'trying native view'
@driver.execute_script 'mobile: leaveWebView'
yield @driver
return
rescue Exception => e
ex = e
@driver.window_handles.each do |window|
begin
puts "trying web view #{window}"
@driver.switch_to.window window
yield @driver
return
rescue Exception => e
ex = e
end
end
end
ap ex
ap ex.backtrace.join "\n"
raise ex
end
def quit
@driver.quit
end
end
require_relative 'device.rb'
require 'pry'
describe "driver" do
before :each do
capabilities = {
'device' => 'iPad Retina',
'app' => '/path/to/myapp.app'
}
@driver = Device.new(capabilities)
end
after :each do
@driver.quit
end
it "can log in" do
username = @driver.find :id, 'UserName'
username.send_keys 'joebob'
password = @driver.find(:id, 'Password')
password.send_keys 'password1'
login = @driver.find :name, 'submitButton'
login.click
dashboard_button = @driver.find :name, 'dashboard'
sleep 3
dashboard_button.click
sleep 1
exec = @driver.find(:xpath, '//*[@text="Menu Option"]')
exec.click
@driver.find(:tag_name, 'text').has do |element|
ap element.text
element.text.should == 'November'
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment