eyes_core 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/ext/eyes_core/extconf.rb +3 -0
  3. data/ext/eyes_core/eyes_core.c +80 -0
  4. data/ext/eyes_core/eyes_core.h +24 -0
  5. data/lib/applitools/capybara.rb +8 -0
  6. data/lib/applitools/chunky_png/resampling.rb +148 -0
  7. data/lib/applitools/chunky_png_patch.rb +8 -0
  8. data/lib/applitools/connectivity/proxy.rb +3 -0
  9. data/lib/applitools/connectivity/server_connector.rb +118 -0
  10. data/lib/applitools/core/app_environment.rb +29 -0
  11. data/lib/applitools/core/app_output.rb +17 -0
  12. data/lib/applitools/core/app_output_with_screenshot.rb +22 -0
  13. data/lib/applitools/core/argument_guard.rb +35 -0
  14. data/lib/applitools/core/batch_info.rb +18 -0
  15. data/lib/applitools/core/eyes_base.rb +463 -0
  16. data/lib/applitools/core/eyes_screenshot.rb +35 -0
  17. data/lib/applitools/core/fixed_cut_provider.rb +61 -0
  18. data/lib/applitools/core/fixed_scale_provider.rb +14 -0
  19. data/lib/applitools/core/helpers.rb +18 -0
  20. data/lib/applitools/core/location.rb +84 -0
  21. data/lib/applitools/core/match_result.rb +16 -0
  22. data/lib/applitools/core/match_results.rb +9 -0
  23. data/lib/applitools/core/match_window_data.rb +34 -0
  24. data/lib/applitools/core/match_window_task.rb +86 -0
  25. data/lib/applitools/core/mouse_trigger.rb +39 -0
  26. data/lib/applitools/core/rectangle_size.rb +46 -0
  27. data/lib/applitools/core/region.rb +180 -0
  28. data/lib/applitools/core/screenshot.rb +49 -0
  29. data/lib/applitools/core/session.rb +15 -0
  30. data/lib/applitools/core/session_start_info.rb +33 -0
  31. data/lib/applitools/core/test_results.rb +55 -0
  32. data/lib/applitools/core/text_trigger.rb +24 -0
  33. data/lib/applitools/core/trigger.rb +8 -0
  34. data/lib/applitools/extensions.rb +18 -0
  35. data/lib/applitools/eyes_logger.rb +45 -0
  36. data/lib/applitools/images/eyes.rb +204 -0
  37. data/lib/applitools/images/eyes_images_screenshot.rb +102 -0
  38. data/lib/applitools/method_tracer.rb +23 -0
  39. data/lib/applitools/sauce.rb +2 -0
  40. data/lib/applitools/utils/eyes_selenium_utils.rb +348 -0
  41. data/lib/applitools/utils/image_delta_compressor.rb +146 -0
  42. data/lib/applitools/utils/image_utils.rb +146 -0
  43. data/lib/applitools/utils/utils.rb +68 -0
  44. data/lib/applitools/version.rb +3 -0
  45. data/lib/eyes_core.rb +70 -0
  46. metadata +273 -0
