appium_failure_helper 1.1.1 → 1.1.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.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3436268826107494e9e5ae0049106b4ae0d7a9d01609b0ea68e1d0e0474a07bb
|
|
4
|
+
data.tar.gz: cc600a9229697214f2e88a3b6c4ece1d7fa90b09ee1e525a32892679231451e5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ff3fd06ae96eb6ddec8170791c2c1cdb88c5266a5dd773c47ae155d7a981776b4a2f78fd82f826409822bec789b8b0047fd2060e3767ae87df1a440f52bd140f
|
|
7
|
+
data.tar.gz: a837e539fcf0f9dbbb854e80567ec5680a73914e3adeddb7a2f5dde23d853d0de06092b9c4244db038ae0e0cf495a3654b36a12e4a167ea332fc99fcefd21cd8
|
|
@@ -1,33 +1,25 @@
|
|
|
1
1
|
module AppiumFailureHelper
|
|
2
2
|
module Analyzer
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
:app_crash_issue
|
|
24
|
-
else
|
|
25
|
-
:unknown_appium_issue
|
|
26
|
-
end
|
|
27
|
-
else
|
|
28
|
-
:unknown_issue
|
|
29
|
-
end
|
|
30
|
-
return result
|
|
3
|
+
def self.triage_error(exception)
|
|
4
|
+
case exception
|
|
5
|
+
when Selenium::WebDriver::Error::NoSuchElementError, Selenium::WebDriver::Error::TimeoutError
|
|
6
|
+
:locator_issue
|
|
7
|
+
when Selenium::WebDriver::Error::ElementNotInteractableError
|
|
8
|
+
:visibility_issue
|
|
9
|
+
when Selenium::WebDriver::Error::StaleElementReferenceError
|
|
10
|
+
:stale_element_issue
|
|
11
|
+
when defined?(RSpec::Expectations::ExpectationNotMetError) ? RSpec::Expectations::ExpectationNotMetError : Class.new
|
|
12
|
+
:assertion_failure
|
|
13
|
+
when NoMethodError, NameError, ArgumentError, TypeError
|
|
14
|
+
:ruby_code_issue
|
|
15
|
+
when Selenium::WebDriver::Error::SessionNotCreatedError, Errno::ECONNREFUSED
|
|
16
|
+
:session_startup_issue
|
|
17
|
+
when Selenium::WebDriver::Error::WebDriverError
|
|
18
|
+
return :app_crash_issue if exception.message.include?('session deleted because of page crash')
|
|
19
|
+
:unknown_appium_issue
|
|
20
|
+
else
|
|
21
|
+
:unknown_issue
|
|
22
|
+
end
|
|
31
23
|
end
|
|
32
24
|
|
|
33
25
|
def self.extract_failure_details(exception)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# lib/appium_failure_helper/handler.rb
|
|
2
1
|
module AppiumFailureHelper
|
|
3
2
|
class Handler
|
|
4
3
|
def self.call(driver, exception)
|
|
@@ -8,7 +7,7 @@ module AppiumFailureHelper
|
|
|
8
7
|
def initialize(driver, exception)
|
|
9
8
|
@driver = driver
|
|
10
9
|
@exception = exception
|
|
11
|
-
@timestamp = Time.now.strftime('%
|
|
10
|
+
@timestamp = Time.now.strftime('%Ym%d_%H%M%S')
|
|
12
11
|
@output_folder = "reports_failure/failure_#{@timestamp}"
|
|
13
12
|
end
|
|
14
13
|
|
|
@@ -16,7 +15,6 @@ module AppiumFailureHelper
|
|
|
16
15
|
begin
|
|
17
16
|
unless @driver && @driver.session_id
|
|
18
17
|
Utils.logger.error("Helper não executado: driver nulo ou sessão encerrada.")
|
|
19
|
-
Utils.logger.error("Exceção original: #{@exception.message}")
|
|
20
18
|
return
|
|
21
19
|
end
|
|
22
20
|
|
|
@@ -32,45 +30,44 @@ module AppiumFailureHelper
|
|
|
32
30
|
screenshot_base64: @driver.screenshot_as(:base64)
|
|
33
31
|
}
|
|
34
32
|
|
|
33
|
+
# A análise profunda agora é executada para QUALQUER :locator_issue.
|
|
35
34
|
if triage_result == :locator_issue
|
|
36
35
|
page_source = @driver.page_source
|
|
37
36
|
doc = Nokogiri::XML(page_source)
|
|
38
37
|
|
|
38
|
+
# Tenta Plano A e Plano B sem reclassificar o erro.
|
|
39
39
|
failed_info = Analyzer.extract_failure_details(@exception) || {}
|
|
40
40
|
if failed_info.empty?
|
|
41
41
|
failed_info = SourceCodeAnalyzer.extract_from_exception(@exception) || {}
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if target_suggestion[:attributes] && (target_path = target_suggestion[:attributes][:path])
|
|
55
|
-
target_node = doc.at_xpath(target_path)
|
|
56
|
-
alternative_xpaths = XPathFactory.generate_for_node(target_node) if target_node
|
|
57
|
-
end
|
|
44
|
+
page_analyzer = PageAnalyzer.new(page_source, report_data[:platform].to_s)
|
|
45
|
+
all_page_elements = page_analyzer.analyze || []
|
|
46
|
+
similar_elements = Analyzer.find_similar_elements(failed_info, all_page_elements) || []
|
|
47
|
+
|
|
48
|
+
alternative_xpaths = []
|
|
49
|
+
if !similar_elements.empty?
|
|
50
|
+
target_suggestion = similar_elements.first
|
|
51
|
+
if target_suggestion[:attributes] && (target_path = target_suggestion[:attributes][:path])
|
|
52
|
+
target_node = doc.at_xpath(target_path)
|
|
53
|
+
alternative_xpaths = XPathFactory.generate_for_node(target_node) if target_node
|
|
58
54
|
end
|
|
55
|
+
end
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
unified_element_map = ElementRepository.load_all
|
|
58
|
+
de_para_result = Analyzer.find_de_para_match(failed_info, unified_element_map)
|
|
59
|
+
code_search_results = CodeSearcher.find_similar_locators(failed_info) || []
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
# Adiciona os dados (mesmo que vazios) ao pacote.
|
|
62
|
+
report_data.merge!({
|
|
63
|
+
page_source: page_source,
|
|
64
|
+
failed_element: failed_info,
|
|
65
|
+
similar_elements: similar_elements,
|
|
66
|
+
alternative_xpaths: alternative_xpaths,
|
|
67
|
+
de_para_analysis: de_para_result,
|
|
68
|
+
code_search_results: code_search_results,
|
|
69
|
+
all_page_elements: all_page_elements
|
|
70
|
+
})
|
|
74
71
|
end
|
|
75
72
|
|
|
76
73
|
ReportGenerator.new(@output_folder, report_data).generate_all
|
|
@@ -39,50 +39,51 @@ module AppiumFailureHelper
|
|
|
39
39
|
|
|
40
40
|
def generate_html_report
|
|
41
41
|
if @data[:triage_result] == :locator_issue && @data[:failed_element].empty?
|
|
42
|
-
|
|
42
|
+
html_content = build_simple_diagnosis_report(
|
|
43
43
|
title: "Falha na Análise do Seletor",
|
|
44
44
|
message: "A GEM identificou um erro de 'elemento não encontrado', mas não conseguiu extrair o seletor da mensagem de erro ou do código-fonte. Isso pode ocorrer com métodos de busca customizados ou seletores dinâmicos. Verifique o stack trace para encontrar a linha exata do erro e o método responsável."
|
|
45
45
|
)
|
|
46
|
+
else
|
|
47
|
+
html_content = case @data[:triage_result]
|
|
48
|
+
when :locator_issue
|
|
49
|
+
build_full_report
|
|
50
|
+
when :unidentified_locator_issue, :unidentified_timeout_issue
|
|
51
|
+
build_simple_diagnosis_report(
|
|
52
|
+
title: "Seletor Não Identificado",
|
|
53
|
+
message: "A falha ocorreu porque um elemento não foi encontrado, mas a GEM não conseguiu extrair o seletor exato da mensagem de erro ou do código-fonte. Isso geralmente acontece quando o seletor é construído dinamicamente ou está dentro de um método helper complexo. Verifique o stack trace para encontrar o método responsável (ex: 'tap_by_text')."
|
|
54
|
+
)
|
|
55
|
+
when :assertion_failure
|
|
56
|
+
build_simple_diagnosis_report(
|
|
57
|
+
title: "Falha de Asserção (Bug Funcional)",
|
|
58
|
+
message: "A automação executou os passos corretamente, mas o resultado final verificado na tela não foi o esperado. Isso geralmente indica um bug funcional na aplicação, e não um problema com o seletor."
|
|
59
|
+
)
|
|
60
|
+
when :visibility_issue
|
|
61
|
+
build_simple_diagnosis_report(
|
|
62
|
+
title: "Elemento Oculto ou Não-Interagível",
|
|
63
|
+
message: "O seletor encontrou o elemento no XML da página, mas ele não está visível ou habilitado para interação. Verifique se há outros elementos sobrepondo-o, se ele está desabilitado (disabled/enabled='false'), ou se é necessário aguardar uma animação."
|
|
64
|
+
)
|
|
65
|
+
when :stale_element_issue
|
|
66
|
+
build_simple_diagnosis_report(
|
|
67
|
+
title: "Referência de Elemento Antiga (Stale)",
|
|
68
|
+
message: "O elemento foi encontrado, mas a página foi atualizada antes que a interação pudesse ocorrer. Isso é um problema de timing. A solução é encontrar o elemento novamente logo antes de interagir com ele."
|
|
69
|
+
)
|
|
70
|
+
when :session_startup_issue
|
|
71
|
+
build_simple_diagnosis_report(
|
|
72
|
+
title: "Falha na Conexão com o Servidor Appium",
|
|
73
|
+
message: "Não foi possível criar uma sessão com o servidor. Verifique se o servidor Appium está rodando, se as 'capabilities' (incluindo prefixos 'appium:') e a URL de conexão estão corretas."
|
|
74
|
+
)
|
|
75
|
+
when :app_crash_issue
|
|
76
|
+
build_simple_diagnosis_report(
|
|
77
|
+
title: "Crash do Aplicativo",
|
|
78
|
+
message: "A sessão foi encerrada inesperadamente, o que indica que o aplicativo travou. A causa raiz deve ser investigada nos logs do dispositivo (Logcat para Android, Console para iOS)."
|
|
79
|
+
)
|
|
80
|
+
else # :ruby_code_issue, :unknown_issue
|
|
81
|
+
build_simple_diagnosis_report(
|
|
82
|
+
title: "Erro Inesperado",
|
|
83
|
+
message: "Ocorreu um erro não catalogado. Verifique o stack trace para mais detalhes."
|
|
84
|
+
)
|
|
85
|
+
end
|
|
46
86
|
end
|
|
47
|
-
html_content = case @data[:triage_result]
|
|
48
|
-
when :locator_issue
|
|
49
|
-
build_full_report
|
|
50
|
-
when :unidentified_locator_issue, :unidentified_timeout_issue
|
|
51
|
-
build_simple_diagnosis_report(
|
|
52
|
-
title: "Seletor Não Identificado",
|
|
53
|
-
message: "A falha ocorreu porque um elemento não foi encontrado, mas a GEM não conseguiu extrair o seletor exato da mensagem de erro ou do código-fonte. Isso geralmente acontece quando o seletor é construído dinamicamente ou está dentro de um método helper complexo. Verifique o stack trace para encontrar o método responsável (ex: 'tap_by_text')."
|
|
54
|
-
)
|
|
55
|
-
when :assertion_failure
|
|
56
|
-
build_simple_diagnosis_report(
|
|
57
|
-
title: "Falha de Asserção (Bug Funcional)",
|
|
58
|
-
message: "A automação executou os passos corretamente, mas o resultado final verificado na tela não foi o esperado. Isso geralmente indica um bug funcional na aplicação, e não um problema com o seletor."
|
|
59
|
-
)
|
|
60
|
-
when :visibility_issue
|
|
61
|
-
build_simple_diagnosis_report(
|
|
62
|
-
title: "Elemento Oculto ou Não-Interagível",
|
|
63
|
-
message: "O seletor encontrou o elemento no XML da página, mas ele não está visível ou habilitado para interação. Verifique se há outros elementos sobrepondo-o, se ele está desabilitado (disabled/enabled='false'), ou se é necessário aguardar uma animação."
|
|
64
|
-
)
|
|
65
|
-
when :stale_element_issue
|
|
66
|
-
build_simple_diagnosis_report(
|
|
67
|
-
title: "Referência de Elemento Antiga (Stale)",
|
|
68
|
-
message: "O elemento foi encontrado, mas a página foi atualizada antes que a interação pudesse ocorrer. Isso é um problema de timing. A solução é encontrar o elemento novamente logo antes de interagir com ele."
|
|
69
|
-
)
|
|
70
|
-
when :session_startup_issue
|
|
71
|
-
build_simple_diagnosis_report(
|
|
72
|
-
title: "Falha na Conexão com o Servidor Appium",
|
|
73
|
-
message: "Não foi possível criar uma sessão com o servidor. Verifique se o servidor Appium está rodando, se as 'capabilities' (incluindo prefixos 'appium:') e a URL de conexão estão corretas."
|
|
74
|
-
)
|
|
75
|
-
when :app_crash_issue
|
|
76
|
-
build_simple_diagnosis_report(
|
|
77
|
-
title: "Crash do Aplicativo",
|
|
78
|
-
message: "A sessão foi encerrada inesperadamente, o que indica que o aplicativo travou. A causa raiz deve ser investigada nos logs do dispositivo (Logcat para Android, Console para iOS)."
|
|
79
|
-
)
|
|
80
|
-
else # :ruby_code_issue, :unknown_issue
|
|
81
|
-
build_simple_diagnosis_report(
|
|
82
|
-
title: "Erro no Código de Teste",
|
|
83
|
-
message: "A falha foi causada por um erro de sintaxe ou lógica no próprio código de automação (ex: método não definido, variável nula). O problema não é no Appium ou no seletor, mas sim no script. Verifique o stack trace para encontrar o arquivo e a linha exatos."
|
|
84
|
-
)
|
|
85
|
-
end
|
|
86
87
|
|
|
87
88
|
File.write("#{@output_folder}/report_#{@data[:timestamp]}.html", html_content)
|
|
88
89
|
end
|