eyes_core 3.18.1 → 4.0.0
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/lib/applitools/appium/eyes.rb +2 -1
- data/lib/applitools/appium/target.rb +218 -193
- data/lib/applitools/connectivity/proxy.rb +11 -3
- data/lib/applitools/connectivity/server_connector.rb +4 -2
- data/lib/applitools/core/accessibility_level.rb +11 -0
- data/lib/applitools/core/batch_info.rb +24 -2
- data/lib/applitools/core/classic_runner.rb +8 -1
- data/lib/applitools/core/eyes_base.rb +82 -29
- data/lib/applitools/core/eyes_base_configuration.rb +34 -2
- data/lib/applitools/core/eyes_runner.rb +12 -0
- data/lib/applitools/core/floating_region.rb +17 -8
- data/lib/applitools/core/image_match_settings.rb +54 -0
- data/lib/applitools/core/match_level.rb +3 -1
- data/lib/applitools/core/match_window_data.rb +4 -0
- data/lib/applitools/core/session_start_info.rb +2 -1
- data/lib/applitools/core/test_results.rb +2 -2
- data/lib/applitools/core/universal_eyes_checks.rb +66 -0
- data/lib/applitools/core/universal_eyes_open.rb +100 -0
- data/lib/applitools/core/universal_new_api.rb +43 -0
- data/lib/applitools/universal_sdk/universal_check_settings.rb +184 -0
- data/lib/applitools/universal_sdk/universal_client.rb +142 -0
- data/lib/applitools/universal_sdk/universal_client_socket.rb +110 -0
- data/lib/applitools/universal_sdk/universal_eyes.rb +45 -0
- data/lib/applitools/universal_sdk/universal_eyes_config.rb +203 -0
- data/lib/applitools/universal_sdk/universal_eyes_manager.rb +40 -0
- data/lib/applitools/universal_sdk/universal_eyes_manager_config.rb +62 -0
- data/lib/applitools/universal_sdk/universal_server.rb +81 -0
- data/lib/applitools/utils/utils.rb +13 -0
- data/lib/applitools/version.rb +2 -1
- data/lib/eyes_core.rb +3 -0
- metadata +69 -2
| @@ -0,0 +1,184 @@ | |
| 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 | 
            +
                #     renderId?: string
         | 
| 15 | 
            +
                #     variationGroupId?: string
         | 
| 16 | 
            +
                #     timeout?: number
         | 
| 17 | 
            +
                #   }
         | 
| 18 | 
            +
                json_fields :name,
         | 
| 19 | 
            +
                  :disableBrowserFetching,
         | 
| 20 | 
            +
                  :layoutBreakpoints,
         | 
| 21 | 
            +
                  :visualGridOptions,
         | 
| 22 | 
            +
                  :hooks,
         | 
| 23 | 
            +
                  :renderId,
         | 
| 24 | 
            +
                  :variationGroupId,
         | 
| 25 | 
            +
                  :timeout
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                # export type MatchSettings<TRegion> = {
         | 
| 28 | 
            +
                #   exact?: {
         | 
| 29 | 
            +
                #     minDiffIntensity: number
         | 
| 30 | 
            +
                #     minDiffWidth: number
         | 
| 31 | 
            +
                #     minDiffHeight: number
         | 
| 32 | 
            +
                #     matchThreshold: number
         | 
| 33 | 
            +
                #   }
         | 
| 34 | 
            +
                #   matchLevel?: MatchLevel
         | 
| 35 | 
            +
                #   sendDom?: boolean
         | 
| 36 | 
            +
                #   useDom?: boolean
         | 
| 37 | 
            +
                #   enablePatterns?: boolean
         | 
| 38 | 
            +
                #   ignoreCaret?: boolean
         | 
| 39 | 
            +
                #   ignoreDisplacements?: boolean
         | 
| 40 | 
            +
                #   accessibilitySettings?: {
         | 
| 41 | 
            +
                #     level?: AccessibilityLevel
         | 
| 42 | 
            +
                #     guidelinesVersion?: AccessibilityGuidelinesVersion
         | 
| 43 | 
            +
                #   }
         | 
| 44 | 
            +
                #   ignoreRegions?: TRegion[]
         | 
| 45 | 
            +
                #   layoutRegions?: TRegion[]
         | 
| 46 | 
            +
                #   strictRegions?: TRegion[]
         | 
