eyes_selenium 3.18.2 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'selenium-webdriver'
4
+
5
+
6
+ module Applitools
7
+ module Selenium
8
+ class DomSnapshotScript
9
+
10
+ attr_accessor :driver
11
+
12
+ def initialize(driver)
13
+ self.driver = driver
14
+ end
15
+
16
+ def create_dom_snapshot(
17
+ dont_fetch_resources,
18
+ urls_to_skip,
19
+ cross_origin_rendering,
20
+ use_cookies
21
+ )
22
+ serialize_resources = true
23
+ compress_resources = false
24
+ script = DomSnapshotScript.new(driver, urls_to_skip, dont_fetch_resources, serialize_resources, compress_resources)
25
+ snapshotter = RecursiveSnapshotter.new(driver, script, cross_origin_rendering, use_cookies)
26
+
27
+ begin
28
+ snapshotter.create_cross_frames_dom_snapshots
29
+ rescue StandardError => e
30
+ Applitools::EyesLogger.error e.class.to_s
31
+ Applitools::EyesLogger.error e.message
32
+ raise ::Applitools::EyesError.new 'Error while getting dom snapshot!'
33
+ end
34
+
35
+ end
36
+
37
+ class DomSnapshotScript
38
+ DOM_EXTRACTION_TIMEOUT = 300
39
+
40
+ attr_accessor :driver, :urls_to_skip, :dont_fetch_resources, :serialize_resources, :compress_resources
41
+
42
+ def initialize(driver, urls_to_skip, dont_fetch_resources, serialize_resources = false, compress_resources = false)
43
+ self.driver = driver
44
+ self.urls_to_skip = urls_to_skip
45
+ self.dont_fetch_resources = dont_fetch_resources
46
+ self.compress_resources = compress_resources
47
+ self.serialize_resources = serialize_resources
48
+ end
49
+
50
+ def process_page_script
51
+ Applitools::Selenium::Scripts::PROCESS_PAGE_AND_POLL
52
+ end
53
+
54
+ def script_options
55
+ options = []
56
+ options.push("dontFetchResources: #{dont_fetch_resources}")
57
+ options.push("skipResources: [#{urls_to_skip}]")
58
+ options.push("compressResources: #{compress_resources}")
59
+ options.push("serializeResources: #{serialize_resources}")
60
+ "{#{options.join(', ')}}"
61
+ end
62
+
63
+ def script
64
+ "#{process_page_script} return __processPageAndSerializePoll(#{script_options});"
65
+ end
66
+
67
+ def run
68
+ Applitools::EyesLogger.info 'Trying to get DOM snapshot...'
69
+
70
+ script_thread = Thread.new do
71
+ result = {}
72
+ while result['status'] != 'SUCCESS'
73
+ Thread.current[:script_result] = driver.execute_script(script)
74
+ begin
75
+ Thread.current[:result] = result = Oj.load(Thread.current[:script_result])
76
+ sleep 0.5
77
+ rescue Oj::ParseError => e
78
+ Applitools::EyesLogger.warn e.message
79
+ end
80
+ end
81
+ end
82
+ sleep 0.5
83
+ script_thread_result = script_thread.join(DOM_EXTRACTION_TIMEOUT)
84
+ raise ::Applitools::EyesError.new 'Timeout error while getting dom snapshot!' unless script_thread_result
85
+ Applitools::EyesLogger.info 'Done!'
86
+
87
+ script_thread_result[:result]['value']
88
+ end
89
+
90
+ end
91
+
92
+
93
+ class RecursiveSnapshotter
94
+
95
+ POLL_INTERVAL_MS = 0.5
96
+
97
+ attr_accessor :should_skip_failed_frames
98
+
99
+ attr_accessor :driver, :script, :cross_origin_rendering, :use_cookies
100
+
101
+ def initialize(driver, script, cross_origin_rendering, use_cookies)
102
+ self.should_skip_failed_frames = true
103
+ self.driver = driver
104
+ self.script = script
105
+ self.cross_origin_rendering = cross_origin_rendering
106
+ self.use_cookies = use_cookies
107
+ end
108
+
109
+ def create_cross_frames_dom_snapshots
110
+ dom = create_dom_snapshot_threaded
111
+ process_dom_snapshot_frames dom
112
+ dom
113
+ end
114
+
115
+ def create_dom_snapshot_threaded
116
+ script.run
117
+ end
118
+
119
+ def process_dom_snapshot_frames dom
120
+ dom["cookies"] = driver.manage.all_cookies if use_cookies
121
+
122
+ dom["frames"].each do |frame|
123
+ selector = frame['selector']
124
+ unless selector
125
+ Applitools::EyesLogger.warn "inner frame with null selector"
126
+ next
127
+ end
128
+ begin
129
+ original_frame_chain = driver.frame_chain
130
+ frame_element = driver.find_element(:css, selector)
131
+ frame_src = frame_element.attribute('src')
132
+ Applitools::EyesLogger.info "process_dom_snapshot_frames src = #{frame_src}"
133
+ driver.switch_to.frame(frame_element)
134
+
135
+ process_dom_snapshot_frames frame
136
+
137
+ driver.switch_to.default_content
138
+ unless original_frame_chain.empty?
139
+ driver.switch_to.frames frame_chain: original_frame_chain
140
+ end
141
+ rescue StandardError => e
142
+ Applitools::EyesLogger.error e.class.to_s
143
+ Applitools::EyesLogger.error e.message
144
+ if should_skip_failed_frames
145
+ Applitools::EyesLogger.warn "failed switching to frame #{selector}"
146
+ else
147
+ raise ::Applitools::EyesError.new 'failed switching to frame'
148
+ end
149
+ end
150
+ end
151
+
152
+ self.snapshot_and_process_cors_frames(dom) if self.cross_origin_rendering
153
+ end
154
+
155
+ def snapshot_and_process_cors_frames(dom)
156
+ dom["crossFrames"].each do |frame|
157
+ selector = frame['selector']
158
+ unless selector
159
+ Applitools::EyesLogger.warn "cross frame with null selector"
160
+ next
161
+ end
162
+ frame_index = frame['index']
163
+ begin
164
+ original_frame_chain = driver.frame_chain
165
+ frame_element = driver.find_element(:css, selector) #
166
+ frame_src = frame_element.attribute('src')
167
+ Applitools::EyesLogger.info "snapshot_and_process_cors_frames src = #{frame_src}"
168
+ driver.switch_to.frame(frame_element)
169
+
170
+ frame_dom = create_cross_frames_dom_snapshots
171
+ dom['frames'] ||= []
172
+ dom['frames'].push frame_dom
173
+ frame_url = frame_dom['url']
174
+ dom['cdt'][frame_index]['attributes'].push({ 'name' => 'data-applitools-src', 'value' => frame_url })
175
+ Applitools::EyesLogger.info "Created cross origin frame snapshot #{frame_url}"
176
+ process_dom_snapshot_frames frame_dom
177
+
178
+ driver.switch_to.default_content
179
+ unless original_frame_chain.empty?
180
+ driver.switch_to.frames(frame_chain: original_frame_chain)
181
+ end
182
+ rescue StandardError => e
183
+ Applitools::EyesLogger.error e.class.to_s
184
+ Applitools::EyesLogger.error e.message
185
+ if should_skip_failed_frames
186
+ Applitools::EyesLogger.warn "failed extracting and processing cross frame #{selector}"
187
+ else
188
+ raise ::Applitools::EyesError.new 'failed switching to frame'
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ end
195
+ end
196
+ end
197
+ end
@@ -36,6 +36,10 @@ module Applitools
36
36
  ios_device_info.device_name
