eyes_core 3.18.4 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
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