| 47 | 
            +
                #   contentRegions?: TRegion[]
         | 
| 48 | 
            +
                #   floatingRegions?: (TRegion | FloatingRegion<TRegion>)[]
         | 
| 49 | 
            +
                #   accessibilityRegions?: (TRegion | AccessibilityRegion<TRegion>)[]
         | 
| 50 | 
            +
                # }
         | 
| 51 | 
            +
                json_fields :exact,
         | 
| 52 | 
            +
                  :matchLevel,
         | 
| 53 | 
            +
                  :sendDom,
         | 
| 54 | 
            +
                  :useDom,
         | 
| 55 | 
            +
                  :enablePatterns,
         | 
| 56 | 
            +
                  :ignoreCaret,
         | 
| 57 | 
            +
                  :ignoreDisplacements,
         | 
| 58 | 
            +
                  :accessibilitySettings,
         | 
| 59 | 
            +
                  :ignoreRegions,
         | 
| 60 | 
            +
                  :layoutRegions,
         | 
| 61 | 
            +
                  :strictRegions,
         | 
| 62 | 
            +
                  :contentRegions,
         | 
| 63 | 
            +
                  :floatingRegions,
         | 
| 64 | 
            +
                  :accessibilityRegions
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                # export type ScreenshotSettings<TElement, TSelector> = {
         | 
| 67 | 
            +
                #   region?: RegionReference<TElement, TSelector>
         | 
| 68 | 
            +
                #   frames?: (ContextReference<TElement, TSelector> | FrameReference<TElement, TSelector>)[]
         | 
| 69 | 
            +
                #   scrollRootElement?: ElementReference<TElement, TSelector>
         | 
| 70 | 
            +
                #   fully?: boolean
         | 
| 71 | 
            +
                # }
         | 
| 72 | 
            +
                json_fields :region,
         | 
| 73 | 
            +
                  :frames,
         | 
| 74 | 
            +
                  :scrollRootElement,
         | 
| 75 | 
            +
                  :fully
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                def initialize(*args)
         | 
| 78 | 
            +
                  options = Applitools::Utils.extract_options! args
         | 
| 79 | 
            +
                  options.keys.select {|k| options[k] && respond_to?("#{k}=") }.each {|k| send("#{k}=", options[k]) }
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  # self.timeout = Applitools::Connectivity::ServerConnector::DEFAULT_TIMEOUT
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                def normalize_element_selector(element)
         | 
| 85 | 
            +
                  if element.is_a?(::Selenium::WebDriver::Element) || element.is_a?(Applitools::Selenium::Element)
         | 
| 86 | 
            +
                    ref = element.ref
         | 
| 87 | 
            +
                    ref = element.ref[1] if ref.is_a?(Array) && ref[0] === :element
         | 
| 88 | 
            +
                    return { elementId: ref }
         | 
| 89 | 
            +
                  else
         | 
| 90 | 
            +
                    element
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def from_original_target(target, eyes)
         | 
| 95 | 
            +
                  # require('pry')
         | 
| 96 | 
            +
                  # binding.pry
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  self.accessibility_settings = eyes.accessibility_validation
         | 
| 99 | 
            +
                  self.disable_browser_fetching = eyes.dont_fetch_resources
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                  self.accessibility_regions = target.accessibility_regions
         | 
| 102 | 
            +
                  self.content_regions = target.content_regions
         | 
| 103 | 
            +
                  self.floating_regions = target.floating_regions
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  if target.respond_to?(:frames)
         | 
| 106 | 
            +
                    self.frames = target.frames.map do |f|
         | 
| 107 | 
            +
                      f = f.call(eyes.driver) if f.is_a?(Proc)
         | 
| 108 | 
            +
                      normalize_element_selector(f)
         | 
| 109 | 
            +
                    end
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  self.fully = target.options[:stitch_content]
         | 
| 113 | 
            +
                  self.hooks = target.options[:script_hooks]
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  # require('pry')
         | 
| 116 | 
            +
                  # binding.pry
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  self.ignore_regions = target.ignored_regions.map do |ir|
         | 
| 119 | 
            +
                    ir.is_a?(Proc) ? normalize_element_selector(ir.call(eyes.driver)) : ir
         | 
| 120 | 
            +
                  end
         | 
| 121 | 
            +
                  # self.ignore_regions = target.ignored_regions
         | 
| 122 | 
            +
                  self.layout_regions = target.layout_regions.map do |lr|
         | 
| 123 | 
            +
                    lr.is_a?(Proc) ? normalize_element_selector(lr.call(eyes.driver)) : lr
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                  if target.region_to_check.is_a?(Hash)
         | 
| 127 | 
            +
                    self.region = target.region_to_check
         | 
| 128 | 
            +
                  elsif target.region_to_check.is_a?(String)
         | 
| 129 | 
            +
                    self.region = target.region_to_check
         | 
| 130 | 
            +
                  elsif target.region_to_check.is_a?(Proc)
         | 
| 131 | 
            +
                    # require('pry')
         | 
| 132 | 
            +
                    # binding.pry
         | 
| 133 | 
            +
                    el = target.region_to_check.call(eyes.driver)
         | 
| 134 | 
            +
                    self.region = normalize_element_selector(el) unless el.respond_to?(:empty?) && el.empty?
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
                  # self.region = normalize_element_selector(target.region_to_check.call(eyes.driver))
         | 
| 137 | 
            +
                  # self.region = nil if region.empty?
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  self.strict_regions = target.strict_regions
         | 
| 140 | 
            +
                  self.timeout = target.options[:timeout]
         | 
| 141 | 
            +
                  self.variation_group_id = target.options[:variation_group_id]
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                  self.scroll_root_element = target.options[:scroll_root_element] || eyes.scroll_root_element
         | 
| 144 | 
            +
                  self.layout_breakpoints = target.options[:layout_breakpoints] || eyes.layout_breakpoints
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                  self.exact = (target.options[:exact] && target.options[:exact].to_hash) || (eyes.exact && eyes.exact.to_hash)
         | 
| 147 | 
            +
                  self.enable_patterns = from_target_options_or_eyes(:enable_patterns, target.options, eyes)
         | 
| 148 | 
            +
                  self.ignore_caret = from_target_options_or_eyes(:ignore_caret, target.options, eyes)
         | 
| 149 | 
            +
                  self.ignore_displacements = from_target_options_or_eyes(:ignore_displacements, target.options, eyes)
         | 
| 150 | 
            +
                  self.match_level = from_target_options_or_eyes(:match_level, target.options, eyes)
         | 
| 151 | 
            +
                  self.send_dom = from_target_options_or_eyes(:send_dom, target.options, eyes)
         | 
| 152 | 
            +
                  self.use_dom = from_target_options_or_eyes(:use_dom, target.options, eyes)
         | 
| 153 | 
            +
                  self.visual_grid_options = from_target_options_or_eyes(:visual_grid_options, target.options, eyes)
         | 
| 154 | 
            +
                # rescue => e
         | 
| 155 | 
            +
                #   require('pry')
         | 
| 156 | 
            +
                #   binding.pry
         | 
| 157 | 
            +
                end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                def to_hash
         | 
| 160 | 
            +
                  json_data.compact.reject do |_, v|
         | 
| 161 | 
            +
                    case v
         | 
| 162 | 
            +
                      when Array, Hash
         | 
| 163 | 
            +
                        v.empty?
         | 
| 164 | 
            +
                      when Numeric
         | 
| 165 | 
            +
                        v.zero?
         | 
| 166 | 
            +
                      # when FalseClass
         | 
| 167 | 
            +
                      #   true
         | 
| 168 | 
            +
                      else
         | 
| 169 | 
            +
                        false
         | 
| 170 | 
            +
                    end
         | 
| 171 | 
            +
                  end
         | 
| 172 | 
            +
                end
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                private
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                def from_target_options_or_eyes(what, options, eyes)
         | 
| 177 | 
            +
                  return options[what] unless options[what].nil?
         | 
| 178 | 
            +
                  return eyes.send(what) if eyes.respond_to?(what)
         | 
| 179 | 
            +
                  nil
         | 
| 180 | 
            +
                end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
              end
         | 
| 183 | 
            +
            end
         | 
| 184 | 
            +
            # 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.closeAllEyes'
         | 
| 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
         | 
| @@ -0,0 +1,203 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Applitools
         | 
| 4 | 
            +
              class UniversalEyesConfig
         | 
| 5 | 
            +
                include Applitools::Jsonable
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                # export type EyesBaseConfig = {
         | 
| 8 | 
            +
                #   logs?: LogHandler
         | 
| 9 | 
            +
                #   debugScreenshots?: DebugScreenshotHandler
         | 
| 10 | 
            +
                #   agentId?: string
         | 