37
37
  end
38
38
 
39
+ def to_hash
40
+ {iosDeviceInfo: ios_device_info.to_hash}
41
+ end
42
+
39
43
  private
40
44
 
41
45
  class EmulationInfo < EmulationBaseInfo
@@ -49,6 +53,14 @@ module Applitools
49
53
  version: 'latest'
50
54
  }
51
55
  end
56
+
57
+ def to_hash
58
+ {
59
+ deviceName: device_name,
60
+ screenOrientation: screen_orientation,
61
+ iosVersion: 'latest'
62
+ }
63
+ end
52
64
  end
53
65
  end
54
66
  end
@@ -1,5 +1,8 @@
1
1
  module IosDeviceName
2
2
  extend self
3
+ IPhone_13_Pro_Max = 'iPhone 13 Pro Max'
4
+ IPhone_13_Pro = 'iPhone 13 Pro'
5
+ IPhone_13 = 'iPhone 13'
3
6
  IPhone_12_Pro_Max = 'iPhone 12 Pro Max'
4
7
  IPhone_12_Pro = 'iPhone 12 Pro'
5
8
  IPhone_12 = 'iPhone 12'
@@ -14,10 +17,14 @@ module IosDeviceName
14
17
  IPhone_7 = 'iPhone 7'
15
18
  IPad_Pro_3 = 'iPad Pro (12.9-inch) (3rd generation)'
