Module: AppiumFailureHelper::Analyzer

Defined in:
lib/appium_failure_helper/analyzer.rb

Class Method Summary collapse

Class Method Details

.extract_failure_details(exception) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/appium_failure_helper/analyzer.rb', line 3

def self.extract_failure_details(exception)
  message = exception.message
  info = {}
  patterns = [
    /element with locator ['"]?(#?\w+)['"]?/i,
    /(?:could not be found|cannot find element) using (.+?)=['"]?([^'"]+)['"]?/i,
    /no such element: Unable to locate element: {"method":"([^"]+)","selector":"([^"]+)"}/i,
    /(?:with the resource-id|with the accessibility-id) ['"]?(.+?)['"]?/i
  ]
  patterns.each do |pattern|
      match = message.match(pattern)
      if match
          info[:selector_value] = match.captures.last.strip.gsub(/['"]/, '')
          info[:selector_type] = match.captures.size > 1 ? match.captures[0].strip.gsub(/['"]/, '') : 'id'
          return info
      end
  end
  info
end

.find_de_para_match(failed_info, element_map) ⇒ Object



23
24
25
26
27
28
29
30
31
32
# File 'lib/appium_failure_helper/analyzer.rb', line 23

def self.find_de_para_match(failed_info, element_map)
  logical_name_key = failed_info[:selector_value].to_s.gsub(/^#/, '')
  if element_map.key?(logical_name_key)
    return {
      logical_name: logical_name_key,
      correct_locator: element_map[logical_name_key]
    }
  end
  nil
end

.find_similar_elements(failed_info, all_page_suggestions) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/appium_failure_helper/analyzer.rb', line 34

def self.find_similar_elements(failed_info, all_page_suggestions)
  failed_locator_value = failed_info[:selector_value]
  failed_locator_type = failed_info[:selector_type]
  return [] unless failed_locator_value && failed_locator_type

  normalized_failed_type = failed_locator_type.downcase.include?('id') ? 'id' : failed_locator_type

  cleaned_failed_locator = failed_locator_value.to_s.gsub(/[:\-\/@=\[\]'"()]/, ' ').gsub(/\s+/, ' ').downcase.strip
  similarities = []

  all_page_suggestions.each do |suggestion|
    candidate_locator = suggestion[:locators].find { |loc| loc[:strategy] == normalized_failed_type }
    next unless candidate_locator
    
    cleaned_candidate_locator = candidate_locator[:locator].gsub(/[:\-\/@=\[\]'"()]/, ' ').gsub(/\s+/, ' ').downcase.strip
    distance = DidYouMean::Levenshtein.distance(cleaned_failed_locator, cleaned_candidate_locator)
    max_len = [cleaned_failed_locator.length, cleaned_candidate_locator.length].max
    next if max_len.zero?
    
    similarity_score = 1.0 - (distance.to_f / max_len)
    if similarity_score > 0.8
      similarities << { name: suggestion[:name], locators: suggestion[:locators], score: similarity_score }
    end
  end
  similarities.sort_by { |s| -s[:score] }.first(5)
end