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.
@@ -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
- [match_level_value, value == Applitools::MatchLevel::EXACT ? convert_exact_options(exact_options) : nil]
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
- Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative],
11
- Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
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
- Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative],
391
- Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is]
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
- @browser_info = JSON.parse(@renderer.to_json, object_class: OpenStruct)
26
- results = Applitools::Utils.deep_stringify_keys(init_results[:result] ? init_results[:result] : init_results)
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 which enables Eyes
18
- # trigger recording and frame handling
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
- if (config.viewport_size.nil? || config.viewport_size&.empty?) && options[:viewport_size]
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
- target['target'] = { elementId: target['target'].ref } if target['target'].is_a?(::Selenium::WebDriver::Element)
17
- target['target']['x'] = target['target'].delete('left') if target['target']['left']
18
- target['target']['y'] = target['target'].delete('top') if target['target']['top']
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) ? driver.universal_driver_config : image_target
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) ? driver.universal_driver_config : { image: patterns_array.delete('image') }
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]} : driver.universal_driver_config
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|
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Applitools
4
4
  module EyesCore
5
- VERSION = '6.6.1'.freeze
5
+ VERSION = '6.9.6'.freeze
6
6
  end
7
7
 
8
8
  VERSION = Applitools::EyesCore::VERSION
@@ -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
- from_eyes.each {|m| copy_from(m, original_eyes) }
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.1
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-04-03 00:00:00.000000000 Z
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.35.1
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.35.1
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
- - Applitools
360
+ - Proprietary
373
361
  metadata:
374
362
  yard.run: yri
375
363
  post_install_message: