eyes_selenium 2.39.1 → 3.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/applitools/capybara.rb +1 -1
  3. data/lib/applitools/selenium/border_aware_element_content_location_provider.rb +41 -0
  4. data/lib/applitools/selenium/browser.rb +1 -0
  5. data/lib/applitools/selenium/capybara/capybara_settings.rb +8 -0
  6. data/lib/applitools/selenium/capybara/driver.rb +1 -0
  7. data/lib/applitools/selenium/context_based_scale_provider.rb +36 -0
  8. data/lib/applitools/selenium/css_translate_position_provider.rb +66 -0
  9. data/lib/applitools/selenium/driver.rb +159 -44
  10. data/lib/applitools/selenium/element.rb +100 -8
  11. data/lib/applitools/selenium/element_position_provider.rb +48 -0
  12. data/lib/applitools/selenium/eyes.rb +922 -0
  13. data/lib/applitools/selenium/eyes_target_locator.rb +191 -0
  14. data/lib/applitools/selenium/eyes_web_driver_screenshot.rb +274 -0
  15. data/lib/applitools/selenium/frame.rb +24 -0
  16. data/lib/applitools/selenium/frame_chain.rb +68 -0
  17. data/lib/applitools/selenium/full_page_capture_algorithm.rb +162 -0
  18. data/lib/applitools/selenium/keyboard.rb +1 -0
  19. data/lib/applitools/selenium/match_window_task.rb +0 -197
  20. data/lib/applitools/selenium/mouse.rb +1 -0
  21. data/lib/applitools/selenium/move_to_region_visibility_strategy.rb +33 -0
  22. data/lib/applitools/selenium/nop_region_visibility_strategy.rb +16 -0
  23. data/lib/applitools/selenium/scroll_position_provider.rb +52 -0
  24. data/lib/applitools/selenium/takes_screenshot_image_provider.rb +36 -0
  25. data/lib/applitools/version.rb +1 -1
  26. data/lib/eyes_selenium.rb +19 -30
  27. metadata +24 -254
  28. data/.gitignore +0 -18
  29. data/.rspec +0 -2
  30. data/.rubocop.yml +0 -57
  31. data/.travis.yml +0 -17
  32. data/Gemfile +0 -4
  33. data/LICENSE.txt +0 -13
  34. data/README.md +0 -38
  35. data/Rakefile +0 -11
  36. data/certs/cacert.pem +0 -3557
  37. data/examples/appium_example_script.rb +0 -59
  38. data/examples/capybara_example.rb +0 -82
  39. data/examples/sauce_capybara_example.rb +0 -41
  40. data/examples/sauce_example.rb +0 -34
  41. data/examples/simple_test_script.rb +0 -23
  42. data/examples/watir_test_script.rb +0 -26
  43. data/eyes_selenium.gemspec +0 -89
  44. data/lib/applitools/appium_driver.rb +0 -7
  45. data/lib/applitools/base/batch_info.rb +0 -21
  46. data/lib/applitools/base/dimension.rb +0 -36
  47. data/lib/applitools/base/environment.rb +0 -19
  48. data/lib/applitools/base/image_position.rb +0 -10
  49. data/lib/applitools/base/mouse_trigger.rb +0 -33
  50. data/lib/applitools/base/point.rb +0 -34
  51. data/lib/applitools/base/region.rb +0 -112
  52. data/lib/applitools/base/server_connector.rb +0 -120
  53. data/lib/applitools/base/session.rb +0 -15
  54. data/lib/applitools/base/start_info.rb +0 -34
  55. data/lib/applitools/base/test_results.rb +0 -28
  56. data/lib/applitools/base/text_trigger.rb +0 -22
  57. data/lib/applitools/extensions.rb +0 -17
  58. data/lib/applitools/eyes.rb +0 -460
  59. data/lib/applitools/eyes_logger.rb +0 -38
  60. data/lib/applitools/method_tracer.rb +0 -22
  61. data/lib/applitools/poltergeist/applitools_compatible.rb +0 -28
  62. data/lib/applitools/poltergeist/driver.rb +0 -11
  63. data/lib/applitools/sauce.rb +0 -2
  64. data/lib/applitools/selenium/match_window_data.rb +0 -28
  65. data/lib/applitools/selenium_webdriver.rb +0 -8
  66. data/lib/applitools/utils/image_delta_compressor.rb +0 -148
  67. data/lib/applitools/utils/image_utils.rb +0 -143
  68. data/lib/applitools/utils/utils.rb +0 -49
  69. data/lib/applitools/watir_browser.rb +0 -8
  70. data/spec/driver_passthrough_spec.rb +0 -68
  71. data/spec/fixtures/static_test_file.html +0 -15
  72. data/spec/spec_helper.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ac6ebb7be4b5a18ba713a6ef6628810325979d58