16
19
  IPad_7 = 'iPad (7th generation)'
20
+ IPad_9 = 'iPad (9th generation)'
17
21
  IPad_Air_2 = 'iPad Air (2nd generation)'
18
22
 
19
23
  def enum_values
20
24
  [
25
+ IPhone_13_Pro_Max,
26
+ IPhone_13_Pro,
27
+ IPhone_13,
21
28
  IPhone_12_Pro_Max,
22
29
  IPhone_12_Pro,
23
30
  IPhone_12,
@@ -32,6 +39,7 @@ module IosDeviceName
32
39
  IPhone_7,
33
40
  IPad_Pro_3,
34
41
  IPad_7,
42
+ IPad_9,
35
43
  IPad_Air_2
36
44
  ]
37
45
  end
@@ -188,12 +188,13 @@ module Applitools
188
188
  end
189
189
 
190
190
  fetch_block = proc do |_s, key|
191
- resp_proc = proc { |u| server_connector.download_resource(u, ua_string) }
191
+ resp_proc = proc { |u, cookies| server_connector.download_resource(u, ua_string, cookies) }
192
192
  retry_count = 3
193
+ matching_cookies = data['cookies'].to_a.select {|c| is_cookie_for_url(c, key)}
193
194
  response = nil
194
195
  loop do
195
196
  retry_count -= 1
196
- response = resp_proc.call(key.dup)
197
+ response = resp_proc.call(key.dup, matching_cookies)
197
198
  break unless response.status != 200 && retry_count > 0
198
199
  end