@@ -0,0 +1,180 @@
1
+ module Applitools
2
+ class Region
3
+ attr_accessor :left, :top, :width, :height
4
+ alias x left
5
+ alias y top
6
+
7
+ class << self
8
+ def from_location_size(location, size)
9
+ new location.x, location.y, size.width, size.height
10
+ end
11
+ end
12
+
13
+ def initialize(left, top, width, height)
14
+ @left = left.round
15
+ @top = top.round
16
+ @width = width.round
17
+ @height = height.round
18
+ end
19
+
20
+ EMPTY = Region.new(0, 0, 0, 0)
21
+
22
+ def make_empty
23
+ @left = EMPTY.left
24
+ @top = EMPTY.top
25
+ @width = EMPTY.width
26
+ @height = EMPTY.height
27
+ end
28
+
29
+ def empty?
30
+ @left == EMPTY.left && @top == EMPTY.top && @width == EMPTY.width && @height == EMPTY.height
31
+ end
32
+
33
+ def size
34
+ Applitools::RectangleSize.new width, height
35
+ end
36
+
37
+ def location
38
+ Location.new left, top
39
+ end
40
+
41
+ def location=(other_location)
42
+ self.left = other_location.left
43
+ self.top = other_location.top
44
+ end
45
+
46
+ def right
47
+ left + width
48
+ end
49
+
50
+ def bottom
51
+ top + height
52
+ end
53
+
54
+ def intersecting?(other)
55
+ ((left <= other.left && other.left <= right) || (other.left <= left && left <= other.right)) &&
56
+ ((top <= other.top && other.top <= bottom) || (other.top <= top && top <= other.bottom))
57
+ end
58
+
59
+ def intersect(other)
60
+ unless intersecting?(other)
61
+ make_empty
62
+
63
+ return
64
+ end
65
+
66
+ i_left = left >= other.left ? left : other.left
67
+ i_right = right <= other.right ? right : other.right
68
+ i_top = top >= other.top ? top : other.top
69
+ i_bottom = bottom <= other.bottom ? bottom : other.bottom
70
+
71
+ @left = i_left
72
+ @top = i_top
73
+ @width = i_right - i_left
74
+ @height = i_bottom - i_top
75
+ end
76
+
77
+ def contains?(other_left, other_top)
78
+ other_left >= left && other_left <= right && other_top >= top && other_top <= bottom
79
+ end
80
+
81
+ def middle_offset
82
+ mid_x = width / 2
83
+ mid_y = height / 2
84
+ Applitools::Location.for(mid_x.round, mid_y.round)
85
+ end
86
+
87
+ def sub_regions(subregion_size, is_fixed_size = false)
88
+ return self.class.sub_regions_with_fixed_size self, subregion_size if is_fixed_size
89
+ self.class.sub_regions_with_varying_size self, subregion_size
90
+ end
91
+
92
+ def to_hash
93
+ {
94
+ left: left,
95
+ top: top,
96
+ height: height,
97
+ width: width
98
+ }
99
+ end
100
+
101
+ def to_s
102
+ "(#{left}, #{top}), #{width} x #{height}"
103
+ end
104
+
105
+ def size_equals?(region)
106
+ width == region.width && height == region.height
107
+ end
108
+
109
+ class << self
110
+ def sub_regions_with_fixed_size(container_region, sub_region)
111
+ Applitools::ArgumentGuard.not_nil container_region, 'container_region'
112
+ Applitools::ArgumentGuard.not_nil sub_region, 'sub_region'
113
+
114
+ Applitools::ArgumentGuard.greater_than_zero(sub_region.width, 'sub_region.width')
115
+ Applitools::ArgumentGuard.greater_than_zero(sub_region.height, 'sub_region.height')
116
+
117
+ sub_region_width = sub_region.width
118
+ sub_region_height = sub_region.height
119
+
120
+ # Normalizing.
121
+ sub_region_width = container_region.width if sub_region_width > container_region.width
122
+ sub_region_height = container_region.height if sub_region_height > container_region.height
123
+
124
+ if sub_region_width == container_region.width && sub_region_height == container_region.height
125
+ return Enumerator(1) do |y|
126
+ y << sub_region
127
+ end
128
+ end
129
+
130
+ current_top = container_region.top
131
+ bottom = container_region.top + container_region.height - 1
132
+ right = container_region.left + container_region.width - 1
133
+ Enumerator.new do |y|
134
+ while current_top <= bottom
135
+ current_top = (bottom - sub_region_height) + 1 if current_top + sub_region_height > bottom
136
+ current_left = container_region.left
137
+ while current_left <= right
138
+ current_left = (rught - sub_region_width) + 1 if current_left + sub_region_width > right
139
+ y << new(current_left, current_top, sub_region_width, sub_region_height)
140
+ current_left += sub_region_width
141
+ end
142
+ current_top += sub_region_height
143
+ end
144
+ end
145
+ end
146
+
147
+ def sub_regions_with_varying_size(container_region, sub_region)
148
+ Applitools::ArgumentGuard.not_nil container_region, 'container_region'
149
+ Applitools::ArgumentGuard.not_nil sub_region, 'sub_region'
150
+
151
+ Applitools::ArgumentGuard.greater_than_zero(sub_region.width, 'sub_region.width')
152
+ Applitools::ArgumentGuard.greater_than_zero(sub_region.height, 'sub_region.height')
153
+
154
+ current_top = container_region.top
155
+ bottom = container_region.top + container_region.height
156
+ right = container_region.left + container_region.width
157
+
158
+ Enumerator.new do |y|
159
+ while current_top < bottom
160
+ current_bottom = current_top + sub_region.height
161
+ current_bottom = bottom if current_bottom > bottom
162
+ current_left = container_region.left
163
+ while current_left < right
164
+ current_right = current_left + sub_region.width
165
+ current_right = right if current_right > right
166
+
167
+ current_height = current_bottom - current_top
168
+ current_width = current_right - current_left
169
+
170
+ y << new(current_left, current_top, current_width, current_height)
171
+
172
+ current_left += sub_region.width
173
+ end
174
+ current_top += sub_region.height
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,49 @@
1
+ module Applitools
2
+ class Screenshot < Delegator
3
+ extend Forwardable
4
+ def_delegators :header, :width, :height
5
+
6
+ class << self
7
+ def from_region(region)
8
+ new ChunkyPNG::Image.new(region.width, region.height).to_blob
9
+ end
10
+ end
11
+
12
+ def initialize(image)
13
+ @datastream = ::ChunkyPNG::Datastream.from_string image
14
+ end
15
+
16
+ def to_blob
17
+ @datastream.to_blob
18
+ end
19
+
20
+ def __getobj__
21
+ restore
22
+ end
23
+
24
+ def header
25
+ @datastream.header_chunk
26
+ end
27
+
28
+ def __setobj__(obj)
29
+ @datastream = obj.to_datastream
30
+ self
31
+ end
32
+
33
+ def method_missing(method, *args, &block)
34
+ if method =~ /^.+!$/
35
+ __setobj__ super
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ def respond_to_missing?(method_name, include_private = false)
42
+ super
43
+ end
44
+
45
+ def restore
46
+ ::ChunkyPNG::Image.from_datastream @datastream
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ module Applitools
2
+ class Session
3
+ attr_reader :id, :url
4
+
5
+ def initialize(session_id, session_url, new_session)
6
+ @id = session_id
7
+ @url = session_url
8
+ @new_session = new_session
9
+ end
10
+
11
+ def new_session?
12
+ @new_session
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ module Applitools
2
+ class SessionStartInfo
3
+ attr_accessor :app_id_or_name, :scenario_id_or_name
4
+
5
+ def initialize(options = {})
6
+ @agent_id = options[:agent_id]
7
+ @app_id_or_name = options[:app_id_or_name]
8
+ @ver_id = options[:ver_id]
9
+ @scenario_id_or_name = options[:scenario_id_or_name]
10
+ @batch_info = options[:batch_info]
11
+ @env_name = options[:env_name]
12
+ @environment = options[:environment]
13
+ @match_level = options[:match_level]
14
+ @branch_name = options[:branch_name]
15
+ @parent_branch_name = options[:parent_branch_name]
16
+ end
17
+
18
+ def to_hash
19
+ {
20
+ agent_id: @agent_id,
21
+ app_id_or_name: @app_id_or_name,
22
+ ver_id: @ver_id,
23
+ scenario_id_or_name: @scenario_id_or_name,
24
+ batch_info: @batch_info.to_hash,
25
+ env_name: @env_name,
26
+ environment: @environment.to_hash,
27
+ match_level: @match_level,
28
+ branch_name: @branch_name,
29
+ parent_branch_name: @parent_branch_name
30
+ }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,55 @@
1
+ require 'yaml'
2
+
3
+ module Applitools
4
+ class TestResults
5
+ attr_accessor :is_new, :url
6
+ attr_reader :steps, :matches, :mismatches, :missing
7
+
8
+ def initialize(results = {})
9
+ @steps = results.fetch('steps', 0)
10
+ @matches = results.fetch('matches', 0)
11
+ @mismatches = results.fetch('mismatches', 0)
12
+ @missing = results.fetch('missing', 0)
13
+ @is_new = nil
14
+ @url = nil
15
+ @original_results = results
16
+ end
17
+
18
+ def passed?
19
+ return !(mismatches > 0) && !(missing > 0) unless new?
20
+ false
21
+ end
22
+
23
+ def failed?
24
+ return (mismatches > 0) || (missing > 0) unless new?
25
+ false
26
+ end
27
+
28
+ def new?
29
+ is_new
30
+ end
31
+
32
+ def ==(other)
33
+ if other.is_a? self.class
34
+ result = true
35
+ %i(is_new url steps matches mismatches missing).each do |field|
36
+ result &&= send(field) == other.send(field)
37
+ end
38
+ return result if result
39
+ end
40
+ false
41
+ end
42
+
43
+ alias is_passed passed?
44
+
45
+ def to_s(advanced = false)
46
+ is_new_str = ''
47
+ is_new_str = is_new ? 'New test' : 'Existing test' unless is_new.nil?
48
+
49
+ return @original_results.to_yaml if advanced
50
+
51
+ "#{is_new_str} [ steps: #{steps}, matches: #{matches}, mismatches: #{mismatches}, missing: #{missing} ], " \
52
+ "URL: #{url}"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ require 'applitools/core/trigger'
2
+ module Applitools
3
+ class TextTrigger < Trigger
4
+ TRIGGER_TYPE = :Text
5
+ attr_reader :text, :control
6
+
7
+ def initialize(text, control)
8
+ @text = text
9
+ @control = control
10
+ end
11
+
12
+ def to_hash
13
+ {
14
+ triggerType: trigger_type,
15
+ text: text,
16
+ control: control.to_hash
17
+ }
18
+ end
19
+
20
+ def to_s
21
+ "Text [#{@control}] #{@text}"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ module Applitools
2
+ class Trigger
3
+ TRIGGER_TYPE = :unknown
4
+ def trigger_type
5
+ self.class::TRIGGER_TYPE
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,18 @@
1
+ # @!visibility private
2
+ class Module
3
+ def alias_attribute(new_name, old_name)
4
+ module_eval <<-STR, __FILE__, __LINE__ + 1
5
+ def #{new_name}
6
+ self.#{old_name}
7
+ end
8
+
9
+ def #{new_name}?
10
+ self.#{old_name}?
11
+ end
12
+
13
+ def #{new_name}=(v)
14
+ self.#{old_name}
15
+ end
16
+ STR
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ require 'logger'
2
+
3
+ module Applitools::EyesLogger
4
+ class NullLogger < Logger
5
+ def initialize(*_args) end
6
+
7
+ def add(*_args, &_block) end
8
+ end
9
+
10
+ extend Forwardable
11
+ extend self
12
+
13
+ MANDATORY_METHODS = [:debug, :info, :close].freeze
14
+ OPTIONAL_METHODS = [:warn, :error, :fatal].freeze
15
+
16
+ def_delegators :@log_handler, *MANDATORY_METHODS
17
+
18
+ @log_handler = NullLogger.new
19
+
20
+ def log_handler=(log_handler)
21
+ raise Applitools::EyesError.new('log_handler must implement Logger!') unless valid?(log_handler)
22
+
23
+ @log_handler = log_handler
24
+ end
25
+
26
+ def log_handler
27
+ @log_handler
28
+ end
29
+
30
+ def logger
31
+ self
32
+ end
33
+
34
+ OPTIONAL_METHODS.each do |method|
35
+ define_singleton_method(method) do |msg|
36
+ @log_handler.respond_to?(method) ? @log_handler.send(method, msg) : @log_handler.info(msg)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def valid?(log_handler)
43
+ MANDATORY_METHODS.all? { |method| log_handler.respond_to?(method) }
44
+ end
45
+ end
@@ -0,0 +1,204 @@
1
+ require 'applitools/core/eyes_base'
2
+
3
+ # Eyes Images SDK
4
+ #
5
+ module Applitools::Images
6
+ # A class to perform visual validation on images. Allows to handle user data like +Mouse trigger+ and +Text trigger+
7
+ # @example
8
+ # eyes = Applitools::Images::Eyes.new
9
+ # eyes.open(app_name: 'App name', test_name: 'Test name')
10
+ # eyes.check_image(eyes.check_image(image_path: '~/test/some_screenshot.png', tag: 'My Test')
11
+ # eyes.close(true)
12
+ class Eyes < Applitools::EyesBase
13
+ # @!visibility private
14
+ attr_accessor :base_agent_id, :screenshot, :inferred_environment, :title
15
+
16
+ # @!visibility private
17
+ def capture_screenshot
18
+ @screenshot
19
+ end
20
+
21
+ # Creates a new eyes object
22
+ # @example
23
+ # eyes = Applitools::Images::Eyes.new
24
+ # @param server_url The Eyes Server URL
25
+ def initialize(server_url = Applitools::Connectivity::ServerConnector::DEFAULT_SERVER_URL)
26
+ super
27
+ self.base_agent_id = 'eyes.images.ruby/1.0.0'
28
+ end
29
+
30
+ # Starts a test.
31
+ # @param [Hash] options
32
+ # @option options [String] :app_name the name of the application under trest. Required.
33
+ # @option options [String] :test_name the test name. Required
34
+ # @option options [String | Hash] :viewport_size viewport size for the baseline, may be passed as a
35
+ # string (<tt>'800x600'</tt>) or as a hash (<tt>{width: 800, height: 600}</tt>).
36
+ # If ommited, the viewport size will be grabbed from the actual image size
37
+ # @example
38
+ # eyes.open app_name: 'my app', test_name: 'my test'
39
+ def open(options = {})
40
+ Applitools::ArgumentGuard.hash options, 'open(options)', [:app_name, :test_name]
41
+ options[:viewport_size] = Applitools::RectangleSize.from_any_argument options[:viewport_size]
42
+ open_base options
43
+ end
44
+
45
+ # Opens eyes using passed options, yields the block and then closes eyes session.
46
+ # Use Applitools::Images::Eyes method inside the block to perform the test. If the block throws an exception,
47
+ # eyes session will be closed correctly.
48
+ # @example
49
+ # eyes.test(app_name: 'Eyes.Java', test_name: 'home2') do
50
+ # eyes.check_image(image_path: './images/viber-home.png')
51
+ # eyes.check_image(image_path: './images/viber-bada.png')
52
+ # end
53
+ def test(options = {}, &_block)
54
+ open(options)
55
+ yield
56
+ close
57
+ ensure
58
+ abort_if_not_closed
59
+ end
60
+
61
+ # Matches the input image with the next expected image. Takes a hash as an argument. Returns +boolean+
62
+ # as result of matching.
63
+ # @param [Hash] options
64
+ # @option options [Applitools::Screenshot] :image
65
+ # @option options [String] :image_bytes image in PNG format. Can be obtained as ChunkyPNG::Image.to_blob()
66
+ # @option options [String] :image_path
67
+ # @option options [String] :tag An optional tag to be associated with the validation checkpoint.
68
+ # @option options [Boolean] :ignore_mismatch If set to +true+ the server should ignore a negative
69
+ # result for the visual validation. (+false+ by default)
70
+ # @example Image is a file
71
+ # eyes.check_image(image_path: '~/test/some_screenshot.png', tag: 'My Test')
72
+ # @example Image is a +Applitools::Screenshot+ instance
73
+ # eyes.check_image(image: my_image, tag: 'My Test')
74
+ # @example Image is a +String+
75
+ # eyes.check_image(image_bytes: string_represents_image, tag: 'My Test')
76
+ # @example Ignore mismatch
77
+ # eyes.check_image(image: my_image, tag: 'My Test', ignore_mismatch: true)
78
+ def check_image(options)
79
+ options = { tag: nil, ignore_mismatch: false }.merge options
80
+
81
+ if disabled?
82
+ logger.info "check_image(image, #{options[:tag]}, #{options[:ignore_mismatch]}): Ignored"
83
+ return false
84
+ end
85
+
86
+ image = get_image_from_options options
87
+
88
+ logger.info "check_image(image, #{options[:tag]}, #{options[:ignore_mismatch]})"
89
+ if image.is_a? Applitools::Screenshot
90
+ self.viewport_size = Applitools::RectangleSize.new image.width, image.height if viewport_size.nil?
91
+ self.screenshot = EyesImagesScreenshot.new image
92
+ end
93
+ self.title = options[:tag] || ''
94
+ region_provider = Object.new
95
+ region_provider.instance_eval do
96
+ define_singleton_method :region do
97
+ Applitools::Region::EMPTY
98
+ end
99
+
100
+ define_singleton_method :coordinate_type do
101
+ nil
102
+ end
103
+ end
104
+ mr = check_window_base region_provider, options[:tag], options[:ignore_mismatch],
105
+ Applitools::EyesBase::USE_DEFAULT_TIMEOUT
106
+ mr.as_expected?
107
+ end
108
+
109
+ # Performs visual validation for the current image.
110
+ # @param [Hash] options
111
+ # @option options [Applitools::Region] :region A region to validate within the image
112
+ # @option options [Applitools::Screenshot] :image Image to validate
113
+ # @option options [String] :image_bytes Image in +PNG+ format. Can be obtained as ChunkyPNG::Image.to_blob()
114
+ # @option options [String] :image_path Path to image file
115
+ # @option options [String] :tag An optional tag to be associated with the validation checkpoint.
116
+ # @option options [Boolean] :ignore_mismatch If set to +true+ the server would ignore a negative
117
+ # result for the visual validation
118
+ # @example Image is a file
119
+ # eyes.check_region(image_path: '~/test/some_screenshot.png', region: my_region, tag: 'My Test')
120
+ # @example Image is a Applitools::Screenshot instance
121
+ # eyes.check_region(image: my_image, tag: 'My Test', region: my_region)
122
+ # @example Image is a +String+
123
+ # eyes.check_region(image_bytes: string_represents_image, tag: 'My Test', region: my_region)
124
+ def check_region(options)
125
+ options = { tag: nil, ignore_mismatch: false }.merge options
126
+
127
+ if disabled?
128
+ logger.info "check_region(image, #{options[:tag]}, #{options[:ignore_mismatch]}): Ignored"
129
+ return false
130
+ end
131
+
132
+ Applitools::ArgumentGuard.not_nil options[:region], 'options[:region] can\'t be nil!'
133
+ image = get_image_from_options options
134
+
135
+ logger.info "check_region(image, #{options[:region]}, #{options[:tag]}, #{options[:ignore_mismatch]})"
136
+
137
+ if image.is_a? Applitools::Screenshot
138
+ self.viewport_size = Applitools::RectangleSize.new image.width, image.height if viewport_size.nil?
139
+ self.screenshot = EyesImagesScreenshot.new image
140
+ end
141
+ self.title = options[:tag] || ''
142
+
143
+ region_provider = Object.new
144
+ region_provider.instance_eval do
145
+ define_singleton_method :region do
146
+ options[:region]
147
+ end
148
+ define_singleton_method :coordinate_type do
149
+ Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
150
+ end
151
+ end
152
+ mr = check_window_base region_provider, options[:tag], options[:ignore_mismatch],
153
+ Applitools::EyesBase::USE_DEFAULT_TIMEOUT
154
+ mr.as_expected?
155
+ end
156
+
157
+ # Adds a mouse trigger
158
+ # @param [Symbol] action A mouse action. Can be one of +:click+, +:right_click+, +:double_click+, +:move+,
159
+ # +:down+, +:up+
160
+ # @param [Applitools::Region] control The control on which the trigger is activated
161
+ # (context relative coordinates).
162
+ # @param [Applitools::Location] cursor The cursor's position relative to the control.
163
+ def add_mouse_trigger(action, control, cursor)
164
+ add_mouse_trigger_base action, control, cursor
165
+ end
166
+
167
+ # Adds a keyboard trigger
168
+ # @param [Applitools::Region] control the control's context-relative region.
169
+ # @param text The trigger's text.
170
+ def add_text_trigger(control, text)
171
+ add_text_trigger_base control, text
172
+ end
173
+
174
+ private
175
+
176
+ def vp_size
177
+ viewport_size
178
+ end
179
+
180
+ def vp_size=(value)
181
+ Applitools::ArgumentGuard.not_nil 'value', value
182
+ @viewport_size = Applitools::RectangleSize.for value
183
+ end
184
+
185
+ alias get_viewport_size vp_size
186
+ alias set_viewport_size vp_size=
187
+
188
+ def get_image_from_options(options)
189
+ if options[:image].nil? && !options[:image].is_a?(Applitools::Screenshot)
190
+ if !options[:image_path].nil? && !options[:image_path].empty?
191
+ image = Applitools::Screenshot.new ChunkyPNG::Datastream.from_file(options[:image_path]).to_s
192
+ elsif options[:image_bytes].nil? && !options[:image_bytes].empty?
193
+ image = Applitools::Screenshot.new options[:image_bytes]
194
+ end
195
+ else
196
+ image = options[:image]
197
+ end
198
+
199
+ Applitools::ArgumentGuard.not_nil image, 'options[:image] can\'t be nil!'
200
+
201
+ image
202
+ end
203
+ end
204
+ end