eyes_core 3.18.4 → 4.0.3

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/applitools/appium/eyes.rb +3 -2
  3. data/lib/applitools/appium/target.rb +218 -193
  4. data/lib/applitools/calabash/calabash_screenshot_provider.rb +23 -23
  5. data/lib/applitools/calabash/full_page_capture_algorithm/base.rb +1 -1
  6. data/lib/applitools/connectivity/proxy.rb +11 -3
  7. data/lib/applitools/connectivity/server_connector.rb +2 -1
  8. data/lib/applitools/core/accessibility_level.rb +11 -0
  9. data/lib/applitools/core/batch_info.rb +24 -2
  10. data/lib/applitools/core/classic_runner.rb +9 -1
  11. data/lib/applitools/core/debug_screenshot_provider.rb +3 -3
  12. data/lib/applitools/core/eyes_base.rb +81 -28
  13. data/lib/applitools/core/eyes_base_configuration.rb +22 -1
  14. data/lib/applitools/core/eyes_runner.rb +12 -0
  15. data/lib/applitools/core/floating_region.rb +17 -8
  16. data/lib/applitools/core/image_match_settings.rb +54 -0
  17. data/lib/applitools/core/match_level.rb +3 -1
  18. data/lib/applitools/core/screenshot.rb +7 -7
  19. data/lib/applitools/core/test_result_summary.rb +17 -4
  20. data/lib/applitools/core/test_results.rb +2 -2
  21. data/lib/applitools/core/universal_eyes_checks.rb +66 -0
  22. data/lib/applitools/core/universal_eyes_open.rb +100 -0
  23. data/lib/applitools/core/universal_new_api.rb +43 -0
  24. data/lib/applitools/universal_sdk/universal_check_settings.rb +190 -0
  25. data/lib/applitools/universal_sdk/universal_client.rb +142 -0
  26. data/lib/applitools/universal_sdk/universal_client_socket.rb +110 -0
  27. data/lib/applitools/universal_sdk/universal_eyes.rb +45 -0
  28. data/lib/applitools/universal_sdk/universal_eyes_config.rb +205 -0
  29. data/lib/applitools/universal_sdk/universal_eyes_manager.rb +40 -0
  30. data/lib/applitools/universal_sdk/universal_eyes_manager_config.rb +62 -0
  31. data/lib/applitools/universal_sdk/universal_server.rb +81 -0
  32. data/lib/applitools/utils/image_utils.rb +7 -7
  33. data/lib/applitools/utils/utils.rb +13 -0
  34. data/lib/applitools/version.rb +2 -1
  35. data/lib/eyes_core.rb +4 -1
  36. metadata +55 -18
  37. data/lib/applitools/chunky_png/resampling.rb +0 -51
  38. data/lib/applitools/chunky_png_patch.rb +0 -11
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: false
2
+
3
+ module Applitools
4
+ module UniversalNewApi
5
+
6
+ # export type OCRExtractSettings<TElement, TSelector> = {
7
+ # target: RegionReference<TElement, TSelector>
8
+ # hint?: string
9
+ # minMatch?: number
10
+ # language?: string
11
+ # }
12
+ def extract_text(targets_array)
13
+ targets_array.map do |target|
14
+ target['target'] = { elementId: target['target'].ref } if target['target'].is_a?(::Selenium::WebDriver::Element)
15
+ target
16
+ end
17
+ universal_eyes.extract_text(targets_array)
18
+ end
19
+
20
+
21
+ # export type OCRSearchSettings<TPattern extends string> = {
22
+ # patterns: TPattern[]
23
+ # ignoreCase?: boolean
24
+ # firstOnly?: boolean
25
+ # language?: string
26
+ # }
27
+ def extract_text_regions(patterns_array)
28
+ results = universal_eyes.extract_text_regions(patterns_array)
29
+ Applitools::Utils.deep_stringify_keys(results)
30
+ end
31
+
32
+
33
+ def locate(locate_settings)
34
+ settings = {
35
+ locatorNames: locate_settings[:locator_names],
36
+ firstOnly: !!locate_settings[:first_only]
37
+ }
38
+ results = universal_eyes.locate(settings)
39
+ Applitools::Utils.deep_stringify_keys(results)
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Applitools
4
+ class UniversalCheckSettings
5
+ include Applitools::Jsonable
6
+
7
+ # export type CheckSettings<TElement, TSelector> = MatchSettings<RegionReference<TElement, TSelector>> &
8
+ # ScreenshotSettings<TElement, TSelector> & {
9
+ # name?: string
10
+ # disableBrowserFetching?: boolean
11
+ # layoutBreakpoints?: boolean | number[]
12
+ # visualGridOptions?: {[key: string]: any}
13
+ # hooks?: {beforeCaptureScreenshot: string}
14
+ # pageId?: string
15
+ # renderId?: string
16
+ # variationGroupId?: string
17
+ # timeout?: number
18
+ # waitBeforeCapture?: number
19
+ # }
20
+ json_fields :name,
21
+ :disableBrowserFetching,
22
+ :layoutBreakpoints,
23
+ :visualGridOptions,
24
+ :hooks,
25
+ :pageId,
26
+ :renderId,
27
+ :variationGroupId,
28
+ :timeout,
29
+ :waitBeforeCapture
30
+
31
+ # export type MatchSettings<TRegion> = {
32
+ # exact?: {
33
+ # minDiffIntensity: number
34
+ # minDiffWidth: number
35
+ # minDiffHeight: number
36
+ # matchThreshold: number
37
+ # }
38
+ # matchLevel?: MatchLevel
39
+ # sendDom?: boolean
40
+ # useDom?: boolean
41
+ # enablePatterns?: boolean
42
+ # ignoreCaret?: boolean
43
+ # ignoreDisplacements?: boolean
44
+ # accessibilitySettings?: {
45
+ # level?: AccessibilityLevel
46
+ # guidelinesVersion?: AccessibilityGuidelinesVersion
47
+ # }
48
+ # ignoreRegions?: TRegion[]
49
+ # layoutRegions?: TRegion[]
50
+ # strictRegions?: TRegion[]
51
+ # contentRegions?: TRegion[]
52
+ # floatingRegions?: (TRegion | FloatingRegion<TRegion>)[]
53
+ # accessibilityRegions?: (TRegion | AccessibilityRegion<TRegion>)[]
54
+ # }
55
+ json_fields :exact,
56
+ :matchLevel,
57
+ :sendDom,
58
+ :useDom,
59
+ :enablePatterns,
60
+ :ignoreCaret,
61
+ :ignoreDisplacements,
62
+ :accessibilitySettings,
63
+ :ignoreRegions,
64
+ :layoutRegions,
65
+ :strictRegions,
66
+ :contentRegions,
67
+ :floatingRegions,
68
+ :accessibilityRegions
69
+
70
+ # export type ScreenshotSettings<TElement, TSelector> = {
71
+ # region?: RegionReference<TElement, TSelector>
72
+ # frames?: (ContextReference<TElement, TSelector> | FrameReference<TElement, TSelector>)[]
73
+ # scrollRootElement?: ElementReference<TElement, TSelector>
74
+ # fully?: boolean
75
+ # }
76
+ json_fields :region,
77
+ :frames,
78
+ :scrollRootElement,
79
+ :fully
80
+
81
+ def initialize(*args)
82
+ options = Applitools::Utils.extract_options! args
83
+ options.keys.select {|k| options[k] && respond_to?("#{k}=") }.each {|k| send("#{k}=", options[k]) }
84
+
85
+ # self.timeout = Applitools::Connectivity::ServerConnector::DEFAULT_TIMEOUT
86
+ end
87
+
88
+ def normalize_element_selector(element)
89
+ if element.is_a?(::Selenium::WebDriver::Element) || element.is_a?(Applitools::Selenium::Element)
90
+ ref = element.ref
91
+ ref = element.ref[1] if ref.is_a?(Array) && ref[0] === :element
92
+ return { elementId: ref }
93
+ else
94
+ element
95
+ end
96
+ end
97
+
98
+ def from_original_target(target, eyes)
99
+ # require('pry')
100
+ # binding.pry
101
+
102
+ self.accessibility_settings = eyes.accessibility_validation
103
+ self.disable_browser_fetching = eyes.dont_fetch_resources
104
+
105
+ self.accessibility_regions = target.accessibility_regions
106
+ self.content_regions = target.content_regions
107
+ self.floating_regions = target.floating_regions
108
+
109
+ if target.respond_to?(:frames)
110
+ self.frames = target.frames.map do |f|
111
+ f = f.call(eyes.driver) if f.is_a?(Proc)
112
+ normalize_element_selector(f)
113
+ end
114
+ end
115
+
116
+ self.fully = target.options[:stitch_content]
117
+ self.hooks = target.options[:script_hooks]
118
+
119
+ # require('pry')
120
+ # binding.pry
121
+
122
+ self.ignore_regions = target.ignored_regions.map do |ir|
123
+ ir.is_a?(Proc) ? normalize_element_selector(ir.call(eyes.driver)) : ir
124
+ end
125
+ # self.ignore_regions = target.ignored_regions
126
+ self.layout_regions = target.layout_regions.map do |lr|
127
+ lr.is_a?(Proc) ? normalize_element_selector(lr.call(eyes.driver)) : lr
128
+ end
129
+
130
+ if target.region_to_check.is_a?(Hash)
131
+ self.region = target.region_to_check
132
+ elsif target.region_to_check.is_a?(String)
133
+ self.region = target.region_to_check
134
+ elsif target.region_to_check.is_a?(Proc)
135
+ # require('pry')
136
+ # binding.pry
137
+ el = target.region_to_check.call(eyes.driver)
138
+ self.region = normalize_element_selector(el) unless el.respond_to?(:empty?) && el.empty?
139
+ end
140
+ # self.region = normalize_element_selector(target.region_to_check.call(eyes.driver))
141
+ # self.region = nil if region.empty?
142
+
143
+ self.strict_regions = target.strict_regions
144
+ self.timeout = target.options[:timeout]
145
+ self.variation_group_id = target.options[:variation_group_id]
146
+ self.wait_before_capture = target.options[:wait_before_capture]
147
+ self.page_id = target.options[:page_id]
148
+
149
+ self.scroll_root_element = target.options[:scroll_root_element] || eyes.scroll_root_element
150
+ self.layout_breakpoints = target.options[:layout_breakpoints] || eyes.layout_breakpoints
151
+
152
+ self.exact = (target.options[:exact] && target.options[:exact].to_hash) || (eyes.exact && eyes.exact.to_hash)
153
+ self.enable_patterns = from_target_options_or_eyes(:enable_patterns, target.options, eyes)
154
+ self.ignore_caret = from_target_options_or_eyes(:ignore_caret, target.options, eyes)
155
+ self.ignore_displacements = from_target_options_or_eyes(:ignore_displacements, target.options, eyes)
156
+ self.match_level = from_target_options_or_eyes(:match_level, target.options, eyes)
157
+ self.send_dom = from_target_options_or_eyes(:send_dom, target.options, eyes)
158
+ self.use_dom = from_target_options_or_eyes(:use_dom, target.options, eyes)
159
+ self.visual_grid_options = from_target_options_or_eyes(:visual_grid_options, target.options, eyes)
160
+ # rescue => e
161
+ # require('pry')
162
+ # binding.pry
163
+ end
164
+
165
+ def to_hash
166
+ json_data.compact.reject do |_, v|
167
+ case v
168
+ when Array, Hash
169
+ v.empty?
170
+ when Numeric
171
+ v.zero?
172
+ # when FalseClass
173
+ # true
174
+ else
175
+ false
176
+ end
177
+ end
178
+ end
179
+
180
+ private
181
+
182
+ def from_target_options_or_eyes(what, options, eyes)
183
+ return options[what] unless options[what].nil?
184
+ return eyes.send(what) if eyes.respond_to?(what)
185
+ nil
186
+ end
187
+
188
+ end
189
+ end
190
+ # U-Notes : Added internal Applitools::UniversalCheckSettings
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eventmachine'
4
+
5
+ # require_relative 'universal_client_socket'
6
+ # require_relative 'universal_eyes_manager'
7
+
8
+ module Applitools::Connectivity
9
+ class UniversalClient
10
+
11
+ extend Forwardable
12
+ def_delegators 'Applitools::EyesLogger', :logger
13
+
14
+ SESSION_INIT = 'Core.makeSDK'
15
+
16
+ CORE_MAKE_MANAGER = 'Core.makeManager'
17
+ CORE_GET_VIEWPORT_SIZE = 'Core.getViewportSize'
18
+ CORE_SET_VIEWPORT_SIZE = 'Core.setViewportSize'
19
+ CORE_CLOSE_BATCHES = 'Core.closeBatches'
20
+ CORE_DELETE_TEST = 'Core.deleteTest'
21
+
22
+ EYES_MANAGER_MAKE_EYES = 'EyesManager.openEyes'
23
+ EYES_MANAGER_CLOSE_ALL_EYES = 'EyesManager.closeManager'
24
+ EYES_CHECK = 'Eyes.check'
25
+ EYES_LOCATE = 'Eyes.locate'
26
+ EYES_EXTRACT_TEXT_REGIONS = 'Eyes.extractTextRegions'
27
+ EYES_EXTRACT_TEXT = 'Eyes.extractText'
28
+ EYES_CLOSE = 'Eyes.close'
29
+ EYES_ABORT = 'Eyes.abort'
30
+
31
+
32
+ def initialize(queue = EM::Queue.new)
33
+ @socket = Applitools::Connectivity::UniversalClientSocket.new
34
+ @queue = queue
35
+ prepare_socket
36
+ # store on open for next check calls
37
+ @open_config = nil
38
+ end
39
+
40
+ def make_manager(eyes_manager_config)
41
+ Applitools::EyesLogger.logger.debug "EyesManager config: #{eyes_manager_config}"
42
+ eyes_manager = core_make_manager(eyes_manager_config)
43
+ Applitools::EyesLogger.logger.debug "EyesManager applitools-ref-id: #{eyes_manager[:"applitools-ref-id"]}"
44
+ Applitools::UniversalEyesManager.new(eyes_manager, self)
45
+ end
46
+
47
+
48
+ def core_make_manager(eyes_manager_config)
49
+ await(->(cb) { @socket.request(CORE_MAKE_MANAGER, eyes_manager_config, cb) })
50
+ end
51
+
52
+ def eyes_manager_make_eyes(manager, driver_config, config)
53
+ @open_config = config
54
+
55
+ await(->(cb) {
56
+ @socket.request(EYES_MANAGER_MAKE_EYES, {manager: manager, driver: driver_config, config: config}, cb)
57
+ })
58
+ end
59
+
60
+ def eyes_manager_close_all_eyes(manager)
61
+ await(->(cb) { @socket.request(EYES_MANAGER_CLOSE_ALL_EYES, {manager: manager}, cb) })
62
+ end
63
+
64
+ def eyes_check(eyes, settings)
65
+ await(->(cb) { @socket.request(EYES_CHECK, {eyes: eyes, settings: settings, config: @open_config}, cb) })
66
+ end
67
+
68
+ def eyes_locate(eyes, settings)
69
+ await(->(cb) { @socket.request(EYES_LOCATE, {eyes: eyes, settings: settings, config: @open_config}, cb) })
70
+ end
71
+
72
+ def eyes_extract_text_regions(eyes, settings)
73
+ await(->(cb) { @socket.request(EYES_EXTRACT_TEXT_REGIONS, {eyes: eyes, settings: settings, config: @open_config}, cb) })
74
+ end
75
+
76
+ def eyes_extract_text(eyes, regions)
77
+ await(->(cb) { @socket.request(EYES_EXTRACT_TEXT, {eyes: eyes, regions: regions, config: @open_config}, cb) })
78
+ end
79
+
80
+ def eyes_close(eyes)
81
+ await(->(cb) { @socket.request(EYES_CLOSE, {eyes: eyes}, cb) })
82
+ end
83
+
84
+ def eyes_abort(eyes)
85
+ await(->(cb) { @socket.request(EYES_ABORT, {eyes: eyes}, cb) })
86
+ end
87
+
88
+ def core_get_viewport_size(driver)
89
+ await(->(cb) { @socket.request(CORE_GET_VIEWPORT_SIZE, {driver: driver}, cb) })
90
+ end
91
+
92
+ def core_set_viewport_size(driver, size)
93
+ await(->(cb) { @socket.request(CORE_SET_VIEWPORT_SIZE, {driver: driver, size: size}, cb) })
94
+ end
95
+
96
+ def core_close_batches(close_batch_settings)
97
+ # batchIds, serverUrl?, apiKey?, proxy?
98
+ await(->(cb) { @socket.request(CORE_CLOSE_BATCHES, close_batch_settings, cb) })
99
+ end
100
+
101
+ def core_delete_test(delete_test_settings)
102
+ # testId, batchId, secretToken, serverUrl, apiKey?, proxy?
103
+ await(->(cb) { @socket.request(CORE_DELETE_TEST, delete_test_settings, cb) })
104
+ end
105
+
106
+
107
+ private
108
+
109
+
110
+ def prepare_socket
111
+ socket_uri = ::Applitools::Connectivity::UniversalServer.check_or_run
112
+ connect_and_configure_socket(socket_uri)
113
+ end
114
+
115
+ def connect_and_configure_socket(uri)
116
+ Thread.new do
117
+ EM.run do
118
+ @socket.connect(uri)
119
+ @socket.emit(SESSION_INIT, {
120
+ name: :rb,
121
+ version: ::Applitools::VERSION,
122
+ protocol: :webdriver,
123
+ cwd: Dir.pwd
124
+ })
125
+ end
126
+ end
127
+ end
128
+
129
+ def await(function)
130
+ resolved = false
131
+ cb = ->(result) {
132
+ resolved = result
133
+ }
134
+ @queue.push(function)
135
+ @queue.pop {|fn| fn.call(cb)}
136
+ sleep 1 until !!resolved
137
+ resolved
138
+ end
139
+
140
+ end
141
+ end
142
+ # U-Notes : Added internal Applitools::Connectivity::UniversalClient
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faye/websocket'
4
+ require 'json'
5
+ require 'securerandom'
6
+ require 'colorize'
7
+
8
+ module Applitools::Connectivity
9
+ class UniversalClientSocket
10
+ attr_reader :listeners, :queue
11
+
12
+ def initialize
13
+ @listeners = {}
14
+ @queue = []
15
+ end
16
+
17
+ def connect(uri, ws = ::Faye::WebSocket::Client.new(uri))
18
+ @socket = ws
19
+
20
+ queue.each {|command| command.call}
21
+ queue.clear
22
+
23
+ ws.on :message do |event|
24
+ message = JSON.parse(event.data, {:symbolize_names => true})
25
+ params = [message[:payload], message[:key]]
26
+ find_and_execute_listeners(message[:name], message[:key], params)
27
+ end
28
+
29
+ ws.on :close do |event|
30
+ find_and_execute_listeners('close')
31
+ end
32
+ end
33
+
34
+ def emit(message, payload)
35
+ command = ->() {@socket.send(serialize(message, payload))}
36
+ @socket ? command.call : queue.push(command)
37
+ end
38
+
39
+ def command(name, fn)
40
+ on(name, ->(payload, key) {
41
+ begin
42
+ log("[#{'COMMAND'.yellow}] #{name}, #{key}, #{JSON.pretty_generate(payload)}")
43
+ result = fn.call(payload)
44
+ emit({name: name, key: key}, {result: result})
45
+ rescue => error
46
+ log("[#{'COMMAND ERROR'.red}] #{error}")
47
+ emit({name: name, key: key}, error.message || error)
48
+ end
49
+ })
50
+ end
51
+
52
+ def request(name, payload, cb = nil, key = SecureRandom.uuid)
53
+ log("[#{'REQUEST'.blue}] #{name}, #{key}, #{JSON.pretty_generate(payload)}")
54
+ emit({name: name, key: key}, payload)
55
+ once({name: name, key: key}, Proc.new {|result|
56
+ cb.call(result[:result] || result[:error] || true) if cb
57
+ })
58
+ end
59
+
60
+ private
61
+
62
+ def find_and_execute_listeners(name, key = nil, params = [])
63
+ name_with_key = "#{name}/#{key}"
64
+ fns = listeners[name.to_sym]
65
+ fns = listeners[name_with_key.to_sym] if (!fns)
66
+ return if (!fns)
67
+ fns.each {|fn| fn.call(*params)}
68
+ end
69
+
70
+ def serialize(type, payload)
71
+ message = type.is_a?(String) ?
72
+ {:name => type, :payload => payload} : {:name => type[:name], key: type[:key], :payload => payload}
73
+ JSON.generate(message)
74
+ end
75
+
76
+ def get_name_from_type(type)
77
+ type.is_a?(String) ? type : "#{type[:name]}/#{type[:key]}"
78
+ end
79
+
80
+ def on(type, fn)
81
+ name = get_name_from_type(type)
82
+ fns = listeners[name.to_sym]
83
+ if (!fns)
84
+ fns = []
85
+ listeners[name.to_sym] = fns
86
+ end
87
+ fns.push(fn)
88
+ end
89
+
90
+ def off(type)
91
+ name = get_name_from_type(type)
92
+ listeners.delete(name.to_sym)
93
+ end
94
+
95
+ def once(type, fn)
96
+ on(type, ->(*args) {
97
+ fn.call(*args)
98
+ off(type)
99
+ })
100
+ end
101
+
102
+ def log(message)
103
+ if ENV['APPLITOOLS_SHOW_UNIVERSAL_LOGS']
104
+ Applitools::EyesLogger.logger.debug message
105
+ end
106
+ end
107
+
108
+ end
109
+ end
110
+ # U-Notes : Added internal Applitools::Connectivity::UniversalClientSocket
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Applitools
4
+ class UniversalEyes
5
+
6
+ extend Forwardable
7
+ def_delegators 'Applitools::EyesLogger', :logger
8
+
9
+ def initialize(eyes, universal_client)
10
+ @eyes = eyes
11
+ @universal_client = universal_client
12
+ end
13
+
14
+ def check(settings)
15
+ elapsed_time_start = Time.now
16
+ # Applitools::EyesLogger.logger.debug "check settings: #{settings}"
17
+ check_result = @universal_client.eyes_check(@eyes, settings)
18
+ # Applitools::EyesLogger.logger.debug "check_result: #{check_result}"
19
+ Applitools::EyesLogger.logger.info "Completed in #{format('%.2f', Time.now - elapsed_time_start)} seconds"
20
+ check_result
21
+ end
22
+
23
+ def close
24
+ @universal_client.eyes_close(@eyes)
25
+ end
26
+
27
+ def abort
28
+ @universal_client.eyes_abort(@eyes)
29
+ end
30
+
31
+ def locate(settings)
32
+ @universal_client.eyes_locate(@eyes, settings)
33
+ end
34
+
35
+ def extract_text_regions(patterns_array)
36
+ @universal_client.eyes_extract_text_regions(@eyes, patterns_array)
37
+ end
38
+
39
+ def extract_text(targets_array)
40
+ @universal_client.eyes_extract_text(@eyes, targets_array)
41
+ end
42
+
43
+ end
44
+ end
45
+ # U-Notes : Added internal Applitools::UniversalEyes