4
- data.tar.gz: 397ff449e9dfcf03df28c7518167b5fcae0f891c
3
+ metadata.gz: 298245f32bacdf8a255523b09d83c01d992750d9
4
+ data.tar.gz: b989742805a0c330a4c92ea11fe1703e70b415ed
5
5
  SHA512:
6
- metadata.gz: a254e084da60256c59ab2a5d568ce8c4baebb362db0081f2c206361b2c21915161102351da6e925286cd9ae31068191652f7b717e89fbc8d670f74023544cc3f
7
- data.tar.gz: 0a4e68c2a92f8147eeaeefa22f13b05d645be179b88d8230b231788cfa6388ff941f1f76c51debfdd74475a2811c6ecf3fab09c52d5185e9df0e8d3bbccc32d0
6
+ metadata.gz: 9a641c66332c48f9ed14ee0a6895d6ed5a6a824bb15092ccfd9cd981f7a60f44abe2c1deccc242884509dfba25d5c47e0f9f5dcd018a038ce59a9317d615edbc
7
+ data.tar.gz: cf81849b83decbedd66337779dfba74f94a057e9595bd0f908af8d9457d5f19bae6612d146fe97e69e97376151dfd51be82ce3fe1d04d6e54a018992cd5f71ba
@@ -1,6 +1,6 @@
1
1
  require 'capybara'
2
2
 
3
- Applitools.require_dir 'selenium/capybara'
3
+ Applitools::Selenium.require_dir 'selenium/capybara'
4
4
 
5
5
  module Applitools
6
6
  extend Applitools::Selenium::Capybara::CapybaraSettings
@@ -0,0 +1,41 @@
1
+ module Applitools::Selenium
2
+ # @!visibility private
3
+ class BorderAwareElementContentLocationProvider
4
+ extend Forwardable
5
+
6
+ def_delegators 'Applitools::EyesLogger', :logger, :log_handler, :log_handler=
7
+
8
+ attr_accessor :element, :location, :size
9
+
10
+ def initialize(element)
11
+ raise Applitools::EyesIllegalArgument.new 'Passed element is not Applitools::Selenium::Element instance!' unless
12
+ element.is_a? Applitools::Selenium::Element
13
+ self.element = element
14
+ self.location = Applitools::Location.for element.location
15
+ self.size = Applitools::RectangleSize.for element.size
16
+ calculate_location_size
17
+ end
18
+
19
+ private
20
+
21
+ def calculate_location_size
22
+ border_left = element.border_left_width
23
+ border_right = element.border_right_width
24
+ border_top = element.border_top_width
25
+ border_bottom = element.border_bottom_width
26
+
27
+ padding_left = element.padding_left_width
28
+ padding_right = element.padding_right_width
29
+ padding_top = element.padding_top_width
30
+ padding_bottom = element.padding_bottom_width
31
+
32
+ location.offset Applitools::Location.new(border_left + padding_left, border_top + padding_top)
33
+ size - Applitools::RectangleSize.new(padding_left + padding_right + border_left + border_right,
34
+ padding_top + padding_bottom + border_top + border_bottom)
35
+
36
+ rescue Applitools::EyesDriverOperationException
37
+ self.location = Applitools::Location.for element.location
38
+ self.size = Applitools::RectangleSize.for element.size
39
+ end
40
+ end
41
+ end
@@ -1,4 +1,5 @@
1
1
  module Applitools::Selenium