199
200
  Applitools::Selenium::VGResource.parse_response(
@@ -287,6 +288,24 @@ module Applitools
287
288
  running_tests << running_test
288
289
  running_tests.length - 1
289
290
  end
291
+
292
+ def is_cookie_for_url(cookie, url)
293
+ return false if cookie[:secure] && url.scheme != 'https'
294
+ return false if cookie[:expires] && DateTime.now > cookie[:expires]
295
+
296
+ subdomains_allowed = cookie[:domain].start_with? '.'
297
+ domain = subdomains_allowed ? cookie[:domain][1..-1] : cookie[:domain]
298
+ domain_match = url.hostname === domain
299
+ subdomain_match = url.hostname.end_with?('.' + domain)
300
+ return false unless domain_match || (subdomains_allowed && subdomain_match)
301
+
302
+ path = cookie[:path]
303
+ path = path.end_with?('/') ? path[0..-2] : path
304
+
305
+ return true if url.path === path
306
+ return true if url.path.start_with?(path + '/')
307
+ false
308
+ end
290
309
  end
291
310
  end
292
311
  end
@@ -58,7 +58,8 @@ module Applitools
58
58
  end
59
59
 
60
60
  def init_or_renew_threads
61
- (concurrency - @thread_group.list.count).times do
61
+ one_concurrency = 1 # Thread's moved to universal server
62
+ (one_concurrency - @thread_group.list.count).times do
62
63
  logger.debug 'starting new thread (task worker)'
63
64
  next_thread
64
65
  end
@@ -7,8 +7,14 @@ require 'securerandom'
7
7
  module Applitools
8
8
  module Selenium
9
9
  class VisualGridEyes
10
+ # new open, with eyes-manager
11
+ include Applitools::UniversalEyesOpen
12
+ # all checks here
13
+ include Applitools::UniversalEyesChecks
14
+ # add extract_text, extract_text_regions, locate
15
+ include Applitools::UniversalNewApi
16
+
10
17
  include Applitools::Selenium::Concerns::SeleniumEyes
11
- DOM_EXTRACTION_TIMEOUT = 300 # seconds or 5 minutes
12
18
  USE_DEFAULT_MATCH_TIMEOUT = -1
13
19
  extend Forwardable
14
20
 
@@ -27,6 +33,10 @@ module Applitools
27
33
  def_delegators 'config', *Applitools::Selenium::Configuration.methods_to_delegate
28
34
  def_delegators 'config', *Applitools::EyesBaseConfiguration.methods_to_delegate
29
35
 
36
+ alias runner visual_grid_manager
37
+ attr_accessor :universal_eyes, :universal_driver
38
+ attr_accessor :debug_screenshots, :save_failed_tests, :scale_ratio, :disabled, :stitching_overlap, :compare_with_parent_branch
39
+
30
40
  def initialize(visual_grid_manager, server_url = nil)
31
41
  ensure_config
32
42
  @server_connector = Applitools::Connectivity::ServerConnector.new(server_url)
@@ -44,6 +54,7 @@ module Applitools
44
54
 
45
55
  def ensure_config
46
56
  self.config = Applitools::Selenium::Configuration.new
57
+ self.send_dom = true
47
58
  end
48
59
 
49
60
  def full_agent_id
@@ -57,51 +68,60 @@ module Applitools
57
68
  end
58
69
 
59
70
  def open(*args)
60
- self.test_uuid = SecureRandom.uuid
71
+ # self.test_uuid = SecureRandom.uuid
61
72
  options = Applitools::Utils.extract_options!(args)
62
- Applitools::ArgumentGuard.hash(options, 'options', [:driver])
63
-
64
- config.app_name = options[:app_name] if options[:app_name]
65
- config.test_name = options[:test_name] if options[:test_name]
66
- config.agent_run_id = "#{config.test_name}--#{SecureRandom.hex(10)}"
67
-
68
- if config.viewport_size.nil? || config.viewport_size && config.viewport_size.empty?
69
- config.viewport_size = Applitools::RectangleSize.from_any_argument(options[:viewport_size]) if options[:viewport_size]
70
- end
71
-
72
- self.driver = Applitools::Selenium::SeleniumEyes.eyes_driver(options.delete(:driver), self)
73
- self.current_url = driver.current_url
74
-
75
- if viewport_size
76
- set_viewport_size(viewport_size)
77
- else
78
- self.viewport_size = get_viewport_size
79
- end
80
-
81
- visual_grid_manager.open(self)
82
- visual_grid_manager.add_batch(batch.id) do
83
- server_connector.close_batch(batch.id)
84
- end
85
-
86
- logger.info('Getting all browsers info...')
87
- browsers_info_list = config.browsers_info
88
- logger.info('Creating test descriptors for each browser info...')
89
- browsers_info_list.each(viewport_size) do |bi|
90
- test = Applitools::Selenium::RunningTest.new(eyes_connector, bi, driver).tap do |t|
91
- t.on_results_received do |results|
92
- visual_grid_manager.aggregate_result(results)
93
- end
94
- t.test_uuid = test_uuid
95
- end
96
- test_list.push test
97
- end
98
- self.opened = true
99
- driver
73
+ universal_open(options)
74
+ # Applitools::ArgumentGuard.hash(options, 'options', [:driver])
75
+ #
76
+ # config.app_name = options[:app_name] if options[:app_name]
77
+ # config.test_name = options[:test_name] if options[:test_name]
78
+ # config.agent_run_id = "#{config.test_name}--#{SecureRandom.hex(10)}"
79
+ #
80
+ # if config.viewport_size.nil? || config.viewport_size && config.viewport_size.empty?
81
+ # config.viewport_size = Applitools::RectangleSize.from_any_argument(options[:viewport_size]) if options[:viewport_size]
82
+ # end
83
+ #
84
+ # self.driver = Applitools::Selenium::SeleniumEyes.eyes_driver(options.delete(:driver), self)
85
+ # self.current_url = driver.current_url
86
+ #
87
+ # if viewport_size
88
+ # set_viewport_size(viewport_size)
89
+ # else
90
+ # self.viewport_size = get_viewport_size
91
+ # end
92
+ #
93
+ # visual_grid_manager.open(self)
94
+ # visual_grid_manager.add_batch(batch.id) do
95
+ # server_connector.close_batch(batch.id)
96
+ # end
97
+ #
98
+ # logger.info('Getting all browsers info...')
99
+ # browsers_info_list = config.browsers_info
100
+ # logger.info('Creating test descriptors for each browser info...')
101
+ # browsers_info_list.each(viewport_size) do |bi|
102
+ # test = Applitools::Selenium::RunningTest.new(eyes_connector, bi, driver).tap do |t|
103
+ # t.on_results_received do |results|
104
+ # visual_grid_manager.aggregate_result(results)
105
+ # end
106
+ # t.test_uuid = test_uuid
107
+ # end
108
+ # test_list.push test
109
+ # end
110
+ # self.opened = true
111
+ # driver
100
112
  end
101
113
 
102
114
  def get_viewport_size(web_driver = driver)
103
115
  Applitools::ArgumentGuard.not_nil 'web_driver', web_driver
104
- self.utils.extract_viewport_size(driver)
116
+ # self.utils.extract_viewport_size(driver)
117
+ driver_config_json = universal_driver_config(web_driver)
118
+
119
+ Applitools::EyesLogger.debug 'extract_viewport_size()'
120
+ viewport_size = runner.universal_client.core_get_viewport_size(driver_config_json)
121
+ result = Applitools::RectangleSize.new viewport_size[:width], viewport_size[:height]
122
+
123
+ Applitools::EyesLogger.debug "Viewport size is #{result}."
124
+ result
105
125
  end
106
126
 
107
127
  def eyes_connector
@@ -125,42 +145,43 @@ module Applitools
125
145
  tag = first_arg[:name] || first_arg[:tag]
126
146
  end
127
147
 
128
- script = <<-END
129
- #{Applitools::Selenium::Scripts::PROCESS_PAGE_AND_POLL} return __processPageAndSerializePoll(document, {skipResources: [#{visual_grid_manager.resource_cache.urls_to_skip}]});
130
- END
131
148
  render_task = nil
132
149
  target.default_full_page_for_vg
133
150
 
151
+ return universal_check(tag, target)
152
+
134
153
  target_to_check = target.finalize
135
154
  begin
136
155
  check_in_frame(target_frames: target_to_check.frames) do
137
156
  sleep wait_before_screenshots
138
157
  Applitools::EyesLogger.info 'Trying to get DOM snapshot...'
139
-
140
- script_thread = Thread.new do
141
- result = {}
142
- while result['status'] != 'SUCCESS'
143
- Thread.current[:script_result] = driver.execute_script(script)
144
- begin
145
- Thread.current[:result] = result = Oj.load(Thread.current[:script_result])
146
- sleep 0.5
147
- rescue Oj::ParseError => e
148
- Applitools::EyesLogger.warn e.message
149
- end
150
- end
158
+ begin
159
+ dont_fetch_resources = self.dont_fetch_resources
160
+ enable_cross_origin_rendering = self.enable_cross_origin_rendering
161
+ use_cookies = !self.dont_use_cookies
162
+ urls_to_skip = visual_grid_manager.resource_cache.urls_to_skip
163
+ dom_script = Applitools::Selenium::DomSnapshotScript.new driver
164
+
165
+ script_dom = dom_script.create_dom_snapshot(
166
+ dont_fetch_resources,
167
+ urls_to_skip,
168
+ enable_cross_origin_rendering,
169
+ use_cookies
170
+ )
171
+ rescue StandardError => e
172
+ Applitools::EyesLogger.error e.class.to_s
173
+ Applitools::EyesLogger.error e.message
174
+ raise ::Applitools::EyesError.new 'Error while getting dom snapshot!'
151
175
  end
152
- sleep 0.5
153
- script_thread_result = script_thread.join(DOM_EXTRACTION_TIMEOUT)
154
- raise ::Applitools::EyesError.new 'Timeout error while getting dom snapshot!' unless script_thread_result
155
176
  Applitools::EyesLogger.info 'Done!'
156
177
 
157
- mod = Digest::SHA2.hexdigest(script_thread_result[:script_result])
178
+ mod = Digest::SHA2.hexdigest(script_dom.to_s)
158
179
 
159
180
  region_x_paths = get_regions_x_paths(target_to_check)
160
181
 
161
182
  render_task = RenderTask.new(
162
183
  "Render #{config.short_description} - #{tag}",
163
- script_thread_result[:result]['value'],
184
+ script_dom,
164
185
  visual_grid_manager,
165
186
  server_connector,
166
187
  region_x_paths,
@@ -298,21 +319,33 @@ module Applitools
298
319
  end
299
320
 
300
321
  def close(throw_exception = true)
301
- return false if test_list.empty?
302
- close_async
303
-
304
- until (states = test_list.map(&:state_name).uniq).count == 1 && states.first == :completed
305
- sleep 0.5
306
- end
307
- self.opened = false
308
-
309
- test_list.select { |t| t.pending_exceptions && !t.pending_exceptions.empty? }.each do |t|
310
- t.pending_exceptions.each do |e|
311
- raise e
312
- end
313
- end
314
-
315
- all_results = test_list.map(&:test_result).compact
322
+ logger.info "close(#{throw_exception})"
323
+ logger.info 'Ending server session...'
324
+
325
+ universal_results = universal_eyes.close # Array even for one test
326
+ raise Applitools::EyesError.new("Request failed: #{universal_results[:message]}") if server_error?(universal_results)
327
+ key_transformed_results = Applitools::Utils.deep_stringify_keys(universal_results)
328
+ results = key_transformed_results.map {|result| Applitools::TestResults.new(result) }
329
+ # results = results.first if results.size == 1
330
+ # session_results_url = results.url
331
+ all_results = results.compact
332
+
333
+
334
+ # return false if test_list.empty?
335
+ # close_async
336
+ #
337
+ # until (states = test_list.map(&:state_name).uniq).count == 1 && states.first == :completed
338
+ # sleep 0.5
339
+ # end
340
+ # self.opened = false
341
+ #
342
+ # test_list.select { |t| t.pending_exceptions && !t.pending_exceptions.empty? }.each do |t|
343
+ # t.pending_exceptions.each do |e|
344
+ # raise e
345
+ # end
346
+ # end
347
+ #
348
+ # all_results = test_list.map(&:test_result).compact
316
349
  failed_results = all_results.select { |r| !r.as_expected? }
317
350
 
318
351
  if throw_exception
@@ -323,16 +356,18 @@ module Applitools
323
356
  end
324
357
  end
325
358
 
326
- failed_results.empty? ? all_results.first : failed_results
359
+ failed_results.empty? ? all_results.first : failed_results.first
327
360
  end
328
361
 
329
362
  def abort_async
330
363
  test_list.each(&:abort)
364
+ universal_sdk_abort
331
365
  end
332
366
 
333
367
  def abort_if_not_closed
334
368
  self.opened = false
335
369
  test_list.each(&:abort)
370
+ universal_sdk_abort
336
371
  end
337
372
 
338
373
  alias abort abort_if_not_closed
@@ -349,6 +384,8 @@ module Applitools
349
384
 
350
385
  # rubocop:disable Style/AccessorMethodName
351
386
  def set_viewport_size(value)
387
+ # require('pry')
388
+ # binding.pry
352
389
  self.utils.set_viewport_size driver, value
353
390
  rescue => e
354
391
  logger.error e.class.to_s
@@ -400,6 +437,14 @@ module Applitools
400
437
 
401
438
  def add_text_trigger(_control, _text); end
402
439
 
440
+ def disabled=(value)
441
+ @disabled = Applitools::Utils.boolean_value value
442
+ end
443
+
444
+ def disabled?
445
+ @disabled
446
+ end
447
+
403
448
  private :new_test_error_message, :diffs_found_error_message, :test_failed_error_message
404
449
 
405
450
  private
@@ -61,6 +61,10 @@ module Applitools
61
61
  super
62
62
  end
63
63
 
64
+ def universal_eyes_manager_config
65
+ Applitools::UniversalEyesManagerConfig.vg(@thread_pool.concurrency)
66
+ end
67
+
64
68
  private
65
69
 
66
70
  def all_running_tests
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Applitools
4
- VERSION = '3.18.2'.freeze
4
+ VERSION = '4.0.2'.freeze
5
+ UNIVERSAL_VERSION = '1.0.9'.freeze
5
6
  end
data/lib/eyes_selenium.rb CHANGED
@@ -31,5 +31,14 @@ if defined? Selenium::WebDriver::Driver
31
31
  is_mobile_device = capabilities['platformName'] ? true : false
32
32
  Applitools::Selenium::Driver.new(eyes, driver: self, is_mobile_device: is_mobile_device)
33
33
  end
34
+
35
+ def universal_driver_config
36
+ hidden_server_url = bridge.http.send(:server_url).to_s
37
+ {
38
+ serverUrl: hidden_server_url,
39
+ sessionId: session_id,
40
+ capabilities: capabilities.as_json
41
+ }
42
+ end
34
43
  end
35
44
  end