eyes_core 3.0.4

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.
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