2
+ # @!visibility private
2
3
  class Browser
3
4
  JS_GET_USER_AGENT = <<-JS.freeze
4
5
  return navigator.userAgent;
@@ -1,5 +1,13 @@
1
1
  module Applitools::Selenium::Capybara
2
2
  module CapybaraSettings
3
+ # Registers Capybara driver which will be used by eyes and sets it as default Capybara driver.
4
+ # The name of the driver is :eyes, and the driver is a descendant of class Capybara::Selenium::Driver.
5
+ # Options are eventually passed to drivers constructor
6
+ # @param [Hash] options
7
+ # @example
8
+ # Applitools.register_capybara_driver :browser => :chrome
9
+ # @example
10
+ # Applitools.register_capybara_driver :browser => :remote, :url => 'remote_url', :desired_capabilities => {}
3
11
  def register_capybara_driver(options = {})
4
12
  Capybara.register_driver :eyes do |app|
5
13
  Applitools::Selenium::Capybara::Driver.new app, options
@@ -1,5 +1,6 @@
1
1
  if defined? Capybara::Selenium::Driver
2
2
  module Applitools::Selenium::Capybara
3
+ # @!visibility private
3
4
  class Driver < Capybara::Selenium::Driver
4
5
  def driver_for_eyes(eyes)
5
6
  browser eyes: eyes
@@ -0,0 +1,36 @@
1
+ module Applitools::Selenium
2
+ # @!visibility private
3
+ class ContextBasedScaleProvider
4
+ UNKNOWN_SCALE_RATIO = 0
5
+ ALLOWED_VS_DEVIATION = 1
6
+ ALLOWED_DCES_DEVIATION = 10
7
+
8
+ attr_reader :top_level_context_entire_size, :viewport_size, :device_pixel_ratio, :scale_ratio
9
+
10
+ def initialize(top_level_context_entire_size, viewport_size, device_pixel_ratio)
11
+ @top_level_context_entire_size = top_level_context_entire_size
12
+ @viewport_size = viewport_size
13
+ @device_pixel_ratio = device_pixel_ratio
14
+ @scale_ratio = UNKNOWN_SCALE_RATIO
15
+ end
16
+
17
+ def scale_image(image)
18
+ if @scale_ratio == UNKNOWN_SCALE_RATIO
19
+ @scale_ratio = if ((image.width >= viewport_size.width - ALLOWED_VS_DEVIATION) &&
20
+ (image.width <= viewport_size.width + ALLOWED_VS_DEVIATION)) ||
21
+ ((image.width >= top_level_context_entire_size.width - ALLOWED_DCES_DEVIATION) &&
22
+ (image.width <= top_level_context_entire_size.width + ALLOWED_DCES_DEVIATION))
23
+ 1
24
+ else
25
+ 1.to_f / device_pixel_ratio
26
+ end
27
+ end
28
+ Applitools::Utils::ImageUtils.scale!(image, scale_ratio)
29
+ end
30
+
31
+ def scale_ratio
32
+ raise Applitools::EyesError.new 'Scale ratio is not defined yet!' if @scale_ratio == UNKNOWN_SCALE_RATIO
33
+ @scale_ratio
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,66 @@
1
+ module Applitools::Selenium
2
+ class CssTranslatePositionProvider
3
+ extend Forwardable
4
+
5
+ def_delegators 'Applitools::EyesLogger', :logger, :log_handler, :log_handler=
6
+
7
+ attr_accessor :last_state_position
8
+
9
+ def initialize(executor)
10
+ self.executor = executor
11
+ end
12
+
13
+ def current_position
14
+ last_state_position
15
+ end
16
+
17
+ def state
18
+ Applitools::Utils::EyesSeleniumUtils.current_transforms(executor)
19
+ end
20
+
21
+ def restore_state(value)
22
+ transforms = value.values.select { |el| !el.empty? }
23
+ Applitools::Utils::EyesSeleniumUtils.set_transforms(executor, value)
24
+ if transforms.empty?
25
+ self.last_state_position = Applitools::Location::TOP_LEFT
26
+ else
27
+ positions = transforms.map { |s| get_position_from_transform(s) }
28
+ positions.each { |p| raise Applitools::EyesError.new 'Got different css positions!' unless p == positions[0] }
29
+ self.last_state_position = positions[0]
30
+ end
31
+ end
32
+
33
+ def position=(value)
34
+ Applitools::ArgumentGuard.not_nil(value, 'value')
35
+ logger.info "Setting position to: #{value}"
36
+ Applitools::Utils::EyesSeleniumUtils.translate_to(executor, value)
37
+ logger.info 'Done!'
38
+ self.last_state_position = value
39
+ end
40
+
41
+ def force_offset
42
+ Applitools::Location.from_any_attribute last_state_position
43
+ end
44
+
45
+ alias scroll_to position=
46
+
47
+ def entire_size
48
+ e_size = Applitools::Utils::EyesSeleniumUtils.current_frame_content_entire_size(executor)
49
+ logger.info "Entire size: #{e_size}"
50
+ e_size
51
+ end
52
+
53
+ private
54
+
55
+ attr_accessor :executor
56
+
57
+ def get_position_from_transform(transform)
58
+ regexp = /^translate\(\s*(\-?)(\d+)px,\s*(\-?)(\d+)px\s*\)/
59
+ data = regexp.match(transform)
60
+ raise Applitools::EyesError.new "Can't parse CSS transition: #{transform}!" unless data
61
+ x = data[1].empty? ? data[2].to_i : -1 * data[2].to_i
62
+ y = data[3].empty? ? data[4].to_i : -1 * data[4].to_i
63
+ Applitools::Location.new(x, y)
64
+ end
65
+ end
66
+ end
@@ -1,4 +1,3 @@
1
- require 'forwardable'
2
1
  require 'socket'
