appium_failure_helper 1.1.7 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a20ff6bfd04e9343504f2718b569ff4872a4e8a398d9dd9952f4da57c70b4395
4
- data.tar.gz: 3cf66ebae97ae64bd6dce35b35279834fa86f31c46d00c6a5df7948e990a6ea1
3
+ metadata.gz: 58d069ff8c960c6fc6f012dc6990bce28cffce23f50e4152dae22cabfdb27deb
4
+ data.tar.gz: '06659b00652b380f0e8f77a10d8d6e024cb80df00e01b2b59a80f8921865819f'
5
5
  SHA512:
6
- metadata.gz: 96ea0be769224f562be575f06fdb0a75ceeb53379c1a0b587fb7085404e06c8315e4ebb81e08a8e53d5f2ee7c18c4a08b7e5f91de421520f62ec780a4f0c2b16
7
- data.tar.gz: e95f63b9cf6f5079da73a32d10260f319960b689e3abc0691282b8f830cb8abc4e69be0e2d2c14008d9846a6bb719529cc6b46a8da7e0d9f1b080c1ee07a2ee9
6
+ metadata.gz: '09ec8522e2732b4c8c9a044b551aabe0ba5890af4b8494c0872ccf680dd10909abcb4ad0e550f9bcfa2eeb600fb4a2a913d0494393b58c05e5c7b2254cded9a1'
7
+ data.tar.gz: 022c5386083b49e772e4a1d6147980ef1786e3a039ed882fe0f9f1300ffd8ff310259f55062d2a1820003a3a93efa8d2ab43bf48c840f4c9442454b2dcd44d89
data/README.md CHANGED
@@ -1,28 +1,28 @@
1
- # Diagnóstico Inteligente de Falhas Appium
1
+ # Appium Failure Helper: Diagnóstico Inteligente de Falhas
2
2
 
