eyes_selenium 2.15.0 → 2.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/.travis.yml +16 -0
- data/Gemfile +1 -1
- data/README.md +14 -4
- data/Rakefile +8 -1
- data/eyes_selenium.gemspec +26 -17
- data/lib/applitools/base/batch_info.rb +19 -0
- data/lib/applitools/base/dimension.rb +21 -0
- data/lib/applitools/base/environment.rb +19 -0
- data/lib/applitools/base/mouse_trigger.rb +33 -0
- data/lib/applitools/base/point.rb +21 -0
- data/lib/applitools/base/region.rb +77 -0
- data/lib/applitools/base/server_connector.rb +113 -0
- data/lib/applitools/base/session.rb +15 -0
- data/lib/applitools/base/start_info.rb +34 -0
- data/lib/applitools/base/test_results.rb +36 -0
- data/lib/applitools/base/text_trigger.rb +22 -0
- data/lib/applitools/eyes.rb +393 -0
- data/lib/applitools/eyes_logger.rb +40 -0
- data/lib/applitools/method_tracer.rb +22 -0
- data/lib/applitools/selenium/driver.rb +194 -0
- data/lib/applitools/selenium/element.rb +66 -0
- data/lib/applitools/selenium/keyboard.rb +27 -0
- data/lib/applitools/selenium/match_window_data.rb +24 -0
- data/lib/applitools/selenium/match_window_task.rb +190 -0
- data/lib/applitools/selenium/mouse.rb +62 -0
- data/lib/applitools/selenium/viewport_size.rb +128 -0
- data/lib/applitools/utils/image_delta_compressor.rb +150 -0
- data/lib/applitools/utils/image_utils.rb +63 -0
- data/lib/applitools/utils/utils.rb +52 -0
- data/lib/applitools/version.rb +3 -0
- data/lib/eyes_selenium.rb +9 -29
- data/spec/driver_passthrough_spec.rb +25 -25
- data/spec/spec_helper.rb +5 -8
- data/test/appium_example_script.rb +57 -0
- data/{test_script.rb → test/test_script.rb} +7 -9
- data/{watir_test.rb → test/watir_test_script.rb} +6 -4
- metadata +120 -48
- data/appium_eyes_example.rb +0 -56
- data/lib/eyes_selenium/capybara.rb +0 -21
- data/lib/eyes_selenium/eyes/agent_connector.rb +0 -76
- data/lib/eyes_selenium/eyes/batch_info.rb +0 -19
- data/lib/eyes_selenium/eyes/dimension.rb +0 -15
- data/lib/eyes_selenium/eyes/driver.rb +0 -266
- data/lib/eyes_selenium/eyes/element.rb +0 -78
- data/lib/eyes_selenium/eyes/environment.rb +0 -15
- data/lib/eyes_selenium/eyes/eyes.rb +0 -396
- data/lib/eyes_selenium/eyes/eyes_keyboard.rb +0 -25
- data/lib/eyes_selenium/eyes/eyes_mouse.rb +0 -60
- data/lib/eyes_selenium/eyes/failure_reports.rb +0 -4
- data/lib/eyes_selenium/eyes/match_level.rb +0 -8
- data/lib/eyes_selenium/eyes/match_window_data.rb +0 -18
- data/lib/eyes_selenium/eyes/match_window_task.rb +0 -182
- data/lib/eyes_selenium/eyes/mouse_trigger.rb +0 -23
- data/lib/eyes_selenium/eyes/region.rb +0 -72
- data/lib/eyes_selenium/eyes/screenshot_taker.rb +0 -18
- data/lib/eyes_selenium/eyes/session.rb +0 -14
- data/lib/eyes_selenium/eyes/start_info.rb +0 -32
- data/lib/eyes_selenium/eyes/test_results.rb +0 -32
- data/lib/eyes_selenium/eyes/text_trigger.rb +0 -19
- data/lib/eyes_selenium/eyes/viewport_size.rb +0 -105
- data/lib/eyes_selenium/eyes_logger.rb +0 -47
- data/lib/eyes_selenium/utils.rb +0 -6
- data/lib/eyes_selenium/utils/image_delta_compressor.rb +0 -149
- data/lib/eyes_selenium/utils/image_utils.rb +0 -76
- data/lib/eyes_selenium/version.rb +0 -3
data/appium_eyes_example.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'eyes_selenium'
|
2
|
-
require 'appium_lib'
|
3
|
-
|
4
|
-
##
|
5
|
-
# Based on Appium example: https://github.com/appium/appium/blob/master/sample-code/examples/ruby/
|
6
|
-
|
7
|
-
|
8
|
-
def android_caps
|
9
|
-
{
|
10
|
-
deviceName: 'Samsung Galaxy S4 Emulator',
|
11
|
-
platformName: 'Android',
|
12
|
-
platformVersion: 4.4,
|
13
|
-
app: ENV['ANDROID_NOTES_LIST_APP'],
|
14
|
-
appPackage: 'com.example.android.notepad',
|
15
|
-
appActivity: '.NotesList',
|
16
|
-
# orientation: 'landscape',
|
17
|
-
newCommandTimeout: 300
|
18
|
-
}
|
19
|
-
end
|
20
|
-
def ios_caps
|
21
|
-
{
|
22
|
-
deviceName: 'iPhone 6',
|
23
|
-
platformName: 'ios',
|
24
|
-
platformVersion: 8.3,
|
25
|
-
app: ENV['IOS_DEMO_APP'],
|
26
|
-
orientation: 'landscape',
|
27
|
-
newCommandTimeout: 300
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
def appium_opts
|
32
|
-
{
|
33
|
-
server_url: 'http://127.0.0.1:4723/wd/hub',
|
34
|
-
}
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
@eyes = Applitools::Eyes.new
|
39
|
-
@eyes.log_handler = Logger.new(STDOUT)
|
40
|
-
@eyes.api_key = ENV['APPLITOOLS_API_KEY']
|
41
|
-
begin
|
42
|
-
# @driver = Appium::Driver.new({caps: android_caps, appium_lib: appium_opts})
|
43
|
-
@driver = Appium::Driver.new({caps: ios_caps, appium_lib: appium_opts})
|
44
|
-
@driver.start_driver
|
45
|
-
# @driver.driver.rotate :landscape
|
46
|
-
puts "Screen size: #{@driver.driver.manage.window.size}"
|
47
|
-
puts "orientation: #{@driver.driver.orientation}"
|
48
|
-
puts @driver.caps
|
49
|
-
@eyes.open(app_name: 'Selenium Israel', test_name: 'Appium Notepad', driver: @driver)
|
50
|
-
@eyes.check_window("No notes")
|
51
|
-
|
52
|
-
@eyes.close
|
53
|
-
ensure
|
54
|
-
@eyes.abort_if_not_closed
|
55
|
-
@driver.driver_quit
|
56
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'eyes_selenium'
|
2
|
-
|
3
|
-
# Override create driver to inject into capybara's driver
|
4
|
-
class Applitools::Eyes
|
5
|
-
def test(params={}, &block)
|
6
|
-
begin
|
7
|
-
previous_driver = Capybara.current_driver
|
8
|
-
previous_browser = Capybara.current_session.driver.instance_variable_get(:@browser)
|
9
|
-
Capybara.current_driver = :selenium
|
10
|
-
Capybara.current_session.driver.instance_variable_set(:@browser, driver)
|
11
|
-
open(params)
|
12
|
-
yield(self, driver)
|
13
|
-
close
|
14
|
-
rescue Applitools::EyesError
|
15
|
-
ensure
|
16
|
-
abort_if_not_closed
|
17
|
-
Capybara.current_session.driver.instance_variable_set(:@browser, previous_browser)
|
18
|
-
Capybara.current_driver = previous_driver
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
require 'httparty'
|
2
|
-
class Applitools::AgentConnector
|
3
|
-
include HTTParty
|
4
|
-
headers 'Accept' => 'application/json'
|
5
|
-
ssl_ca_file File.join(File.dirname(File.expand_path(__FILE__)), '../../../certs/cacert.pem').to_s
|
6
|
-
default_timeout 300
|
7
|
-
|
8
|
-
# comment out when not debugging
|
9
|
-
#http_proxy 'localhost', 8888
|
10
|
-
#debug_output $stdout
|
11
|
-
|
12
|
-
attr_accessor :server_url, :api_key
|
13
|
-
|
14
|
-
def server_url=(server_url)
|
15
|
-
@server_url = server_url
|
16
|
-
# Remove trailing slashes in server url and add the running sessions endpoint uri.
|
17
|
-
@endpoint_uri = server_url.gsub(/\/$/,'') + '/api/sessions/running'
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize(server_url)
|
21
|
-
self.server_url = server_url
|
22
|
-
end
|
23
|
-
|
24
|
-
def match_window(session, data)
|
25
|
-
self.class.headers 'Content-Type' => 'application/octet-stream'
|
26
|
-
json_data = data.to_hash.to_json.force_encoding('BINARY') # Notice that this does not include the screenshot
|
27
|
-
body = [json_data.length].pack('L>') + json_data + data.screenshot
|
28
|
-
EyesLogger.debug 'Sending match data...'
|
29
|
-
res = self.class.post(@endpoint_uri + "/#{session.id}", query: {apiKey: api_key}, body: body)
|
30
|
-
raise Applitools::EyesError.new('could not connect to server') if res.code != 200
|
31
|
-
EyesLogger.debug "Got response! #{res.parsed_response['asExpected']}"
|
32
|
-
res.parsed_response['asExpected']
|
33
|
-
end
|
34
|
-
|
35
|
-
def start_session(session_start_info)
|
36
|
-
self.class.headers 'Content-Type' => 'application/json'
|
37
|
-
res = self.class.post(@endpoint_uri, query: {apiKey: api_key}, body: { startInfo: session_start_info.to_hash }.to_json)
|
38
|
-
status_code = res.response.message
|
39
|
-
parsed_res = res.parsed_response
|
40
|
-
Applitools::Session.new(parsed_res['id'], parsed_res['url'], status_code == 'Created' )
|
41
|
-
end
|
42
|
-
|
43
|
-
def stop_session(session, aborted=nil, save=false)
|
44
|
-
self.class.headers 'Content-Type' => 'application/json'
|
45
|
-
res = self.class.send_long_request('stop_session') do
|
46
|
-
self.class.delete(@endpoint_uri + "/#{session.id}", query: { aborted: aborted.to_s, updateBaseline: save.to_s, apiKey: api_key })
|
47
|
-
end
|
48
|
-
parsed_res = res.parsed_response
|
49
|
-
parsed_res.delete('$id')
|
50
|
-
Applitools::TestResults.new(*parsed_res.values)
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
##
|
55
|
-
# Static method for sending long running requests
|
56
|
-
# Args:
|
57
|
-
# name: (String) name of the method being executed
|
58
|
-
# request_block: (block) The actual block to be executed. Will be called using "yield"
|
59
|
-
# noinspection RubyUnusedLocalVariable
|
60
|
-
def self.send_long_request(name, &request_block)
|
61
|
-
delay = 2 # seconds
|
62
|
-
|
63
|
-
headers 'Eyes-Expect' => '202-accepted'
|
64
|
-
while true
|
65
|
-
# Date should be in RFC 1123 format
|
66
|
-
headers 'Eyes-Date' => Time.now.utc.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
67
|
-
res = yield
|
68
|
-
if res.code != 202
|
69
|
-
return res
|
70
|
-
end
|
71
|
-
EyesLogger.debug "#{name}: Still running... Retrying in #{delay}s"
|
72
|
-
sleep delay
|
73
|
-
delay = [10, (delay*1.5).round].min
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'securerandom'
|
2
|
-
|
3
|
-
class Applitools::BatchInfo
|
4
|
-
attr_accessor :id
|
5
|
-
attr_reader :name, :started_at
|
6
|
-
def initialize(name=nil, started_at = Time.now)
|
7
|
-
@name = name
|
8
|
-
@started_at = started_at
|
9
|
-
@id = SecureRandom.uuid
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_hash
|
13
|
-
{
|
14
|
-
name: name,
|
15
|
-
id: id,
|
16
|
-
startedAt: started_at.iso8601
|
17
|
-
}
|
18
|
-
end
|
19
|
-
end
|
@@ -1,266 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
require 'selenium-webdriver'
|
3
|
-
|
4
|
-
class Applitools::Driver
|
5
|
-
|
6
|
-
# Rotates the image as necessary. The rotation is either manually forced by passing a value in
|
7
|
-
# the +rotation+ parameter, or automatically inferred if the +rotation+ parameter is +nil+.
|
8
|
-
#
|
9
|
-
# +driver+:: +Applitools::Driver+ The driver which produced the screenshot.
|
10
|
-
# +image+:: +ChunkyPNG::Canvas+ The image to normalize.
|
11
|
-
# +rotation+:: +Integer+|+nil+ The degrees by which to rotate the image: positive values = clockwise rotation,
|
12
|
-
# negative values = counter-clockwise, 0 = force no rotation, +nil+ = rotate
|
13
|
-
# automatically when needed.
|
14
|
-
#
|
15
|
-
def self.normalize_rotation!(driver, image, rotation)
|
16
|
-
EyesLogger.debug "#{__method__}()"
|
17
|
-
if rotation != 0
|
18
|
-
num_quadrants = 0
|
19
|
-
if !rotation.nil?
|
20
|
-
if rotation % 90 != 0
|
21
|
-
raise Applitools::EyesError.new(
|
22
|
-
"Currently only quadrant rotations are supported. Current rotation: #{rotation}")
|
23
|
-
end
|
24
|
-
num_quadrants = (rotation / 90).to_i
|
25
|
-
elsif rotation.nil? && driver.mobile_device? && driver.landscape_orientation? && image.height > image.width
|
26
|
-
# For Android, we need to rotate images to the right, and for iOS to the left.
|
27
|
-
num_quadrants = driver.android? ? 1 : -1
|
28
|
-
end
|
29
|
-
Applitools::Utils::ImageUtils.quadrant_rotate!(image, num_quadrants)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
include Selenium::WebDriver::DriverExtensions::HasInputDevices
|
35
|
-
|
36
|
-
attr_reader :remote_server_url, :remote_session_id, :screenshot_taker, :eyes
|
37
|
-
attr_accessor :driver
|
38
|
-
|
39
|
-
DRIVER_METHODS = [
|
40
|
-
:title, :execute_script, :execute_async_script, :quit, :close, :get,
|
41
|
-
:post, :page_source, :window_handles, :window_handle, :switch_to,
|
42
|
-
:navigate, :manage, :capabilities, :current_url
|
43
|
-
]
|
44
|
-
|
45
|
-
## If driver is not provided, Applitools::Driver will raise an EyesError exception.
|
46
|
-
#
|
47
|
-
def initialize(eyes, options)
|
48
|
-
@driver = options[:driver]
|
49
|
-
@is_mobile_device = options.fetch(:is_mobile_device, false)
|
50
|
-
@eyes = eyes
|
51
|
-
# FIXME fix getting "remote address url" or remove "Screenshot taker" altogether.
|
52
|
-
# @remote_server_url = address_of_remote_server
|
53
|
-
@remote_server_url = 'MOCK_URL'
|
54
|
-
@remote_session_id = remote_session_id
|
55
|
-
begin
|
56
|
-
#noinspection RubyResolve
|
57
|
-
if driver.capabilities.takes_screenshot?
|
58
|
-
@screenshot_taker = false
|
59
|
-
else
|
60
|
-
@screenshot_taker = Applitools::ScreenshotTaker.new(@remote_server_url, @remote_session_id)
|
61
|
-
end
|
62
|
-
rescue => e
|
63
|
-
raise Applitools::EyesError.new "Can't take screenshots (#{e.message})"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
DRIVER_METHODS.each do |method|
|
68
|
-
define_method method do |*args, &block|
|
69
|
-
driver.send(method,*args, &block)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# Returns:
|
74
|
-
# +String+ The platform name or +nil+ if it is undefined.
|
75
|
-
def platform_name
|
76
|
-
driver.capabilities['platformName']
|
77
|
-
end
|
78
|
-
|
79
|
-
# Returns:
|
80
|
-
# +String+ The platform version or +nil+ if it is undefined.
|
81
|
-
def platform_version
|
82
|
-
version = driver.capabilities['platformVersion']
|
83
|
-
version.nil? ? nil : version.to_s
|
84
|
-
end
|
85
|
-
|
86
|
-
# Returns:
|
87
|
-
# +true+ if the driver is an Android driver.
|
88
|
-
def android?
|
89
|
-
platform_name.to_s.upcase == 'ANDROID'
|
90
|
-
end
|
91
|
-
|
92
|
-
# Returns:
|
93
|
-
# +true+ if the driver is an iOS driver.
|
94
|
-
def ios?
|
95
|
-
platform_name.to_s.upcase == 'IOS'
|
96
|
-
end
|
97
|
-
|
98
|
-
# Returns:
|
99
|
-
# +true+ if the driver orientation is landscape.
|
100
|
-
def landscape_orientation?
|
101
|
-
begin
|
102
|
-
driver.orientation.to_s.upcase == 'LANDSCAPE'
|
103
|
-
rescue NameError
|
104
|
-
EyesLogger.debug 'driver has no "orientation" attribute. Assuming Portrait.'
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Returns:
|
109
|
-
# +true+ if the platform running the test is a mobile platform. +false+ otherwise.
|
110
|
-
def mobile_device?
|
111
|
-
# We CAN'T check if the device is an +Appium::Driver+ since it is not a RemoteWebDriver. Because of that we use a
|
112
|
-
# flag we got as an option in the constructor.
|
113
|
-
@is_mobile_device
|
114
|
-
end
|
115
|
-
|
116
|
-
# Return a PNG screenshot in the given format as a string
|
117
|
-
#
|
118
|
-
# +output_type+:: +Symbol+ The format of the screenshot. Accepted values are +:base64+ and +:png+.
|
119
|
-
# +rotation+:: +Integer+|+nil+ The degrees by which to rotate the image: positive values = clockwise rotation,
|
120
|
-
# negative values = counter-clockwise, 0 = force no rotation, +nil+ = rotate
|
121
|
-
# automatically when needed.
|
122
|
-
#
|
123
|
-
# Returns: +String+ A screenshot in the requested format.
|
124
|
-
def screenshot_as(output_type, rotation=nil)
|
125
|
-
# FIXME Check if screenshot_taker is still required
|
126
|
-
screenshot = screenshot_taker ? screenshot_taker.screenshot : driver.screenshot_as(:base64)
|
127
|
-
screenshot = Applitools::Utils::ImageUtils.png_image_from_base64(screenshot)
|
128
|
-
Applitools::Driver.normalize_rotation!(self, screenshot, rotation)
|
129
|
-
case output_type
|
130
|
-
when :base64
|
131
|
-
screenshot = Applitools::Utils::ImageUtils.base64_from_png_image(screenshot)
|
132
|
-
when :png
|
133
|
-
screenshot = Applitools::Utils::ImageUtils.bytes_from_png_image(screenshot)
|
134
|
-
else
|
135
|
-
raise Applitools::EyesError.new("Unsupported screenshot output type #{output_type.to_s}")
|
136
|
-
end
|
137
|
-
screenshot.force_encoding('BINARY')
|
138
|
-
end
|
139
|
-
|
140
|
-
def mouse
|
141
|
-
Applitools::EyesMouse.new(self, driver.mouse)
|
142
|
-
end
|
143
|
-
|
144
|
-
def keyboard
|
145
|
-
Applitools::EyesKeyboard.new(self, driver.keyboard)
|
146
|
-
end
|
147
|
-
|
148
|
-
FINDERS = {
|
149
|
-
:class => 'class name',
|
150
|
-
:class_name => 'class name',
|
151
|
-
:css => 'css selector',
|
152
|
-
:id => 'id',
|
153
|
-
:link => 'link text',
|
154
|
-
:link_text => 'link text',
|
155
|
-
:name => 'name',
|
156
|
-
:partial_link_text => 'partial link text',
|
157
|
-
:tag_name => 'tag name',
|
158
|
-
:xpath => 'xpath',
|
159
|
-
}
|
160
|
-
|
161
|
-
def find_element(*args)
|
162
|
-
how, what = extract_args(args)
|
163
|
-
|
164
|
-
# Make sure that "how" is a valid locator.
|
165
|
-
unless FINDERS[how.to_sym]
|
166
|
-
raise ArgumentError, "cannot find element by #{how.inspect}"
|
167
|
-
end
|
168
|
-
|
169
|
-
Applitools::Element.new(self, driver.find_element(how, what))
|
170
|
-
end
|
171
|
-
|
172
|
-
def find_elements(*args)
|
173
|
-
how, what = extract_args(args)
|
174
|
-
|
175
|
-
unless FINDERS[how.to_sym]
|
176
|
-
raise ArgumentError, "cannot find element by #{how.inspect}"
|
177
|
-
end
|
178
|
-
|
179
|
-
driver.find_elements(how, what).map { |el| Applitools::Element.new(self, el) }
|
180
|
-
end
|
181
|
-
|
182
|
-
def ie?
|
183
|
-
driver.to_s == 'ie'
|
184
|
-
end
|
185
|
-
|
186
|
-
def firefox?
|
187
|
-
driver.to_s == 'firefox'
|
188
|
-
end
|
189
|
-
|
190
|
-
def user_agent
|
191
|
-
execute_script 'return navigator.userAgent'
|
192
|
-
rescue => e
|
193
|
-
EyesLogger.info "getUserAgent(): Failed to obtain user-agent string (#{e.message})"
|
194
|
-
return nil
|
195
|
-
end
|
196
|
-
|
197
|
-
private
|
198
|
-
|
199
|
-
# FIXME Fix extraction of remote server, or remove completely if removed ScreenshotTaker
|
200
|
-
# def address_of_remote_server
|
201
|
-
# # The driver's url is not available using a standard interface, so we use reflection to get it.
|
202
|
-
# #noinspection RubyResolve
|
203
|
-
# uri = URI(driver.instance_eval{@bridge}.instance_eval{@http}.instance_eval{@server_url})
|
204
|
-
# raise Applitools::EyesError.new('Failed to get remote web driver url') if uri.to_s.empty?
|
205
|
-
#
|
206
|
-
# webdriver_host = uri.host
|
207
|
-
# if %w[127.0.0.1 localhost].include?(webdriver_host) && !firefox? && !ie?
|
208
|
-
# uri.host = get_local_ip || 'localhost'
|
209
|
-
# end
|
210
|
-
#
|
211
|
-
# uri
|
212
|
-
# end
|
213
|
-
|
214
|
-
def remote_session_id
|
215
|
-
driver.remote_session_id
|
216
|
-
end
|
217
|
-
|
218
|
-
def get_local_ip
|
219
|
-
begin
|
220
|
-
Socket.ip_address_list.detect do |intf|
|
221
|
-
intf.ipv4? and !intf.ipv4_loopback? and !intf.ipv4_multicast?
|
222
|
-
end.ip_address
|
223
|
-
rescue SocketError => e
|
224
|
-
raise Applitools::EyesError.new("Failed to get local IP! (#{e})")
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def extract_args(args)
|
229
|
-
case args.size
|
230
|
-
when 2
|
231
|
-
args
|
232
|
-
when 1
|
233
|
-
arg = args.first
|
234
|
-
|
235
|
-
unless arg.respond_to?(:shift)
|
236
|
-
raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift"
|
237
|
-
end
|
238
|
-
|
239
|
-
# this will be a single-entry hash, so use #shift over #first or #[]
|
240
|
-
arr = arg.dup.shift
|
241
|
-
unless arr.size == 2
|
242
|
-
raise ArgumentError, "expected #{arr.inspect} to have 2 elements"
|
243
|
-
end
|
244
|
-
|
245
|
-
arr
|
246
|
-
else
|
247
|
-
raise ArgumentError, "wrong number of arguments (#{args.size} for 2)"
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
end
|
252
|
-
|
253
|
-
## .bridge, .session_id and .server_url are private methods in Selenium::WebDriver gem
|
254
|
-
module Selenium::WebDriver
|
255
|
-
class Driver
|
256
|
-
def remote_session_id
|
257
|
-
bridge.session_id
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
class Remote::Http::Common
|
262
|
-
def get_server_url
|
263
|
-
server_url
|
264
|
-
end
|
265
|
-
end
|
266
|
-
end
|