eyes_core 3.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ext/eyes_core/extconf.rb +3 -0
- data/ext/eyes_core/eyes_core.c +80 -0
- data/ext/eyes_core/eyes_core.h +24 -0
- data/lib/applitools/capybara.rb +8 -0
- data/lib/applitools/chunky_png/resampling.rb +148 -0
- data/lib/applitools/chunky_png_patch.rb +8 -0
- data/lib/applitools/connectivity/proxy.rb +3 -0
- data/lib/applitools/connectivity/server_connector.rb +118 -0
- data/lib/applitools/core/app_environment.rb +29 -0
- data/lib/applitools/core/app_output.rb +17 -0
- data/lib/applitools/core/app_output_with_screenshot.rb +22 -0
- data/lib/applitools/core/argument_guard.rb +35 -0
- data/lib/applitools/core/batch_info.rb +18 -0
- data/lib/applitools/core/eyes_base.rb +463 -0
- data/lib/applitools/core/eyes_screenshot.rb +35 -0
- data/lib/applitools/core/fixed_cut_provider.rb +61 -0
- data/lib/applitools/core/fixed_scale_provider.rb +14 -0
- data/lib/applitools/core/helpers.rb +18 -0
- data/lib/applitools/core/location.rb +84 -0
- data/lib/applitools/core/match_result.rb +16 -0
- data/lib/applitools/core/match_results.rb +9 -0
- data/lib/applitools/core/match_window_data.rb +34 -0
- data/lib/applitools/core/match_window_task.rb +86 -0
- data/lib/applitools/core/mouse_trigger.rb +39 -0
- data/lib/applitools/core/rectangle_size.rb +46 -0
- data/lib/applitools/core/region.rb +180 -0
- data/lib/applitools/core/screenshot.rb +49 -0
- data/lib/applitools/core/session.rb +15 -0
- data/lib/applitools/core/session_start_info.rb +33 -0
- data/lib/applitools/core/test_results.rb +55 -0
- data/lib/applitools/core/text_trigger.rb +24 -0
- data/lib/applitools/core/trigger.rb +8 -0
- data/lib/applitools/extensions.rb +18 -0
- data/lib/applitools/eyes_logger.rb +45 -0
- data/lib/applitools/images/eyes.rb +204 -0
- data/lib/applitools/images/eyes_images_screenshot.rb +102 -0
- data/lib/applitools/method_tracer.rb +23 -0
- data/lib/applitools/sauce.rb +2 -0
- data/lib/applitools/utils/eyes_selenium_utils.rb +348 -0
- data/lib/applitools/utils/image_delta_compressor.rb +146 -0
- data/lib/applitools/utils/image_utils.rb +146 -0
- data/lib/applitools/utils/utils.rb +68 -0
- data/lib/applitools/version.rb +3 -0
- data/lib/eyes_core.rb +70 -0
- 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,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,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
|