eyes_core 6.6.1 → 6.9.6
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +591 -0
- data/LICENSE +26 -0
- data/README.md +402 -0
- data/eyes_core.gemspec +4 -3
- data/lib/applitools/core/app_output_with_screenshot.rb +2 -3
- data/lib/applitools/core/debug_screenshot_provider.rb +3 -1
- data/lib/applitools/core/dynamic_region.rb +34 -4
- data/lib/applitools/core/eyes_base.rb +5 -4
- data/lib/applitools/core/eyes_base_configuration.rb +26 -5
- data/lib/applitools/core/eyes_screenshot.rb +7 -55
- data/lib/applitools/core/image_match_settings.rb +10 -8
- data/lib/applitools/core/match_level_setter.rb +7 -6
- data/lib/applitools/core/match_window_data.rb +6 -4
- data/lib/applitools/core/padding_bounds.rb +13 -1
- data/lib/applitools/core/test_results.rb +75 -2
- data/lib/applitools/core/universal_eyes_open.rb +15 -4
- data/lib/applitools/core/universal_new_api.rb +24 -8
- data/lib/applitools/eyes_core/version.rb +1 -1
- data/lib/applitools/universal_sdk/universal_client.rb +3 -1
- data/lib/applitools/universal_sdk/universal_eyes_config.rb +17 -1
- metadata +7 -19
@@ -5,17 +5,18 @@ module Applitools::MatchLevelSetter
|
|
5
5
|
raise Applitools::EyesError unless
|
6
6
|
Applitools::MATCH_LEVEL.keys.include?(value) | Applitools::MatchLevel.enum_values.include?(value)
|
7
7
|
|
8
|
-
if value != :exact && value != Applitools::MatchLevel::EXACT && (exact_options && !exact_options.empty?)
|
9
|
-
raise Applitools::EyesError.new(
|
10
|
-
'Exact options are accepted only for EXACT match level'
|
11
|
-
)
|
12
|
-
end
|
13
8
|
match_level_value = if Applitools::MatchLevel.enum_values.include?(value)
|
14
9
|
value
|
15
10
|
else
|
16
11
|
Applitools::MATCH_LEVEL[value]
|
17
12
|
end
|
18
|
-
|
13
|
+
if match_level_value != Applitools::MatchLevel::EXACT && (exact_options && !exact_options.empty?)
|
14
|
+
raise Applitools::EyesError.new(
|
15
|
+
'Exact options are accepted only for EXACT match level'
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
[match_level_value, match_level_value == Applitools::MatchLevel::EXACT ? convert_exact_options(exact_options) : nil]
|
19
20
|
end
|
20
21
|
|
21
22
|
private
|
@@ -7,8 +7,9 @@ module Applitools
|
|
7
7
|
return region.with_padding.to_hash if region.respond_to?(:converted?) && region.converted?
|
8
8
|
screenshot.convert_region_location(
|
9
9
|
region.with_padding,
|
10
|
-
|
11
|
-
|
10
|
+
# Use constants directly since EyesScreenshot is removed
|
11
|
+
:context_relative,
|
12
|
+
:screenshot_as_is
|
12
13
|
).to_hash
|
13
14
|
end
|
14
15
|
|
@@ -387,8 +388,9 @@ module Applitools
|
|
387
388
|
self.floating_regions = @floating_regions.map do |r|
|
388
389
|
updated_region = app_output.screenshot.convert_region_location(
|
389
390
|
r,
|
390
|
-
|
391
|
-
|
391
|
+
# Use constants directly since EyesScreenshot is removed
|
392
|
+
:context_relative,
|
393
|
+
:screenshot_as_is
|
392
394
|
)
|
393
395
|
|
394
396
|
Applitools::FloatingRegion.new(
|
@@ -4,7 +4,15 @@ require_relative 'argument_guard'
|
|
4
4
|
module Applitools
|
5
5
|
class PaddingBounds
|
6
6
|
attr_accessor :padding_left, :padding_top, :padding_right, :padding_bottom
|
7
|
-
def initialize(padding_left, padding_top, padding_right, padding_bottom)
|
7
|
+
def initialize(padding_left = nil, padding_top = nil, padding_right = nil, padding_bottom = nil, **kwargs)
|
8
|
+
# Support both positional and keyword arguments
|
9
|
+
if padding_left.nil? && !kwargs.empty?
|
10
|
+
padding_left = kwargs[:left] || 0
|
11
|
+
padding_top = kwargs[:top] || 0
|
12
|
+
padding_right = kwargs[:right] || 0
|
13
|
+
padding_bottom = kwargs[:bottom] || 0
|
14
|
+
end
|
15
|
+
|
8
16
|
Applitools::ArgumentGuard.is_a?(padding_left, 'padding_left', Integer)
|
9
17
|
Applitools::ArgumentGuard.is_a?(padding_top, 'padding_top', Integer)
|
10
18
|
Applitools::ArgumentGuard.is_a?(padding_right, 'padding_right', Integer)
|
@@ -33,5 +41,9 @@ module Applitools
|
|
33
41
|
}
|
34
42
|
end
|
35
43
|
|
44
|
+
def zero?
|
45
|
+
padding_left == 0 && padding_top == 0 && padding_right == 0 && padding_bottom == 0
|
46
|
+
end
|
47
|
+
|
36
48
|
end
|
37
49
|
end
|
@@ -3,6 +3,70 @@
|
|
3
3
|
require 'yaml'
|
4
4
|
|
5
5
|
module Applitools
|
6
|
+
# First, extend OpenStruct with a custom method for case-insensitive hash access
|
7
|
+
class FlexibleOpenStruct < OpenStruct
|
8
|
+
def [](key)
|
9
|
+
# Convert the key to string in case it's a symbol or number
|
10
|
+
key_str = key.to_s
|
11
|
+
|
12
|
+
# Direct access first (most efficient)
|
13
|
+
return super(key) if respond_to?(key)
|
14
|
+
|
15
|
+
# If the key contains uppercase letters, try snake_case version
|
16
|
+
if key_str =~ /[A-Z]/
|
17
|
+
snake_case_key = key_str.gsub(/([A-Z])/, '_\1').downcase.gsub(/^_/, '')
|
18
|
+
return send(snake_case_key) if respond_to?(snake_case_key)
|
19
|
+
else
|
20
|
+
# If the key is snake_case, try camelCase version
|
21
|
+
camel_case_key = key_str.gsub(/_([a-z])/) { $1.upcase }
|
22
|
+
return send(camel_case_key) if respond_to?(camel_case_key)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Fall back to nil if no matching attribute is found
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
# Also handle nested hashes by recursively converting them to FlexibleOpenStruct
|
30
|
+
def method_missing(name, *args)
|
31
|
+
value = super
|
32
|
+
|
33
|
+
if value.is_a?(Hash)
|
34
|
+
send("#{name}=", hash_to_flexible_open_struct(value))
|
35
|
+
value = send(name)
|
36
|
+
elsif value.is_a?(Array)
|
37
|
+
send("#{name}=", array_to_flexible_open_struct(value))
|
38
|
+
value = send(name)
|
39
|
+
end
|
40
|
+
|
41
|
+
value
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def hash_to_flexible_open_struct(hash)
|
47
|
+
result = FlexibleOpenStruct.new
|
48
|
+
hash.each do |k, v|
|
49
|
+
result[k] = process_value(v)
|
50
|
+
end
|
51
|
+
result
|
52
|
+
end
|
53
|
+
|
54
|
+
def array_to_flexible_open_struct(array)
|
55
|
+
array.map { |item| process_value(item) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def process_value(value)
|
59
|
+
case value
|
60
|
+
when Hash
|
61
|
+
hash_to_flexible_open_struct(value)
|
62
|
+
when Array
|
63
|
+
array_to_flexible_open_struct(value)
|
64
|
+
else
|
65
|
+
value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
6
70
|
class TestResults
|
7
71
|
class AccessibilityStatus
|
8
72
|
attr_accessor :status, :level, :version
|
@@ -19,11 +83,16 @@ module Applitools
|
|
19
83
|
attr_accessor :is_new, :url, :screenshot
|
20
84
|
attr_reader :status, :steps, :matches, :mismatches, :missing, :original_results, :browser_info, :renderer
|
21
85
|
|
86
|
+
attr_reader :results
|
87
|
+
|
22
88
|
def initialize(init_results = {})
|
23
89
|
environment = init_results[:environment] || {}
|
24
90
|
@renderer = Applitools::Utils.deep_stringify_keys(Applitools::Utils.underscore_hash_keys(environment[:requested]))
|
25
|
-
|
26
|
-
|
91
|
+
|
92
|
+
# Use allow querying as both with camel and snake cases
|
93
|
+
@browser_info = JSON.parse(@renderer.to_json, object_class: FlexibleOpenStruct)
|
94
|
+
|
95
|
+
@results = Applitools::Utils.deep_stringify_keys(init_results[:result] ? init_results[:result] : init_results)
|
27
96
|
@original_results = results
|
28
97
|
@steps = results.fetch('steps', 0)
|
29
98
|
@matches = results.fetch('matches', 0)
|
@@ -34,6 +103,10 @@ module Applitools
|
|
34
103
|
@url = results.fetch('url', nil)
|
35
104
|
end
|
36
105
|
|
106
|
+
def [](index)
|
107
|
+
@results[index]
|
108
|
+
end
|
109
|
+
|
37
110
|
def test_results
|
38
111
|
self
|
39
112
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Applitools
|
4
4
|
module UniversalEyesOpen
|
5
5
|
|
6
|
-
# Starts a test
|
6
|
+
# Starts a test with Universal SDK
|
7
7
|
#
|
8
8
|
# @param options [Hash] options
|
9
9
|
# @option options :driver The driver that controls the browser hosting the application
|
@@ -14,8 +14,8 @@ module Applitools
|
|
14
14
|
# (i.e., the visible part of the document's body) or +nil+ to use the current window's viewport.
|
15
15
|
# @option options :session_type The type of the test (e.g., standard test / visual performance test).
|
16
16
|
# Default value is 'SEQUENTAL'
|
17
|
-
# @return [Applitools::Selenium::Driver] A wrapped web driver
|
18
|
-
#
|
17
|
+
# @return [Applitools::Selenium::Driver] A wrapped web driver for internal SDK use
|
18
|
+
# (Note: open() method will return the original, unwrapped driver)
|
19
19
|
def universal_open(options = {})
|
20
20
|
original_driver = options.delete(:driver)
|
21
21
|
if self.class.name != 'Applitools::Images::Eyes'
|
@@ -27,10 +27,18 @@ module Applitools
|
|
27
27
|
end
|
28
28
|
|
29
29
|
self.driver = Applitools::Selenium::SeleniumEyes.eyes_driver(original_driver, self)
|
30
|
+
|
31
|
+
# Call driver-specific settings if available
|
32
|
+
if respond_to?(:perform_driver_specific_settings, true)
|
33
|
+
perform_driver_specific_settings(original_driver)
|
34
|
+
end
|
30
35
|
end
|
31
36
|
|
32
37
|
update_config_from_options(options)
|
33
38
|
universal_driver_config = driver.universal_driver_config if self.class.name != 'Applitools::Images::Eyes'
|
39
|
+
|
40
|
+
# Ensure we have a runner (default to ClassicRunner if not provided)
|
41
|
+
self.runner ||= Applitools::ClassicRunner.new
|
34
42
|
universal_eyes_manager = runner.get_universal_eyes_manager(self)
|
35
43
|
|
36
44
|
universal_eyes_config = Applitools::UniversalEyesConfig.new
|
@@ -87,7 +95,10 @@ module Applitools
|
|
87
95
|
|
88
96
|
self.app_name = options[:app_name] if options[:app_name]
|
89
97
|
self.test_name = options[:test_name] if options[:test_name]
|
90
|
-
|
98
|
+
|
99
|
+
if (config.respond_to?(:viewport_size, true) &&
|
100
|
+
(config.send(:viewport_size).nil? || config.send(:viewport_size)&.empty?)) &&
|
101
|
+
options[:viewport_size]
|
91
102
|
self.viewport_size = Applitools::RectangleSize.from_any_argument options[:viewport_size]
|
92
103
|
end
|
93
104
|
self.session_type = options[:session_type] if options[:session_type]
|
@@ -12,15 +12,31 @@ module Applitools
|
|
12
12
|
def extract_text(*args)
|
13
13
|
image_target = args[0].is_a?(Hash) ? args[0] : nil
|
14
14
|
targets_array = args[0].is_a?(Hash) ? args[1].to_a : args[0]
|
15
|
-
targets_array.map do |target|
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
targets_array = targets_array.map do |target|
|
16
|
+
# Handle element references
|
17
|
+
if target['target'].is_a?(::Selenium::WebDriver::Element)
|
18
|
+
ref = target['target'].ref
|
19
|
+
# Handle different formats of element refs
|
20
|
+
ref = ref[1] if ref.is_a?(Array) && ref[0] == :element
|
21
|
+
target['target'] = { elementId: ref }
|
22
|
+
elsif target['target'].is_a?(String)
|
23
|
+
# It's a CSS selector
|
24
|
+
target['target'] = target['target']
|
25
|
+
elsif target['target'].is_a?(Hash)
|
26
|
+
# Handle coordinate-based regions
|
27
|
+
if target['target']['left']
|
28
|
+
target['target']['x'] = target['target'].delete('left')
|
29
|
+
end
|
30
|
+
if target['target']['top']
|
31
|
+
target['target']['y'] = target['target'].delete('top')
|
32
|
+
end
|
33
|
+
end
|
19
34
|
target[:region] = target.delete('target')
|
20
35
|
target
|
21
36
|
end
|
22
|
-
driver_target = respond_to?(:driver) ?
|
23
|
-
universal_eyes.extract_text(targets_array, driver_target)
|
37
|
+
driver_target = respond_to?(:driver) ? Applitools::Selenium.universal_driver_config(driver) : image_target
|
38
|
+
result = universal_eyes.extract_text(targets_array, driver_target)
|
39
|
+
result
|
24
40
|
end
|
25
41
|
|
26
42
|
|
@@ -31,7 +47,7 @@ module Applitools
|
|
31
47
|
# language?: string
|
32
48
|
# }
|
33
49
|
def extract_text_regions(patterns_array)
|
34
|
-
driver_target = respond_to?(:driver) ?
|
50
|
+
driver_target = respond_to?(:driver) ? Applitools::Selenium.universal_driver_config(driver) : { image: patterns_array.delete('image') }
|
35
51
|
results = universal_eyes.extract_text_regions(patterns_array, driver_target)
|
36
52
|
Applitools::Utils.deep_stringify_keys(results)
|
37
53
|
end
|
@@ -42,7 +58,7 @@ module Applitools
|
|
42
58
|
locatorNames: locate_settings[:locator_names],
|
43
59
|
firstOnly: !!locate_settings[:first_only]
|
44
60
|
}
|
45
|
-
driver_target = locate_settings.has_key?(:image) ? {image: locate_settings[:image]} :
|
61
|
+
driver_target = locate_settings.has_key?(:image) ? {image: locate_settings[:image]} : Applitools::Selenium.universal_driver_config(driver)
|
46
62
|
results = universal_eyes.locate(settings, driver_target)
|
47
63
|
|
48
64
|
old_style = results.map do |k, v|
|
@@ -255,7 +255,9 @@ module Applitools::Connectivity
|
|
255
255
|
# type ExtractTextResponsePayload = string[]
|
256
256
|
payload = { target: driver_target, settings: regions, config: commands_config }
|
257
257
|
payload.delete(:settings) if regions.empty?
|
258
|
-
command_with_result(EYES_EXTRACT_TEXT, payload)
|
258
|
+
result = command_with_result(EYES_EXTRACT_TEXT, payload)
|
259
|
+
# Ensure we return the result array
|
260
|
+
result.is_a?(Hash) && result['result'] ? result['result'] : result
|
259
261
|
end
|
260
262
|
|
261
263
|
def eyes_close(eyes)
|
@@ -186,7 +186,23 @@ module Applitools
|
|
186
186
|
|
187
187
|
def from_original_sdk(original_eyes)
|
188
188
|
from_eyes = original_eyes.class.name != 'Applitools::Images::Eyes' ? FROM_ORIGINAL_EYES : from_eyes_images
|
189
|
-
|
189
|
+
|
190
|
+
# Use a filtered list to avoid accessing private viewport_size method
|
191
|
+
# We will handle viewport_size specially
|
192
|
+
filtered_eyes = from_eyes.reject { |m| m == :viewport_size }
|
193
|
+
|
194
|
+
# Copy all properties except viewport_size
|
195
|
+
filtered_eyes.each { |m| copy_from(m, original_eyes) }
|
196
|
+
|
197
|
+
# Handle viewport_size specially to avoid private method access warning
|
198
|
+
# Access the config's viewport_size directly if available
|
199
|
+
if original_eyes.respond_to?(:config) && original_eyes.config.respond_to?(:viewport_size)
|
200
|
+
self.viewport_size = original_eyes.config.viewport_size
|
201
|
+
elsif original_eyes.respond_to?(:viewport_size)
|
202
|
+
# Fallback to original_eyes.viewport_size if necessary
|
203
|
+
self.viewport_size = original_eyes.viewport_size
|
204
|
+
end
|
205
|
+
|
190
206
|
self.agent_id = original_eyes.base_agent_id if original_eyes.respond_to?(:base_agent_id)
|
191
207
|
self.agent_id = original_eyes.full_agent_id if original_eyes.respond_to?(:full_agent_id)
|
192
208
|
# self.display_name = original_eyes.app_name
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eyes_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.6
|
4
|
+
version: 6.9.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Applitools Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-10-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -114,14 +114,14 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - '='
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 4.
|
117
|
+
version: 4.49.0
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - '='
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 4.
|
124
|
+
version: 4.49.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: bundler
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,20 +178,6 @@ dependencies:
|
|
178
178
|
- - "<="
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: 0.46.0
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: webdrivers
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - "~>"
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '5.0'
|
188
|
-
type: :development
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - "~>"
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: '5.0'
|
195
181
|
- !ruby/object:Gem::Dependency
|
196
182
|
name: pry
|
197
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -285,6 +271,8 @@ extensions: []
|
|
285
271
|
extra_rdoc_files: []
|
286
272
|
files:
|
287
273
|
- CHANGELOG.md
|
274
|
+
- LICENSE
|
275
|
+
- README.md
|
288
276
|
- Rakefile
|
289
277
|
- eyes_core.gemspec
|
290
278
|
- lib/applitools/connectivity/proxy.rb
|
@@ -369,7 +357,7 @@ files:
|
|
369
357
|
- lib/require_utils.rb
|
370
358
|
homepage: https://www.applitools.com
|
371
359
|
licenses:
|
372
|
-
-
|
360
|
+
- Proprietary
|
373
361
|
metadata:
|
374
362
|
yard.run: yri
|
375
363
|
post_install_message:
|