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
@@ -0,0 +1,191 @@
1
+ module Applitools::Selenium
2
+ class EyesTargetLocator < SimpleDelegator
3
+ extend Forwardable
4
+
5
+ def_delegators 'Applitools::EyesLogger', :logger, :log_handler, :log_handler=
6
+
7
+ attr_reader :driver, :on_will_switch, :scroll_position_provider
8
+
9
+ def initialize(driver, original_target_locator, on_will_switch)
10
+ super(original_target_locator)
11
+ @driver = driver
12
+ @on_will_switch = on_will_switch
13
+ @scroll_position_provider = Applitools::Selenium::ScrollPositionProvider.new(driver)
14
+ end
15
+
16
+ # @param [Hash] options
17
+ # @option options [Fixnum] :index
18
+ # @option options [String] :name_or_id
19
+ # @option options [WebElement] :frameElement
20
+ # @return [Applitools::Selenium::Driver]
21
+ def frame(options = {})
22
+ raise Applitools::EyesIllegalArgument.new 'You must pass :index or :name_or_id or :frame_element option' unless
23
+ options[:index] || options[:name_or_id] || options[:frame_element]
24
+ if (needed_keys = (options.keys & %i(index name_or_id frame_element))).length == 1
25
+ send "frame_by_#{needed_keys.first}", options[needed_keys.first]
26
+ else
27
+ raise Applitools::EyesIllegalArgument.new 'You\'ve passed some extra keys!' /
28
+ 'Only :index, :name_or_id or :frame_elenent are allowed.'
29
+ end
30
+ end
31
+
32
+ def parent_frame
33
+ logger.info 'EyesTargetLocator.parent_frame()'
34
+ unless driver.frame_chain.empty?
35
+ on_will_switch.will_switch_to_frame :parent_frame, nil
36
+ logger.info 'Done! Switching to parent_frame...'
37
+ __getobj__.parent_frame
38
+ end
39
+ logger.info 'Done!'
40
+ driver
41
+ end
42
+
43
+ # @param [hash] options
44
+ # @option options [Applitools::Selenium::FrameChain] :frame_chain
45
+ # @option options [String] :frames_path
46
+ # @return Applitools::Selenium::Driver
47
+ def frames(options = {})
48
+ raise Applitools::EyesIllegalArgument.new 'You must pass :frame_chain or :frames_path' if
49
+ options[:frame_chain].nil? & options[:frames_path].nil?
50
+
51
+ if (needed_keys = (options.keys & %i(frame_chain frames_path))).length == 1
52
+ send "frames_by_#{needed_keys.first}", options[needed_keys.first]
53
+ else
54
+ raise Applitools::EyesIllegalArgument.new 'You\'ve passed some extra keys!' /
55
+ 'Only :frame_index or :frames_path are allowed.'
56
+ end
57
+ end
58
+
59
+ # A wrapper for the native method +default_content+
60
+ def default_content
61
+ logger.info 'EyesTargetLocator.default_content()'
62
+ unless driver.frame_chain.empty?
63
+ logger.info 'Making preparations...'
64
+ on_will_switch.will_switch_to_frame :default_content, nil
65
+ logger.info 'Done! Switching to default content...'
66
+ __getobj__.default_content
67
+ logger.info 'Done!'
68
+ end
69
+ driver
70
+ end
71
+
72
+ # A wrapper for the native method +window+
73
+ def window(name_or_handle)
74
+ logger.info 'EyesTargetLocator.window()'
75
+ logger.info 'Making preparaions...'
76
+ on_will_switch.will_switch_to_window name_or_handle
77
+ logger.info 'Done! Switching to window..'
78
+ __getobj__.window name_or_handle
79
+ logger.info 'Done!'
80
+ driver
81
+ end
82
+
83
+ # A wrapper for the native method +active_element+
84
+ def active_element
85
+ logger.info 'EyesTargetLocator.active_element()'
86
+ logger.info 'Switching to element...'
87
+ element = __getobj__.active_element
88
+
89
+ unless element.is_a? Selenium::WebDriver::Element
90
+ raise Applitools::EyesError.new(
91
+ 'Not an Selenium::WebDriver::Element!'
92
+ )
93
+ end
94
+
95
+ result = Applitools::Selenium::Element.new driver, element
96
+
97
+ logger.info 'Done!'
98
+ result
99
+ end
100
+
101
+ # A wrapper for a native method +alert+
102
+ def alert
103
+ logger.info 'EyesTargetLocator.alert()'
104
+ logger.info 'Switching to alert...'
105
+ result = __getobj__.alert
106
+ logger.info 'Done!'
107
+ result
108
+ end
109
+
110
+ private
111
+
112
+ def frame_by_index(index)
113
+ raise Applitools::EyesInvalidArgument.new 'You should pass Integer as :index value!' unless index.is_a? Integer
114
+ logger.info "EyesTargetLocator.frame(#{index})"
115
+ logger.info 'Getting frames list...'
116
+ frames = driver.find_elements(:css, 'frame, iframe')
117
+ raise Applitools::EyesNoSuchFrame.new "Frame index #{index} is invalid!" if index >= frames.size
118
+
119
+ logger.info 'Done! getting the specific frame...'
120
+ target_frame = frames[index]
121
+
122
+ logger.info 'Done! Making preparations...'
123
+ on_will_switch.will_switch_to_frame :frame, target_frame
124
+ logger.info 'Done! Switching to frame...'
125
+
126
+ # TODO: Looks like switching to frame by index (Fixnum) doesn't work at least for Chrome browser
127
+ # Is it better to use __getobj__.frame target_frame instead?
128
+ # __getobj__.frame index
129
+ __getobj__.frame target_frame
130
+
131
+ logger.info 'Done!'
132
+ driver
133
+ end
134
+
135
+ def frame_by_name_or_id(name_or_id)
136
+ logger.info "EyesTargetLocator.frame(#{name_or_id})"
137
+ # Finding the target element so we can report it.
138
+ # We use find elements(plural) to avoid exception when the element
139
+ # is not found.
140
+ logger.info 'Getting frames by name...'
141
+ frames = driver.find_elements :name, name_or_id
142
+ if frames.empty?
143
+ logger.info 'No frames found! Trying by id...'
144
+ frames = driver.find_elements :id, name_or_id
145
+ raise Applitools::EyesNoSuchFrame.new "No frame with name or id #{name_or_id} exists!" if frames.empty?
146
+ end
147
+ logger.info 'Done! Making preparations...'
148
+ on_will_switch.will_switch_to_frame(:frame, frames.first).last
149
+ logger.info 'Done! Switching to frame...'
150
+ __getobj__.frame frames.first
151
+
152
+ logger.info 'Done!'
153
+ driver
154
+ end
155
+
156
+ def frame_by_frame_element(web_element)
157
+ logger.info "EyesTargetLocator.frame(element) [#{web_element}]"
158
+ logger.info 'Done! Making preparations...'
159
+ on_will_switch.will_switch_to_frame :frame, web_element
160
+ logger.info 'Done! Switching to frame...'
161
+ __getobj__.frame web_element
162
+
163
+ logger.info 'Done!'
164
+ driver
165
+ end
166
+
167
+ def frames_by_frame_chain(frame_chain)
168
+ logger.info "EyesTargetLocator.frames(:frame_chain => a_chain) [#{frame_chain}]"
169
+ frame_chain.each do |frame|
170
+ logger.info 'Scrolling by parent scroll position...'
171
+ # scroll_position_provider.scroll_to frame.parent_scroll_position
172
+ logger.info 'Done! Switching to frame...'
173
+ frame(frame_element: frame.reference)
174
+ logger.info 'Done!'
175
+ logger.info 'Done switching into nested frames!'
176
+ driver
177
+ end
178
+ end
179
+
180
+ def frames_by_frames_path(frames_path)
181
+ logger.info 'EyesTargetLocator.frames(:frames_path => a_chain)'
182
+ frames_path.each do |frame_name_or_id|
183
+ logger.info 'Switching to frame...'
184
+ frame(name_or_id: frame_name_or_id)
185
+ logger.info 'Done!'
186
+ end
187
+ logger.info 'Done switching into nested frames!'
188
+ driver
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,274 @@
1
+ module Applitools::Selenium
2
+ # @!visibility private
3
+ class EyesWebDriverScreenshot < Applitools::EyesScreenshot
4
+ SCREENSHOT_TYPES = {
5
+ viewport: 'VIEPORT',
6
+ entire_frame: 'ENTIRE_FRAME'
7
+ }.freeze
8
+
9
+ INIT_CALLBACKS = {
10
+ [:driver, :screenshot_type, :frame_location_in_screenshot].sort => :initialize_main,
11
+ [:driver, :force_offset].sort => :initialize_main,
12
+ [:driver].sort => :initialize_main,
13
+ [:driver, :position_provider].sort => :initialize_main,
14
+ [:driver, :entire_frame_size].sort => :initialize_for_element,
15
+ [:driver, :entire_frame_size, :frame_location_in_screenshot].sort => :initialize_for_element
16
+ }.freeze
17
+
18
+ attr_accessor :driver
19
+ attr_accessor :frame_chain
20
+ private :frame_chain=
21
+
22
+ class << self
23
+ alias _new new
24
+
25
+ def new(*args)
26
+ image = args.shift
27
+ raise Applitools::EyesIllegalArgument.new 'image is expected to be Applitools::Screenshot!' unless
28
+ image.is_a? Applitools::Screenshot
29
+
30
+ options = args.first
31
+ if options.is_a? Hash
32
+ result = _new(image)
33
+ callback = INIT_CALLBACKS[options.keys.sort]
34
+ return result.tap { |o| o.send callback, options } if result.respond_to? callback
35
+ raise Applitools::EyesIllegalArgument.new 'Can\'t find an appropriate initializer!'
36
+ end
37
+ raise Applitools::EyesIllegalArgument.new "#{self.class}.initialize(): Hash is expected as an argument!"
38
+ end
39
+
40
+ def calc_frame_location_in_screenshot(frame_chain, screenshot_type, logger)
41
+ frame_chain = Applitools::Selenium::FrameChain.new other: frame_chain
42
+ logger.info 'Getting first frame...'
43
+ first_frame = frame_chain.shift
44
+ logger.info 'Done!'
45
+ location_in_screenshot = Applitools::Location.for first_frame.location
46
+
47
+ if screenshot_type == SCREENSHOT_TYPES[:viewport]
48
+ default_content_scroll = first_frame.parent_scroll_position
49
+ location_in_screenshot.offset_negative(
50
+ Applitools::Location.for(default_content_scroll.x, default_content_scroll.y)
51
+ )
52
+ end
53
+
54
+ logger.info 'Iterating over frames...'
55
+ frame_chain.each do |frame|
56
+ location_in_screenshot.offset(Applitools::Location.for(frame.location.x, frame.location.y))
57
+ .offset_negative(
58
+ Applitools::Location.for(
59
+ frame.parent_scroll_position.x, frame.parent_scroll_position.y
60
+ )
61
+ )
62
+ end
63
+ location_in_screenshot
64
+ end
65
+ end
66
+
67
+ def initialize_for_element(options = {})
68
+ Applitools::ArgumentGuard.not_nil options[:driver], 'options[:driver]'
69
+ Applitools::ArgumentGuard.not_nil options[:entire_frame_size], 'options[:entire_frame_size]'
70
+ entire_frame_size = options[:entire_frame_size]
71
+ self.driver = options[:driver]
72
+ self.frame_chain = driver.frame_chain
73
+ self.screenshot_type = SCREENSHOT_TYPES[:entire_frame]
74
+ self.scroll_position = Applitools::Location.new(0, 0)
75
+ self.scroll_position = Applitools::Location.new(0, 0).offset(options[:frame_location_in_screenshot]) if
76
+ options[:frame_location_in_screenshot].is_a? Applitools::Location
77
+ self.frame_location_in_screenshot = Applitools::Location.new(0, 0)
78
+ self.frame_window = Applitools::Region.new(0, 0, entire_frame_size.width, entire_frame_size.height)
79
+ end
80
+
81
+ def initialize_main(options = {})
82
+ # options = {screenshot_type: SCREENSHOT_TYPES[:viewport]}.merge options
83
+
84
+ Applitools::ArgumentGuard.hash options, 'options', [:driver]
85
+ Applitools::ArgumentGuard.not_nil options[:driver], 'options[:driver]'
86
+
87
+ self.driver = options[:driver]
88
+ self.position_provider = Applitools::Selenium::ScrollPositionProvider.new driver if
89
+ options[:position_provider].nil?
90
+
91
+ viewport_size = driver.default_content_viewport_size
92
+
93
+ self.frame_chain = driver.frame_chain
94
+ if !frame_chain.empty?
95
+ frame_size = frame_chain.current_frame_size
96
+ else
97
+ begin
98
+ frame_size = position_provider.entire_size
99
+ rescue
100
+ frame_size = viewport_size
101
+ end
102
+ end
103
+
104
+ begin
105
+ self.scroll_position = position_provider.current_position
106
+ rescue
107
+ self.scroll_position = Applitools::Location.new(0, 0)
108
+ end
109
+
110
+ if options[:screenshot_type].nil?
111
+ self.screenshot_type = if image.width <= viewport_size.width && image.height <= viewport_size.height
112
+ SCREENSHOT_TYPES[:viewport]
113
+ else
114
+ SCREENSHOT_TYPES[:entire_frame]
115
+ end
116
+ else
117
+ self.screenshot_type = options[:screenshot_type]
118
+ end
119
+
120
+ if options[:frame_location_in_screenshot].nil?
121
+ if !frame_chain.empty?
122
+ self.frame_location_in_screenshot = self.class.calc_frame_location_in_screenshot(
123
+ frame_chain, screenshot_type, logger
124
+ )
125
+ else
126
+ self.frame_location_in_screenshot = Applitools::Location.new(0, 0)
127
+ end
128
+ else
129
+ self.frame_location_in_screenshot = options[:frame_location_in_screenshot]
130
+ end
131
+
132
+ self.force_offset = Applitools::Location::TOP_LEFT
133
+ self.force_offset = options[:force_offset] if options[:force_offset]
134
+
135
+ logger.info 'Calculating frame window..'
136
+ self.frame_window = Applitools::Region.from_location_size(frame_location_in_screenshot, frame_size)
137
+ frame_window.intersect Applitools::Region.new(0, 0, image.width, image.height)
138
+
139
+ raise Applitools::EyesError.new 'Got empty frame window for screenshot!' if
140
+ frame_window.width <= 0 || frame_window.height <= 0
141
+
142
+ logger.info 'Done!'
143
+ end
144
+
145
+ # def scroll_position
146
+ # begin
147
+ # position_provider.state
148
+ # rescue
149
+ # Applitools::Location.new(0,0)
150
+ # end
151
+ # end
152
+
153
+ def convert_location(location, from, to)
154
+ Applitools::ArgumentGuard.not_nil location, 'location'
155
+ Applitools::ArgumentGuard.not_nil from, 'from'
156
+ Applitools::ArgumentGuard.not_nil to, 'to'
157
+
158
+ result = Applitools::Location.for location
159
+ return result if from == to
160
+ # if frame_chain.size.zero? && screenshot_type == SCREENSHOT_TYPES[:entire_frame]
161
+ # if (from == Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative] ||
162
+ # from == Applitools::EyesScreenshot::COORDINATE_TYPES[:context_as_is]) &&
163
+ # to == Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
164
+ # result.offset frame_location_in_screenshot
165
+ # elsif from == Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is] &&
166
+ # (to == Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative] ||
167
+ # to == Applitools::EyesScreenshot::COORDINATE_TYPES[:context_as_is])
168
+ # result.offset_negative frame_location_in_screenshot
169
+ # end
170
+ # end
171
+
172
+ case from
173
+ when Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative]
174
+ case to
175
+ when Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
176
+ result.offset_negative scroll_position
177
+ result.offset frame_location_in_screenshot
178
+ else
179
+ raise Applitools::EyesCoordinateTypeConversionException.new "Can't convert coordinates from #{from} to #{to}"
180
+ end
181
+ when Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
182
+ case to
183
+ when Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative]
184
+ result.offset_negative frame_location_in_screenshot
185
+ result.offset scroll_position
186
+ else
187
+ raise Applitools::EyesCoordinateTypeConversionException.new "Can't convert coordinates from #{from} to #{to}"
188
+ end
189
+ else
190
+ raise Applitools::EyesCoordinateTypeConversionException.new "Can't convert coordinates from #{from} to #{to}"
191
+ end
192
+
193
+ result
194
+ end
195
+
196
+ def frame_chain
197
+ Applitools::Selenium::FrameChain.new other: @frame_chain
198
+ end
199
+
200
+ def intersected_region(region, original_coordinate_types, result_coordinate_types)
201
+ return Applitools::Region::EMPTY if region.empty?
202
+ intersected_region = convert_region_location(
203
+ region, original_coordinate_types, Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
204
+ )
205
+ case original_coordinate_types
206
+ when Applitools::EyesScreenshot::COORDINATE_TYPES[:context_as_is]
207
+ nil
208
+ when Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative]
209
+ intersected_region.intersect frame_window
210
+ when Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
211
+ intersected_region.intersect Applitools::Region.new(0, 0, image.width, image.height)
212
+ else
213
+ raise Applitools::EyesCoordinateTypeConversionException.new(
214
+ "Unknown coordinates type: #{original_coordinate_types}"
215
+ )
216
+ end
217
+
218
+ return intersected_region if intersected_region.empty?
219
+ convert_region_location(
220
+ intersected_region,
221
+ Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is],
222
+ result_coordinate_types
223
+ )
224
+ end
225
+
226
+ def location_in_screenshot(location, coordinate_type)
227
+ location = convert_location(
228
+ location, coordinate_type, Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
229
+ )
230
+ unless frame_window.contains?(location.x, location.y)
231
+ raise Applitools::OutOfBoundsException.new(
232
+ "Location #{location} (#{coordinate_type}) is not visible in screenshot!"
233
+ )
234
+ end
235
+ location
236
+ end
237
+
238
+ def sub_screenshot(region, coordinate_type, throw_if_clipped = false)
239
+ logger.info "get_subscreenshot(#{region}, #{coordinate_type}, #{throw_if_clipped})"
240
+ Applitools::ArgumentGuard.not_nil region, 'region'
241
+ Applitools::ArgumentGuard.not_nil coordinate_type, 'coordinate_type'
242
+
243
+ region_to_check = Applitools::Region.from_location_size(
244
+ region.location.offset_negative(force_offset), region.size
245
+ )
246
+
247
+ as_is_subscreenshot_region = intersected_region region_to_check, coordinate_type,
248
+ Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
249
+
250
+ if as_is_subscreenshot_region.empty? || (throw_if_clipped && !as_is_subscreenshot_region.size == region.size)
251
+ raise Applitools::OutOfBoundsException.new "Region #{region} (#{coordinate_type}) is out" \
252
+ " of screenshot bounds [#{frame_window}]"
253
+ end
254
+
255
+ sub_screenshot_image = Applitools::Screenshot.new image.crop(as_is_subscreenshot_region.left,
256
+ as_is_subscreenshot_region.top, as_is_subscreenshot_region.width,
257
+ as_is_subscreenshot_region.height).to_datastream.to_blob
258
+
259
+ context_relative_region_location = convert_location as_is_subscreenshot_region.location,
260
+ Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is],
261
+ Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative]
262
+ result = self.class.new sub_screenshot_image, driver: driver,
263
+ entire_frame_size: Applitools::RectangleSize.new(sub_screenshot_image.width, sub_screenshot_image.height),
264
+ frame_location_in_screenshot: context_relative_region_location
265
+ logger.info 'Done!'
266
+ result
267
+ end
268
+
269
+ private
270
+
271
+ attr_accessor :position_provider, :scroll_position, :screenshot_type, :frame_location_in_screenshot,
272
+ :frame_window, :force_offset
273
+ end
274
+ end