3
3
  ![Build Status](https://img.shields.io/badge/build-passing-brightgreen)
4
- ![Gem Version](https://img.shields.io/badge/gem-v1.1.0-blue)
4
+ ![Gem Version](https://img.shields.io/badge/gem-v3.0.0-blue)
5
5
  ![License](https://img.shields.io/badge/license-MIT-lightgrey)
6
6
 
7
- Uma ferramenta robusta para diagnosticar falhas em testes automatizados com Appium, transformando erros de `NoSuchElementException` em relatórios interativos e inteligentes. Chega de perder tempo depurando seletores quebrados; deixe que a análise automatizada faça o trabalho pesado por você.
7
+ Uma GEM de diagnóstico para testes Appium em Ruby, projetada para transformar falhas de automação em insights acionáveis. Quando um teste falha por não encontrar um elemento, esta ferramenta gera um relatório HTML detalhado, identificando a causa provável do erro e acelerando drasticamente o tempo de depuração.
8
8
 
9
9
  ## ✨ Principais Funcionalidades
10
10
 
11
- * **Relatório HTML Interativo:** Gera um relatório visual completo a cada falha, com screenshot, análise detalhada e dump de todos os elementos da tela.
12
- * **Análise de Mapeamento ("De/Para"):** Verifica automaticamente se o elemento que falhou está definido em alguma fonte de dados do projeto, como:
13
- * **Arquivos `.yaml`** gerados dinamicamente.
14
- * **Arquivos de elementos Ruby (`.rb`)** customizáveis.
15
- * **Sugestão por Similaridade:** Utiliza o algoritmo de Levenshtein para encontrar elementos na tela que são "parecidos" com o localizador que falhou, sugerindo correções.
16
- * **Altamente Configurável:** Permite que os projetos definam seus próprios caminhos e nomes de arquivos de elementos, tornando a ferramenta totalmente reutilizável.
17
- * **Arquitetura Modular:** O código é limpo, organizado e fácil de estender, seguindo o Princípio da Responsabilidade Única.
18
- * **Suporte Multiplataforma:** A lógica de análise e sugestão funciona tanto para **Android** quanto para **iOS**.
11
+ * **Diagnóstico por Triagem de Erros:** Identifica inteligentemente o *tipo* de falha (`NoSuchElementError`, `TimeoutError`, `Erro de Código Ruby`, `Falha de Asserção`, etc.) e gera um relatório específico e útil para cada cenário.
12
+ * **Análise de Código-Fonte:** Para erros "silenciosos" (onde a mensagem não contém o seletor), a GEM inspeciona o `stack trace` para encontrar o arquivo e a linha exatos do erro, extraindo o seletor diretamente do código-fonte.
13
+ * **Análise de Atributos Ponderados:** Em vez de uma simples comparação de strings, a GEM "desmonta" o seletor que falhou e o compara atributo por atributo com os elementos na tela, dando pesos diferentes para `resource-id`, `text`, etc., para encontrar o "candidato mais provável".
14
+ * **Relatórios Ricos e Interativos:** Gera um relatório HTML completo com:
15
+ * Screenshot da falha.
16
+ * Diagnóstico claro da causa provável, com sugestões acionáveis.
17
+ * Abas com "Análise Avançada" e um "Dump Completo" de todos os elementos da tela.
18
+ * **Altamente Configurável:** Permite a customização de caminhos para se adaptar a diferentes estruturas de projeto.
19
19
 
20
20
  ## 🚀 Instalação
21
21
 
22
22
  Adicione esta linha ao `Gemfile` do seu projeto de automação:
23
23
 
24
24
  ```ruby
25
- gem 'appium_failure_helper' # (ou o nome que você der para a sua gem)
25
+ gem 'appium_failure_helper', git: 'URL_DO_SEU_REPOSITORIO_GIT' # Exemplo de instalação via Git
26
26
  ```
27
27
 
28
28
  E então execute no seu terminal:
@@ -31,106 +31,107 @@ E então execute no seu terminal:
31
31
  bundle install
32
32
  ```
33
33
 
34
- ## ⚙️ Configuração (Opcional)
34
+ ## 🛠️ Uso e Configuração
35
35
 
36
- Para tornar a ferramenta flexível e adaptável a diferentes projetos, você pode configurar os caminhos onde os elementos são buscados. Crie um bloco de configuração no seu arquivo de inicialização (ex: `features/support/env.rb`).
36
+ A integração ideal envolve 3 passos:
37
37
 
38
- **Se nenhuma configuração for fornecida, a ferramenta usará os valores padrão.**
38
+ ### Passo 1: Configurar a GEM (Opcional)
39
+
40
+ No seu arquivo de inicialização (ex: `features/support/env.rb`), carregue a GEM e, se necessário, configure os caminhos onde seus elementos estão mapeados. Se nenhuma configuração for fornecida, a ferramenta usará os valores padrão.
39
41
 
40
42
  ```ruby
41
- # Em features/support/env.rb
43
+ # features/support/env.rb
44
+ require 'appium_failure_helper'
42
45
 
43
46
  AppiumFailureHelper.configure do |config|
44
- # Caminho para a pasta que contém os arquivos de elementos.
45
47
  # Padrão: 'features/elements'
46
48
  config.elements_path = 'caminho/para/sua/pasta/de/elementos'
47
49
 
48
- # Nome do arquivo principal de elementos Ruby.
49
50
  # Padrão: 'elementLists.rb'
50
51
  config.elements_ruby_file = 'meu_arquivo_de_elementos.rb'
51
52
  end
52
53
  ```
53
54
 
54
- ### Opções Disponíveis
55
-
56
- | Parâmetro | Descrição | Valor Padrão |
57
- | --------------------- | ------------------------------------------------------------------------------ | ------------------------ |
58
- | `elements_path` | Path relativo à raiz do projeto para a pasta que contém os arquivos de elementos. | `'features/elements'` |
59
- | `elements_ruby_file` | Nome do arquivo Ruby principal que define os elementos dentro da `elements_path`. | `'elementLists.rb'` |
60
-
61
- ## 🛠️ Uso no Cucumber
55
+ ### Passo 2: Enriquecer as Exceções (Altamente Recomendado)
62
56
 
63
- A integração é feita através de um hook `After` no seu ambiente de testes.
57
+ Para que a GEM consiga extrair o máximo de detalhes de uma falha (especialmente de erros genéricos como `TimeoutError` ou `NoSuchElementError` sem detalhes), é crucial que a exceção que ela recebe seja rica em informações. A melhor maneira de garantir isso é ajustar seus métodos de busca de elementos.
64
58
 
65
- **Exemplo completo para `features/support/env.rb`:**
59
+ Crie ou ajuste um arquivo de helpers (ex: `features/support/appiumCustom.rb`) com a seguinte estrutura:
66
60
 
67
61
  ```ruby
68
- # features/support/env.rb
62
+ # features/support/appiumCustom.rb
69
63
 
70
- require 'appium_lib'
71
- require 'cucumber'
64
+ # Métodos públicos que seus Page Objects irão chamar
65
+ def find(el)
66
+ find_element_with_enriched_error(el)
67
+ end
72
68
 
73
- # 1. Carrega a sua ferramenta
74
- require 'appium_failure_helper'
69
+ def clickElement(el)
70
+ find_element_with_enriched_error(el).click
71
+ end
75
72
 
76
- # 2. (Opcional) Configura os caminhos se forem diferentes do padrão
77
- AppiumFailureHelper.configure do |config|
78
- config.elements_path = 'features/elements'
79
- config.elements_ruby_file = 'elementLists.rb'
73
+ def waitForElementExist(el, timeout = 10)
74
+ wait = Selenium::WebDriver::Wait.new(timeout: timeout)
75
+ begin
76
+ wait.until { $driver.find_elements(el['tipoBusca'], el['value']).size > 0 }
77
+ rescue Selenium::WebDriver::Error::TimeoutError => e
78
+ # Relança o erro com uma mensagem rica que a GEM entende
79
+ new_message = "Timeout de #{timeout}s esperando pelo elemento: using \"#{el['tipoBusca']}\" with value \"#{el['value']}\""
80
+ raise e.class, new_message
81
+ end
80
82
  end
81
83
 
82
- # 3. Hook que executa após cada cenário de teste
83
- After do |scenario|
84
- # Se o cenário falhou, aciona o seu helper
85
- if scenario.failed?
86
- puts "\n--- CENÁRIO FALHOU! ACIONANDO O DIAGNÓSTICO INTELIGENTE ---"
87
-
88
- # A chamada ao helper utiliza automaticamente as configurações definidas acima.
89
- AppiumFailureHelper.handler_failure(@driver, scenario.exception)
84
+ private # --- Helper Interno ---
85
+
86
+ # Este método é o coração da solução. Ele captura erros e os enriquece.
87
+ def find_element_with_enriched_error(el)
88
+ begin
89
+ return $driver.find_element(el['tipoBusca'], el['value'])
90
+ rescue Selenium::WebDriver::Error::NoSuchElementError => e
91
+ # Cria uma nova mensagem explícita no formato "using... with value..."
92
+ new_message = "using \"#{el['tipoBusca']}\" with value \"#{el['value']}\""
90
93
 
91
- puts "--- HELPER FINALIZOU. VERIFIQUE A PASTA 'reports_failure' ---"
94
+ # Recria a exceção original com a nova mensagem.
95
+ new_exception = e.class.new(new_message)
96
+ new_exception.set_backtrace(e.backtrace) # Preserva o stack trace
97
+ raise new_exception
92
98
  end
93
99
  end
94
100
  ```
95
101
 
96
- ## 📄 Entendendo o Relatório Gerado
102
+ ### Passo 3: Integrar com o Cucumber
97
103
 
98
- Após uma falha, uma nova pasta será criada na raiz do seu projeto: `reports_failure/failure_[timestamp]`. Dentro dela, o arquivo mais importante é o `report_[...].html`.
104
+ Finalmente, no seu `hooks.rb`, acione a GEM no hook `After` em caso de falha.
99
105
 
100
- O relatório HTML é dividido em seções claras para um diagnóstico rápido:
106
+ ```ruby
107
+ # features/support/hooks.rb
101
108
 
102
- #### Análise de Mapeamento (Bloco Verde/Amarelo)
103
- Informa se o elemento que falhou foi encontrado nos seus arquivos de mapeamento (`.rb` ou `.yaml`).
104
- * **Bloco Verde (Sucesso):** Confirma que o elemento foi encontrado. Isso sugere que a definição está correta, e o problema pode ser de timing ou visibilidade na tela.
105
- * **Bloco Amarelo (Aviso):** Informa que o elemento **não foi encontrado**. Isso geralmente aponta para um erro de digitação no nome do elemento no seu código de teste.
109
+ After do |scenario|
110
+ if scenario.failed? && $driver&.session_id
111
+ AppiumFailureHelper.handler_failure($driver, scenario.exception)
112
+ end
113
+ end
114
+ ```
106
115
 
107
- #### Elemento com Falha (Bloco Vermelho)
108
- Mostra exatamente qual `Tipo de Seletor` e `Valor Buscado` o Appium usou quando a falha ocorreu.
116
+ ## 📄 O Relatório Gerado
109
117
 
110
- #### Screenshot da Falha
111
- Uma imagem exata da tela no momento do erro.
118
+ A cada falha, uma nova pasta é criada em `reports_failure/`, contendo o relatório `.html` e outros artefatos. O relatório pode ter dois formatos principais:
112
119
 
113
- #### Sugestões de Reparo (Análise de Similaridade)
114
- Lista os elementos na tela com localizadores parecidos com o que falhou, com uma pontuação de similaridade. Ideal para corrigir erros de digitação nos seletores.
120
+ 1. **Relatório de Diagnóstico Simples:** Gerado para erros que não são de seletor (ex: falha de conexão, erro de código Ruby, falha de asserção). Ele mostra um diagnóstico direto, a mensagem de erro original e o `stack trace`.
115
121
 
116
- #### Dump Completo da Página
117
- Uma lista interativa de **todos os elementos** visíveis na tela, com todos os seus possíveis localizadores.
122
+ 2. **Relatório Detalhado (para problemas de seletor):**
123
+ * **Coluna da Esquerda:** Mostra o "Elemento com Falha" (extraído da exceção ou do código), "Sugestões Encontradas no Código" e o "Screenshot".
124
+ * **Coluna da Direita:** Contém abas interativas:
125
+ * **Análise Avançada:** Apresenta o "candidato mais provável" encontrado na tela e uma análise comparativa de seus atributos (`resource-id`, `text`, etc.), com uma sugestão acionável.
126
+ * **Dump Completo:** Uma lista de todos os elementos da tela e seus possíveis seletores.
118
127
 
119
128
  ## 🏛️ Arquitetura do Código
120
129
 
121
- O código é modular para facilitar a manutenção e a extensibilidade.
122
-
123
- * `configuration.rb`: Classe que armazena as opções configuráveis e seus valores padrão.
124
- * `handler.rb`: O **Maestro**. Orquestra as chamadas para os outros módulos.
125
- * `analyzer.rb`: O **Analista**. Processa a mensagem de erro e calcula a similaridade.
126
- * `element_repository.rb`: O **Repositório**. Encontra e carrega as definições de elementos de arquivos `.yaml` e `.rb` usando os caminhos configurados.
127
- * `page_analyzer.rb`: O **Leitor de Tela**. Processa o XML da página para extrair elementos e sugerir nomes/localizadores.
128
- * `report_generator.rb`: O **Gerador**. Consolida todos os dados e cria os arquivos de relatório.
129
- * `utils.rb`: Funções auxiliares (Logger, etc.).
130
+ A GEM é dividida em módulos com responsabilidades únicas para facilitar a manutenção e a extensibilidade (Handler, Analyzer, ReportGenerator, XPathFactory, etc.).
130
131
 
131
132
  ## 🤝 Como Contribuir
132
133
 
133
- Encontrou um bug ou tem uma ideia para uma nova funcionalidade? Abra uma *Issue* no repositório do projeto. Pull Requests são sempre bem-vindos!
134
+ Pull Requests são bem-vindos. Para bugs ou sugestões, por favor, abra uma *Issue* no repositório.
134
135
 
135
136
  ## 📜 Licença
136
137
 
@@ -1,3 +1,4 @@
1
+ # lib/appium_failure_helper/handler.rb
1
2
  module AppiumFailureHelper
2
3
  class Handler
3
4
  def self.call(driver, exception)
@@ -20,13 +21,21 @@ module AppiumFailureHelper
20
21
 
21
22
  FileUtils.mkdir_p(@output_folder)
22
23
 
24
+ # --- DIAGNÓSTICO ADICIONADO AQUI ---
25
+ puts "\n--- DEBUG DE CAPABILITIES ---"
26
+ puts "Classe do Driver: #{@driver.class}"
27
+ puts "Conteúdo de @driver.capabilities:"
28
+ puts @driver.capabilities.inspect
29
+ puts "-----------------------------\n"
30
+ # ------------------------------------
31
+
23
32
  triage_result = Analyzer.triage_error(@exception)
24
33
 
25
34
  report_data = {
26
35
  exception: @exception,
27
36
  triage_result: triage_result,
28
37
  timestamp: @timestamp,
29
- platform: @driver.capabilities['platformName'] || @driver.capabilities[:platformName] || 'unknown',
38
+ platform: @driver.capabilities['platformName'] || @driver.capabilities[:platform_name] || 'unknown',
30
39
  screenshot_base64: @driver.screenshot_as(:base64)
31
40
  }
32
41
 
@@ -59,14 +59,18 @@ module AppiumFailureHelper
59
59
  screenshot_base64 = @data[:screenshot_base64]
60
60
 
61
61
  locators_html = lambda do |locators|
62
- (locators || []).map { |loc| "<li class='flex justify-between items-center bg-gray-50 p-2 rounded-md mb-1 text-xs font-mono'><span class='font-bold text-indigo-600'>#{CGI.escapeHTML(loc[:strategy].to_s.upcase.gsub('_', ' '))}:</span><span class='text-gray-700 ml-2 overflow-auto max-w-[70%]'>#{CGI.escapeHTML(loc[:locator])}</span></li>" }.join
62
+ (locators || []).map do |loc|
63
+ strategy_text = loc[:strategy].to_s.upcase.gsub('_', ' ')
64
+ "<li class='flex justify-between items-center bg-gray-50 p-2 rounded-md mb-1 text-xs font-mono'><span class='font-bold text-indigo-600'>#{CGI.escapeHTML(strategy_text)}:</span><span class='text-gray-700 ml-2 overflow-auto max-w-[70%]'>#{CGI.escapeHTML(loc[:locator])}</span></li>"
65
+ end.join
63
66
  end
64
67
 
65
68
  all_elements_html = lambda do |elements|
66
69
  (elements || []).map { |el| "<details class='border-b border-gray-200 py-3'><summary class='font-semibold text-sm text-gray-800 cursor-pointer'>#{CGI.escapeHTML(el[:name])}</summary><ul class='text-xs space-y-1 mt-2'>#{locators_html.call(el[:locators])}</ul></details>" }.join
67
70
  end
68
71
 
69
- de_para_html = "" # (Sua lógica de_para_html)
72
+ failed_info_content = "<p class='text-sm text-gray-700 font-medium mb-2'>Tipo de Seletor: <span class='font-mono text-xs bg-red-100 p-1 rounded'>#{CGI.escapeHTML(failed_info[:selector_type].to_s)}</span></p><p class='text-sm text-gray-700 font-medium'>Valor Buscado: <span class='font-mono text-xs bg-red-100 p-1 rounded break-all'>#{CGI.escapeHTML(failed_info[:selector_value].to_s)}</span></p>"
73
+
70
74
  code_search_html = "" # (Sua lógica code_search_html)
71
75
  failed_info_content = if failed_info && !failed_info.empty?
72
76
  "<p class='text-sm text-gray-700 font-medium mb-2'>Tipo de Seletor: <span class='font-mono text-xs bg-red-100 p-1 rounded'>#{CGI.escapeHTML(failed_info[:selector_type].to_s)}</span></p><p class='text-sm text-gray-700 font-medium'>Valor Buscado: <span class='font-mono text-xs bg-red-100 p-1 rounded break-all'>#{CGI.escapeHTML(failed_info[:selector_value].to_s)}</span></p>"
@@ -78,20 +82,9 @@ module AppiumFailureHelper
78
82
  unless code_search_results.empty?
79
83
  suggestions_list = code_search_results.map do |match|
80
84
  score_percent = (match[:score] * 100).round(1)
81
- <<~SUGGESTION
82
- <div class='border border-sky-200 bg-sky-50 p-3 rounded-lg mb-2'>
83
- <p class='text-sm text-gray-600'>Encontrado em: <strong class='font-mono'>#{match[:file]}:#{match[:line_number]}</strong></p>
84
- <pre class='bg-gray-800 text-white p-2 rounded mt-2 text-xs overflow-auto'><code>#{CGI.escapeHTML(match[:code])}</code></pre>
85
- <p class='text-xs text-green-600 mt-1'>Similaridade: #{score_percent}%</p>
86
- </div>
87
- SUGGESTION
85
+ "<div class='border border-sky-200 bg-sky-50 p-3 rounded-lg mb-2'><p class='text-sm text-gray-600'>Encontrado em: <strong class='font-mono'>#{match[:file]}:#{match[:line_number]}</strong></p><pre class='bg-gray-800 text-white p-2 rounded mt-2 text-xs overflow-auto'><code>#{CGI.escapeHTML(match[:code])}</code></pre><p class='text-xs text-green-600 mt-1'>Similaridade: #{score_percent}%</p></div>"
88
86
  end.join
89
- code_search_html = <<~HTML
90
- <div class="bg-white p-4 rounded-lg shadow-md">
91
- <h2 class="text-xl font-bold text-sky-700 mb-4">Sugestões Encontradas no Código</h2>
92
- #{suggestions_list}
93
- </div>
94
- HTML
87
+ code_search_html = "<div class='bg-white p-4 rounded-lg shadow-md'><h2 class='text-xl font-bold text-sky-700 mb-4'>Sugestões Encontradas no Código</h2>#{suggestions_list}</div>"
95
88
  end
96
89
 
97
90
  # --- LÓGICA RESTAURADA: ELEMENTO COM FALHA ---
@@ -211,7 +204,7 @@ module AppiumFailureHelper
211
204
  <div class="p-6">
212
205
  <div id="strategies" class="tab-content active">
213
206
  <h3 class="text-lg font-semibold text-indigo-700 mb-4">Estratégias de Localização Alternativas</h3>
214
- #{repair_strategies_content}
207
+ #{repair_suggestions_content}
215
208
  </div>
216
209
  <div id="all" class="tab-content">
217
210
  <h3 class="text-lg font-semibold text-gray-700 mb-4">Dump de Todos os Elementos da Tela</h3>
@@ -1,3 +1,3 @@
1
1
  module AppiumFailureHelper
2
- VERSION = "1.1.7"
2
+ VERSION = "1.2.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appium_failure_helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.7
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Nascimento