| 11 | 
            +
                #   apiKey?: string
         | 
| 12 | 
            +
                #   serverUrl?: string
         | 
| 13 | 
            +
                #   proxy?: Proxy
         | 
| 14 | 
            +
                #   isDisabled?: boolean
         | 
| 15 | 
            +
                #   connectionTimeout?: number
         | 
| 16 | 
            +
                #   removeSession?: boolean
         | 
| 17 | 
            +
                #   remoteEvents?: {serverUrl: string; accessKey?: string; timeout?: number}
         | 
| 18 | 
            +
                # }
         | 
| 19 | 
            +
                json_fields :logs,
         | 
| 20 | 
            +
                  :debugScreenshots,
         | 
| 21 | 
            +
                  :agentId,
         | 
| 22 | 
            +
                  :apiKey,
         | 
| 23 | 
            +
                  :serverUrl,
         | 
| 24 | 
            +
                  :proxy,
         | 
| 25 | 
            +
                  :isDisabled,
         | 
| 26 | 
            +
                  :connectionTimeout,
         | 
| 27 | 
            +
                  :removeSession,
         | 
| 28 | 
            +
                  :remoteEvents
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                # export type EyesOpenConfig = {
         | 
| 31 | 
            +
                #   appName?: string
         | 
| 32 | 
            +
                #   testName?: string
         | 
| 33 | 
            +
                #   displayName?: string
         | 
| 34 | 
            +
                #   viewportSize?: Size
         | 
| 35 | 
            +
                #   sessionType?: SessionType
         | 
| 36 | 
            +
                #   properties?: CustomProperty[]
         | 
| 37 | 
            +
                #   batch?: Batch
         | 
| 38 | 
            +
                #   defaultMatchSettings?: MatchSettings<Region>
         | 
| 39 | 
            +
                #   hostApp?: string
         | 
| 40 | 
            +
                #   hostOS?: string
         | 
| 41 | 
            +
                #   hostAppInfo?: string
         | 
| 42 | 
            +
                #   hostOSInfo?: string
         | 
| 43 | 
            +
                #   deviceInfo?: string
         | 
| 44 | 
            +
                #   baselineEnvName?: string
         | 
| 45 | 
            +
                #   environmentName?: string
         | 
| 46 | 
            +
                #   branchName?: string
         | 
| 47 | 
            +
                #   parentBranchName?: string
         | 
| 48 | 
            +
                #   baselineBranchName?: string
         | 
| 49 | 
            +
                #   compareWithParentBranch?: boolean
         | 
| 50 | 
            +
                #   ignoreBaseline?: boolean
         | 
| 51 | 
            +
                #   saveFailedTests?: boolean
         | 
| 52 | 
            +
                #   saveNewTests?: boolean
         | 
| 53 | 
            +
                #   saveDiffs?: boolean
         | 
| 54 | 
            +
                #   dontCloseBatches?: boolean
         | 
| 55 | 
            +
                # }
         | 
| 56 | 
            +
                json_fields :appName,
         | 
| 57 | 
            +
                  :testName,
         | 
| 58 | 
            +
                  :displayName,
         | 
| 59 | 
            +
                  :viewportSize,
         | 
| 60 | 
            +
                  :sessionType,
         | 
| 61 | 
            +
                  :properties,
         | 
| 62 | 
            +
                  :batch,
         | 
| 63 | 
            +
                  :defaultMatchSettings,
         | 
| 64 | 
            +
                  :hostApp,
         | 
| 65 | 
            +
                  :hostOS,
         | 
| 66 | 
            +
                  :hostAppInfo,
         | 
| 67 | 
            +
                  :hostOSInfo,
         | 
| 68 | 
            +
                  :deviceInfo,
         | 
| 69 | 
            +
                  :baselineEnvName,
         | 
| 70 | 
            +
                  :environmentName,
         | 
| 71 | 
            +
                  :branchName,
         | 
| 72 | 
            +
                  :parentBranchName,
         | 
| 73 | 
            +
                  :baselineBranchName,
         | 
| 74 | 
            +
                  :compareWithParentBranch,
         | 
| 75 | 
            +
                  :ignoreBaseline,
         | 
| 76 | 
            +
                  :saveFailedTests,
         | 
| 77 | 
            +
                  :saveNewTests,
         | 
| 78 | 
            +
                  :saveDiffs,
         | 