3
2
  require 'selenium-webdriver'
4
3
 
@@ -7,10 +6,14 @@ module Applitools::Selenium
7
6
  extend Forwardable
8
7
 
9
8
  RIGHT_ANGLE = 90
9
+ # @!visibility private
10
10
  IOS = 'IOS'.freeze
11
+ # @!visibility private
11
12
  ANDROID = 'ANDROID'.freeze
13
+ # @!visibility private
12
14
  LANDSCAPE = 'LANDSCAPE'.freeze
13
15
 
16
+ # Available finders
14
17
  FINDERS = {
15
18
  class: 'class name',
16
19
  class_name: 'class name',
@@ -26,9 +29,11 @@ module Applitools::Selenium
26
29
 
27
30
  attr_reader :browser
28
31
  attr_accessor :wait_before_screenshots
32
+ attr_accessor :rotation
29
33
 
30
- def_delegators :@eyes, :user_inputs, :clear_user_inputs
34
+ def_delegators :@eyes, :add_mouse_trigger, :add_text_trigger
31
35
  def_delegators :@browser, :user_agent
36
+ def_delegators 'Applitools::EyesLogger', :logger, :log_handler, :log_handler=
32
37
 
33
38
  # If driver is not provided, Applitools::Selenium::Driver will raise an EyesError exception.
34
39
  def initialize(eyes, options)
@@ -36,82 +41,87 @@ module Applitools::Selenium
36
41
  @is_mobile_device = options.fetch(:is_mobile_device, false)
37
42
  @wait_before_screenshots = 0
38
43
  @eyes = eyes
44
+ @frame_chain = Applitools::Selenium::FrameChain.new
39
45
  @browser = Applitools::Selenium::Browser.new(self, @eyes)
40
46
  Applitools::EyesLogger.warn '"screenshot_as" method not found!' unless driver.respond_to? :screenshot_as
41
47
  end
42
48
 
43
- # Returns:
44
- # +String+ The platform name or +nil+ if it is undefined.
49
+ # Executes javascript in browser context
50
+ # @raise [Applitools::EyesDriverOperationException]
51
+ def execute_script(*args)
52
+ raises_error { __getobj__.execute_script(*args) }
53
+ end
54
+
55
+ # @return [String] The platform name or +nil+ if it is undefined.
45
56
  def platform_name
46
57
  capabilities['platformName']
47
58
  end
48
59
 
49
- # Returns:
50
- # +String+ The platform version or +nil+ if it is undefined.
60
+ # @return [String] The platform version or +nil+ if it is undefined.
51
61
  def platform_version
52
62
  version = capabilities['platformVersion']
53
63
  version.nil? ? nil : version.to_s
54
64
  end
55
65
 
56
- # Returns:
57
- # +true+ if the driver orientation is landscape.
66
+ # Returns +true+ if the driver orientation is landscape.
58
67
  def landscape_orientation?
59
68
  driver.orientation.to_s.upcase == LANDSCAPE
60
69
  rescue NameError
61
70
  Applitools::EyesLogger.debug 'driver has no "orientation" attribute. Assuming: portrait.'
62
71
  end
63
72
 
64
- # Returns:
65
- # +true+ if the platform running the test is a mobile platform. +false+ otherwise.
73
+ # Returns +true+ if the platform running the test is a mobile platform. +false+ otherwise.
66
74
  def mobile_device?
67
75
  # We CAN'T check if the device is an +Appium::Driver+ since it is not a RemoteWebDriver. Because of that we use a
68
76
  # flag we got as an option in the constructor.
69
77
  @is_mobile_device
70
78
  end
71
79
 
72
- ## Hide the main document's scrollbars and returns the original overflow value.
80
+ # Hide the main document's scrollbars and returns the original overflow value.
73
81
  def hide_scrollbars
74
82
  @browser.hide_scrollbars
75
83
  end
76
84
 
77
- ## Set the overflow value for document element and return the original overflow value.
85
+ # Set the overflow value for document element and return the original overflow value.
78
86
  def overflow=(overflow)
79
87
  @browser.set_overflow(overflow)
80
88
  end
81
89
 
82
- alias set_overflow overflow=
83
-
84
- # Return a normalized screenshot.
85
- #
86
- # +rotation+:: +Integer+|+nil+ The degrees by which to rotate the image: positive values = clockwise rotation,
87
- # negative values = counter-clockwise, 0 = force no rotation, +nil+ = rotate automatically when needed.
88
- # +tag+:: +String|nil+ The tag specified for the test, used onle when +debug_screenshot+ is set to true
89
- #
90
- # Returns: +ChunkPng::Image+ A screenshot object, normalized by scale and rotation.
91
- def get_screenshot(rotation = nil, tag = nil)
92
- @tag_for_screenshot_debug = tag
93
- @visible_screenshot_call_count = 0
94
- image = mobile_device? || !@eyes.force_fullpage_screenshot ? visible_screenshot : @browser.fullpage_screenshot
95
- Applitools::Selenium::Driver.normalize_image(self, image, rotation)
96
- image
90
+ # Returns native driver
91
+ # @return Selenium::WebDriver
92
+ def remote_web_driver
93
+ driver
97
94
  end
98
95
 
99
- def visible_screenshot
100
- Applitools::EyesLogger.debug "Waiting before screenshot: #{wait_before_screenshots} seconds..."
101
- sleep(wait_before_screenshots)
102
- Applitools::EyesLogger.debug 'Finished waiting.'
103
- screenshot = driver.screenshot_as(:png)
104
- save_image(screenshot) if @eyes.debug_screenshot
105
- Applitools::Utils::ImageUtils::Screenshot.new screenshot
106
- end
96
+ alias set_overflow overflow=
107
97
 
108
- def mouse
109
- Applitools::Selenium::Mouse.new(self, driver.mouse)
98
+ # Takes a screenshot
99
+ # @param [:Symbol] format A format to store screenshot (one of +:base64+ or +:png+)
100
+ # @return [String] A byte string, representing the screenshot
101
+ def screenshot_as(format)
102
+ raise "Invalid format (#{format}) passed! Available formats: :png, :base64" unless %i(base64 png).include? format
103
+ png_screenshot = driver.screenshot_as(:png)
104
+ yield png_screenshot if block_given?
105
+ screenshot = Applitools::Screenshot.new(png_screenshot)
106
+ self.class.normalize_rotation(self, screenshot, rotation)
107
+ return Applitools::Utils::ImageUtils.base64_from_png_image(screenshot.restore) if format == :base64
108
+ screenshot.to_blob
110
109
  end
111
110
 
112
- def keyboard
113
- Applitools::Selenium::Keyboard.new(self, driver.keyboard)
114
- end
111
+ # Finds an element, specified by +what+ parameter interpreting it in the way, specified in +how+ parameter
112
+ # @param [Symbol] how Defines the way that +what+ parameter will be interpreted (The type of selector). Can be one
113
+ # of: +:class+, +:class_name+, +:css+, +:id+, +:link+, +:link_text+, +:name+, +:partial_link_text+, +:tag_name+,
114
+ # +:xpath+
115
+ # @param [String] what The selector to find an element
116
+ # @example
117
+ # driver.find_element :css, '.some_class'
118
+ # @example
119
+ # driver.find_element :css => '.some_class'
120
+ # @example
121
+ # driver.find_element :id, 'element_id'
122
+ # @raise [ArgumentError] if invalid finder (+how+) is passed
123
+ # @return [Applitools::Selenium::Element]
124
+ # @!parse def find_element(how, what); end
115
125
 
116
126
  def find_element(*args)
117
127
  how, what = extract_args(args)
@@ -122,6 +132,21 @@ module Applitools::Selenium
122
132
  Applitools::Selenium::Element.new(self, driver.find_element(how, what))
123
133
  end
124
134
 
135
+ # Finds elements, specified by +what+ parameter interpreting it in the way, specified in +how+ parameter
136
+ # @param [Symbol] how Defines the way that +what+ parameter will be interpreted (The type of selector). Can be one
137
+ # of: +:class+, +:class_name+, +:css+, +:id+, +:link+, +:link_text+, +:name+, +:partial_link_text+, +:tag_name+,
138
+ # +:xpath+
139
+ # @param [String] what The selector to find an element
140
+ # @example
141
+ # driver.find_elements :css, '.some_class'
142
+ # @example
143
+ # driver.find_elements :css => '.some_class'
144
+ # @example
145
+ # driver.find_elements :id, 'element_id'
146
+ # @raise [ArgumentError] if invalid finder (+how+) is passed
147
+ # @return [ [Applitools::Selenium::Element] ]
148
+ # @!parse def find_elements(how, what); end
149
+
125
150
  def find_elements(*args)
126
151
  how, what = extract_args(args)
127
152
 
@@ -130,20 +155,63 @@ module Applitools::Selenium
130
155
  driver.find_elements(how, what).map { |el| Applitools::Selenium::Element.new(self, el) }
131
156
  end
132
157
 
158
+ # Returns +true+ if test is running on Android platform
133
159
  def android?
134
160
  platform_name.to_s.upcase == ANDROID
135
161
  end
136
162
 
163
+ # Returns +true+ if test is running on iOS platform
137
164
  def ios?
138
165
  platform_name.to_s.upcase == IOS
139
166
  end
140
167
 
168
+ # Returns a copy of current frame chain. Frame chain stores information about all parent frames,
169
+ # including scroll offset an frame coordinates
170
+ def frame_chain
171
+ Applitools::Selenium::FrameChain.new other: @frame_chain
172
+ end
173
+
174
+ # Returns current frame chain. Frame chain stores information about all parent frames,
175
+ # including scroll offset an frame coordinates
176
+ def frame_chain!
177
+ @frame_chain
178
+ end
179
+
180
+ # Gets +default_content_viewport_size+
181
+ # @param [Boolean] force_query if set to true, forces querying of viewport size from the browser,
182
+ # otherwise returns cached value
183
+ # @return [Applitools::RectangleSize]
184
+ def default_content_viewport_size(force_query = false)
185
+ logger.info('default_content_viewport_size()')
186
+ if cached_default_content_viewport_size && !force_query
187
+ logger.info "Using cached viewport_size #{cached_default_content_viewport_size}"
188
+ return cached_default_content_viewport_size
189
+ end
190
+
191
+ current_frames = frame_chain
192
+ switch_to.default_content unless current_frames.empty?
193
+ logger.info 'Extracting viewport size...'
194
+ @cached_default_content_viewport_size = Applitools::Utils::EyesSeleniumUtils.extract_viewport_size(self)
195
+ logger.info "Done! Viewport size is #{@cached_default_content_viewport_size}"
196
+
197
+ switch_to.frames(frame_chain: current_frames) unless current_frames.empty?
198
+ @cached_default_content_viewport_size
199
+ end
200
+
201
+ def switch_to
202
+ @switch_to ||= Applitools::Selenium::EyesTargetLocator.new(
203
+ self, driver.switch_to, FrameChangeEventListener.new(self)
204
+ )
205
+ end
206
+
141
207
  private
142
208
 
143
- def save_image(image)
144
- tag = (@tag_for_screenshot_debug || 'screenshot').gsub(/\s+/, '_')
145
- screenshot = ChunkyPNG::Image.from_string(image)
146
- screenshot.save("#{tag}_#{Time.now.strftime('%Y_%m_%d_%H_%M')}__#{@visible_screenshot_call_count += 1}.png")
209
+ attr_reader :cached_default_content_viewport_size
210
+
211
+ def raises_error
212
+ yield if block_given?
213
+ rescue => e
214
+ raise Applitools::EyesDriverOperationException.new e.message
147
215
  end
148
216
 
149
217
  def bridge
@@ -172,6 +240,53 @@ module Applitools::Selenium
172
240
  end
173
241
  end
174
242
 
243
+ # @!visibility private
244
+ class FrameChangeEventListener
245
+ extend Forwardable
246
+
247
+ def_delegators 'Applitools::EyesLogger', :logger, :log_handler, :log_handler=
248
+
249
+ def initialize(parent)
250
+ self.parent = parent
251
+ end
252
+
253
+ def will_switch_to_frame(target_type, target_frame)
254
+ logger.info 'will_switch_to_frame()'
255
+ case target_type
256
+ when :default_content
257
+ logger.info 'Default content.'
258
+ parent.frame_chain!.clear
259
+ return nil
260
+ when :parent_frame
261
+ logger.info 'Parent frame.'
262
+ return parent.frame_chain!.pop
263
+ when :frame
264
+ logger.info 'Frame.'
265
+ frame_location_size = Applitools::Selenium::BorderAwareElementContentLocationProvider.new target_frame
266
+
267
+ return parent.frame_chain!.push(
268
+ Applitools::Selenium::Frame.new(
269
+ reference: target_frame, frame_id: '',
270
+ location: Applitools::Location.for(frame_location_size.location),
271
+ size: Applitools::RectangleSize.for(frame_location_size.size),
272
+ parent_scroll_position: Applitools::Selenium::ScrollPositionProvider.new(parent).current_position
273
+ )
274
+ )
275
+ else
276
+ raise Applitools::EyesError.new('will_switch_to_frame(): target type is not recognized!')
277
+ end
278
+ logger.info 'Done!'
279
+ end
280
+
281
+ # def will_switch_to_window(name_or_handle)
282
+ #
283
+ # end
284
+
285
+ private
286
+
287
+ attr_accessor :parent
288
+ end
289
+
175
290
  class << self
176
291
  def normalize_image(driver, image, rotation)
177
292
  normalize_rotation(driver, image, rotation)