| 79 | 
            +
                  :dontCloseBatches
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                # export type EyesCheckConfig = {
         | 
| 82 | 
            +
                #   sendDom?: boolean
         | 
| 83 | 
            +
                #   matchTimeout?: number
         | 
| 84 | 
            +
                #   forceFullPageScreenshot?: boolean
         | 
| 85 | 
            +
                # }
         | 
| 86 | 
            +
                json_fields :sendDom,
         | 
| 87 | 
            +
                  :matchTimeout,
         | 
| 88 | 
            +
                  :forceFullPageScreenshot
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                # export type EyesClassicConfig<TElement = unknown, TSelector = unknown> = {
         | 
| 91 | 
            +
                #   waitBeforeScreenshots?: number
         | 
| 92 | 
            +
                #   stitchMode?: StitchMode
         | 
| 93 | 
            +
                #   hideScrollbars?: boolean
         | 
| 94 | 
            +
                #   hideCaret?: boolean
         | 
| 95 | 
            +
                #   stitchOverlap?: number
         | 
| 96 | 
            +
                #   scrollRootElement?: TElement | TSelector
         | 
| 97 | 
            +
                #   cut?: ImageCropRect | ImageCropRegion
         | 
| 98 | 
            +
                #   rotation?: ImageRotation
         | 
| 99 | 
            +
                #   scaleRatio?: number
         | 
| 100 | 
            +
                # }
         | 
| 101 | 
            +
                json_fields :waitBeforeScreenshots,
         | 
| 102 | 
            +
                  :stitchMode,
         | 
| 103 | 
            +
                  :hideScrollbars,
         | 
| 104 | 
            +
                  :hideCaret,
         | 
| 105 | 
            +
                  :stitchOverlap,
         | 
| 106 | 
            +
                  :scrollRootElement,
         | 
| 107 | 
            +
                  :cut,
         | 
| 108 | 
            +
                  :rotation,
         | 
| 109 | 
            +
                  :scaleRatio
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                # export type EyesUFGConfig = {
         | 
| 112 | 
            +
                #   concurrentSessions?: number
         | 
| 113 | 
            +
                #   browsersInfo?: (DesktopBrowserRenderer | ChromeEmulationDeviceRenderer | IOSDeviceRenderer)[]
         | 
| 114 | 
            +
                #   visualGridOptions?: Record<string, any>
         | 
| 115 | 
            +
                #   layoutBreakpoints?: boolean | number[]
         | 
| 116 | 
            +
                #   disableBrowserFetching?: boolean
         | 
| 117 | 
            +
                # }
         | 
| 118 | 
            +
                json_fields :concurrentSessions,
         | 
| 119 | 
            +
                  :browsersInfo,
         | 
| 120 | 
            +
                  :visualGridOptions,
         | 
| 121 | 
            +
                  :layoutBreakpoints,
         | 
| 122 | 
            +
                  :disableBrowserFetching
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                # 23 + 3 + 2 + 11 = 39
         | 
| 125 | 
            +
                FROM_ORIGINAL_EYES = [:api_key, :app_name, :batch, :browsers_info, :concurrent_sessions, :debug_screenshots,
         | 
| 126 | 
            +
                  :force_full_page_screenshot, :hide_caret, :hide_scrollbars, :host_app, :host_os, :match_timeout, :proxy,
         | 
| 127 | 
            +
                  :save_failed_tests, :save_new_tests, :scale_ratio, :send_dom, :server_url, :stitch_mode, :test_name,
         | 
| 128 | 
            +
                  :viewport_size, :visual_grid_options, :wait_before_screenshots] + [
         | 
| 129 | 
            +
                  :disabled?, # disabled? => is_disabled
         | 
| 130 | 
            +
                  :stitching_overlap, # SeleniumEyes.stitching_overlap => stitch_overlap
         | 
| 131 | 
            +
                  :dont_fetch_resources # dont_fetch_resources => disable_browser_fetching
         | 
| 132 | 
            +
                ] + [
         | 
| 133 | 
            +
                  :layout_breakpoints,
         | 
| 134 | 
            +
                  :scroll_root_element,
         | 
| 135 | 
            +
                ] + [
         | 
| 136 | 
            +
                  :environment_name, :branch_name, :default_match_settings, :properties, :parent_branch_name,
         | 
| 137 | 
            +
                  :compare_with_parent_branch, :baseline_env_name, :save_diffs, :session_type, :baseline_branch_name
         | 
| 138 | 
            +
                ]
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                # 51 - 39 - 2 = 10
         | 
| 141 | 
            +
                OTHER = [:logs, :remove_session, :remote_events, :display_name, :host_app_info, :host_os_info, :device_info,
         | 
| 142 | 
            +
                  :ignore_baseline, :cut, :rotation ]
         | 
| 143 | 
            +
             | 
| 144 | 
            +
             | 
| 145 | 
            +
                alias disabled= is_disabled=
         | 
| 146 | 
            +
                alias stitching_overlap= stitch_overlap=
         | 
| 147 | 
            +
                alias dont_fetch_resources= disable_browser_fetching=
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                def initialize(*args)
         | 
| 150 | 
            +
                  options = Applitools::Utils.extract_options! args
         | 
| 151 | 
            +
                  options.keys.select {|k| options[k] && respond_to?("#{k}=") }.each {|k| send("#{k}=", options[k]) }
         | 
| 152 | 
            +
                  # other
         | 
| 153 | 
            +
                  self.connection_timeout = Applitools::Connectivity::ServerConnector::DEFAULT_TIMEOUT
         | 
| 154 | 
            +
                  if 'true'.casecmp(ENV['APPLITOOLS_DONT_CLOSE_BATCHES'] || '') == 0
         | 
| 155 | 
            +
                    self.dont_close_batches = true
         | 
| 156 | 
            +
                    Applitools::EyesLogger.info('APPLITOOLS_DONT_CLOSE_BATCHES environment variable set to true. Doing nothing.')
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                def from_original_sdk(original_eyes)
         | 
| 161 | 
            +
                  FROM_ORIGINAL_EYES.each {|m| copy_from(m, original_eyes) }
         | 
| 162 | 
            +
                  self.agent_id = original_eyes.base_agent_id if original_eyes.respond_to?(:base_agent_id)
         | 
| 163 | 
            +
                  self.agent_id = original_eyes.full_agent_id if original_eyes.respond_to?(:full_agent_id)
         | 
| 164 | 
            +
                  # self.display_name = original_eyes.app_name
         | 
| 165 | 
            +
                  prepare_for_json!
         | 
| 166 | 
            +
                end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                def copy_from(what, from)
         | 
| 169 | 
            +
                  if from.respond_to?(what)
         | 
| 170 | 
            +
                    send("#{what.to_s.chomp('?') }=", from.send(what))
         | 
| 171 | 
            +
                  else
         | 
| 172 | 
            +
                    puts "respond_to? #{what} - fail"
         | 
| 173 | 
            +
                  end
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                def prepare_for_json!
         | 
| 177 | 
            +
                  self.batch = batch.to_hash if batch.is_a?(Applitools::BatchInfo)
         | 
| 178 | 
            +
                  self.browsers_info = browsers_info.to_hash if browsers_info.is_a?(Applitools::Selenium::BrowsersInfo)
         | 
| 179 | 
            +
                  self.default_match_settings = default_match_settings.to_hash if default_match_settings.is_a?(Applitools::ImageMatchSettings)
         | 
| 180 | 
            +
                  self.proxy = proxy.to_hash if proxy.is_a?(Applitools::Connectivity::Proxy)
         | 
| 181 | 
            +
                  self.viewport_size = viewport_size.to_h if viewport_size.is_a?(Applitools::RectangleSize)
         | 
| 182 | 
            +
                  # require 'pry'
         | 
| 183 | 
            +
                  # binding.pry
         | 
| 184 | 
            +
                end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                def to_hash
         | 
| 187 | 
            +
                  json_data.compact.reject do |_, v|
         | 
| 188 | 
            +
                    case v
         | 
| 189 | 
            +
                      when Array, Hash
         | 
| 190 | 
            +
                        v.empty?
         | 
| 191 | 
            +
                      when Numeric
         | 
| 192 | 
            +
                        v.zero?
         | 
| 193 | 
            +
                      # when FalseClass
         | 
| 194 | 
            +
                      #   true
         | 
| 195 | 
            +
                      else
         | 
| 196 | 
            +
                        false
         | 
| 197 | 
            +
                    end
         | 
| 198 | 
            +
                  end
         | 
| 199 | 
            +
                end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
              end
         | 
| 202 | 
            +
            end
         | 
| 203 | 
            +
            # U-Notes : Added internal Applitools::UniversalEyesConfig
         |