appium_failure_helper 0.6.5 → 0.6.7

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: 3024e8a372bc176bf6cef94cb09c5b2b5a600e53eec962cd807a06be9395a1b2
4
- data.tar.gz: 9b91df8d5b51bd21f96af520bf34cc278dc3b6394f307cad49d8b5a5eed70206
3
+ metadata.gz: 5d5d4f2b54142887b1306f844740130498cf86d84a98146539e3c881ade117ad
4
+ data.tar.gz: f42ba2c9bc3c33005613702381b5974475064d22e69a0978bd3f63b0ccaa4dde
5
5
  SHA512:
6
- metadata.gz: a73b5802a489a02f7df1a8b22d43e922c412915782812a55b6114f98dbe352e0d628bc2658c39194e3ff5821cfd383838afe8c80623c94610831c1e52ffa9bee
7
- data.tar.gz: f514dab139cadd44652ae4f0ec2721283e47755a0195b964008ebeb931fcc156ab5babd37d96b39f90efd921b3291c7598877e0c6b9fde8290831c4425768f6b
6
+ metadata.gz: aadc9e9fa50c1d543eac38ae98da69d63353f9824916fe5c03cacc48baa3bfa359a987213f9eb53f719eeff2457cc2e8d5a785d106066548eeb4213c1d2e45da
7
+ data.tar.gz: 37f7783e098caae647c356a089221c7f903871c485523f8e804afa86966b830394f6f1d54b6ee22b142d11f3e938f54c4fbe635e0fec788c8e90ae7e822c5361
data/README.md CHANGED
@@ -1,290 +1,137 @@
1
- # Appium Failure Helper
1
+ # Diagnóstico Inteligente de Falhas Appium
2
2
 
3
- [![Ruby](https://img.shields.io/badge/language-ruby-red.svg)](https://www.ruby-lang.org/)
4
- [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
- [![Status](https://img.shields.io/badge/status-beta-yellow.svg)]()
3
+ ![Build Status](https://img.shields.io/badge/build-passing-brightgreen)
4
+ ![Gem Version](https://img.shields.io/badge/gem-v1.1.0-blue)
5
+ ![License](https://img.shields.io/badge/license-MIT-lightgrey)
6
6
 
7
- **Appium Failure Helper** é um módulo Ruby destinado a automatizar diagnóstico de falhas em testes de automação mobile com **Appium**. O objetivo é reduzir tempo de triagem, fornecer localizadores confiáveis e coletar artefatos de depuração sem depender do Appium Inspector.
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ê.
8
8
 
9
- ---
9
+ ## ✨ Principais Funcionalidades
10
10
 
11
- ## Sumário
12
- - [Visão Geral](#visão-geral)
13
- - [Funcionalidades](#funcionalidades)
14
- - [Arquitetura e Fluxo](#arquitetura-e-fluxo)
15
- - [Instalação](#instalação)
16
- - [Configuração (opcional)](#configuração-opcional)
17
- - [API Pública / Integração](#api-pública--integração)
18
- - [Exemplos de Uso](#exemplos-de-uso)
19
- - [Cucumber (hook After)](#cucumber-hook-after)
20
- - [RSpec (after :each)](#rspec-after-each)
21
- - [Formato dos Artefatos Gerados](#formato-dos-artefatos-gerados)
22
- - [Lógica de Geração de XPaths (detalhada)](#lógica-de-geração-de-xpaths-detalhada)
23
- - [Tratamento de Dados e Deduplicação](#tratamento-de-dados-e-deduplicação)
24
- - [Relatório HTML Interativo](#relatório-html-interativo)
25
- - [Logging e Observabilidade](#logging-e-observabilidade)
26
- - [Testes e Qualidade](#testes-e-qualidade)
27
- - [Roadmap e Contribuição](#roadmap-e-contribuição)
28
- - [Licença](#licença)
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**.
29
19
 
30
- ---
20
+ ## 🚀 Instalação
31
21
 
32
- ## Visão Geral
33
-
34
- No momento em que um teste falha, o módulo realiza, de forma atômica e thread-safe:
35
- 1. captura de screenshot,
36
- 2. extração do `page_source` completo (XML),
37
- 3. varredura da árvore de elementos para gerar localizadores sugeridos,
38
- 4. escrita de dois YAMLs (focado e completo) e um relatório HTML que agrega tudo.
39
-
40
- Todos os artefatos são salvos em uma pasta timestamped (formato `YYYY_MM_DD_HHMMSS`) dentro de `reports_failure/`.
41
-
42
- ---
43
-
44
- ## Funcionalidades
45
-
46
- - Captura automática de screenshot PNG.
47
- - Export completo de `page_source` em XML.
48
- - Geração de `failure_analysis_*.yaml` (focado no elemento que falhou).
49
- - Geração de `all_elements_dump_*.yaml` (todos os elementos com localizadores sugeridos).
50
- - Relatório HTML interativo que combine screenshot, XML formatado e lista de localizadores.
51
- - Geração de XPaths otimizados para **Android** e **iOS**.
52
- - Truncamento de atributos longos (configurável).
53
- - Eliminação de elementos duplicados e normalização de atributos.
54
- - Logging via `Logger` do Ruby (Níveis: DEBUG/INFO/WARN/ERROR).
55
- - Configuração via bloco `configure` (opcional).
56
-
57
- ---
58
-
59
- ## Arquitetura e Fluxo
60
-
61
- 1. **Hook de Testes** (Cucumber/RSpec) → invoca `Capture.handler_failure(driver, exception)`
62
- 2. **Capture.handler_failure**:
63
- - estabelece pasta de saída com timestamp;
64
- - chama `driver.screenshot` (salva PNG);
65
- - chama `driver.page_source` (salva XML);
66
- - percorre XML e cria árvore de elementos;
67
- - para cada elemento gera candidate XPaths aplicando regras por plataforma;
68
- - grava `failure_analysis_*.yaml` (prioriza elemento indicado) e `all_elements_dump_*.yaml`;
69
- - monta `report_*.html` agregando tudo.
70
- 3. Logs detalhados emitidos durante a execução.
71
-
72
- ---
73
-
74
- ## Instalação
75
-
76
- **Como gem (exemplo):**
77
-
78
- Adicione ao `Gemfile` do projeto:
22
+ Adicione esta linha ao `Gemfile` do seu projeto de automação:
79
23
 
80
24
  ```ruby
81
- gem 'appium_failure_helper', '~> 0.1.0'
25
+ gem 'appium_failure_helper' # (ou o nome que você der para a sua gem)
82
26
  ```
83
27
 
84
- Depois:
28
+ E então execute no seu terminal:
85
29
 
86
- ```bash
30
+ ```sh
87
31
  bundle install
88
32
  ```
89
33
 
90
- **Ou manual (para uso local):**
34
+ ## ⚙️ Configuração (Opcional)
91
35
 
92
- Coloque o diretório `appium_failure_helper/` dentro do `lib/` do projeto e faça:
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`).
93
37
 
94
- ```ruby
95
- require_relative 'lib/appium_failure_helper'
96
- ```
97
-
98
- ---
99
-
100
- ## API Pública / Integração
101
-
102
- ### `AppiumFailureHelper::Capture`
38
+ **Se nenhuma configuração for fornecida, a ferramenta usará os valores padrão.**
103
39
 
104
40
  ```ruby
105
- # handler_failure(driver, exception, options = {})
106
- # - driver: objeto de sessão Appium (Selenium::WebDriver / Appium::Driver)
107
- # - exception: exceção capturada no momento da falha
108
- # - options: hash com overrides (ex: output_dir:)
109
- AppiumFailureHelper::Capture.handler_failure(appium_driver, scenario.exception)
110
- ```
41
+ # Em features/support/env.rb
111
42
 
112
- ### Configuração global
43
+ AppiumFailureHelper.configure do |config|
44
+ # Caminho para a pasta que contém os arquivos de elementos.
45
+ # Padrão: 'features/elements'
46
+ config.elements_path = 'caminho/para/sua/pasta/de/elementos'
113
47
 
114
- ```ruby
115
- AppiumFailureHelper.configure do |c|
116
- # ver bloco de configuração acima
48
+ # Nome do arquivo principal de elementos Ruby.
49
+ # Padrão: 'elementLists.rb'
50
+ config.elements_ruby_file = 'meu_arquivo_de_elementos.rb'
117
51
  end
118
52
  ```
119
53
 
120
- ---
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
121
62
 
122
- ## Exemplos de Uso
63
+ A integração é feita através de um hook `After` no seu ambiente de testes.
123
64
 
124
- ### Cucumber (hook `After`)
65
+ **Exemplo completo para `features/support/env.rb`:**
125
66
 
126
67
  ```ruby
127
- # features/support/hooks.rb
68
+ # features/support/env.rb
69
+
70
+ require 'appium_lib'
71
+ require 'cucumber'
72
+
73
+ # 1. Carrega a sua ferramenta
128
74
  require 'appium_failure_helper'
129
75
 
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'
80
+ end
81
+
82
+ # 3. Hook que executa após cada cenário de teste
130
83
  After do |scenario|
84
+ # Se o cenário falhou, aciona o seu helper
131
85
  if scenario.failed?
132
- AppiumFailureHelper::Capture.handler_failure(appium_driver, scenario.exception)
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)
90
+
91
+ puts "--- HELPER FINALIZOU. VERIFIQUE A PASTA 'reports_failure' ---"
133
92
  end
134
93
  end
135
94
  ```
136
95
 
137
- ---
138
-
139
- ## Formato dos Artefatos Gerados
140
-
141
- **Pasta:** `reports_failure/<TIMESTAMP>/`
142
-
143
- Arquivos gerados (ex.: TIMESTAMP = `2025_09_23_173045`):
144
-
145
- ```
146
- screenshot_2025_09_23_173045.png
147
- page_source_2025_09_23_173045.xml
148
- failure_analysis_2025_09_23_173045.yaml
149
- all_elements_dump_2025_09_23_173045.yaml
150
- report_2025_09_23_173045.html
151
- ```
152
-
153
- ### Exemplo (simplificado) de `failure_analysis_*.yaml`
154
-
155
- ```yaml
156
- failed_element:
157
- platform: android
158
- summary:
159
- class: android.widget.Button
160
- resource_id: com.example:id/submit
161
- text: "Enviar"
162
- suggested_xpaths:
163
- - "//android.widget.Button[@resource-id='com.example:id/submit']"
164
- - "//android.widget.Button[contains(@text,'Enviar')]"
165
- capture_metadata:
166
- screenshot: screenshot_2025_09_23_173045.png
167
- page_source: page_source_2025_09_23_173045.xml
168
- timestamp: "2025-09-23T17:30:45Z"
169
- tips: "Priorize resource-id; se ausente, use accessibility id (content-desc) e class+text como fallback."
170
- ```
171
-
172
- ### Exemplo (simplificado) de `all_elements_dump_*.yaml`
173
-
174
- ```yaml
175
- elements:
176
- - id_hash: "a1b2c3..."
177
- class: "android.widget.EditText"
178
- resource_id: "com.example:id/input_email"
179
- text: "example@example.com"
180
- truncated_attributes:
181
- hint: "Digite seu e-mail..."
182
- suggested_xpaths:
183
- - "//*[@resource-id='com.example:id/input_email']"
184
- - "//android.widget.EditText[contains(@hint,'Digite seu e-mail')]"
185
- ```
186
-
187
- ---
188
-
189
- ## Lógica de Geração de XPaths (detalhada)
190
-
191
- **Princípios gerais**
192
- 1. Priorizar identificadores estáveis (resource-id no Android / accessibility id no iOS).
193
- 2. Evitar XPaths com `index` como primeira opção (usado apenas como último recurso).
194
- 3. Combinar atributos quando necessário para aumentar a especificidade e evitar colisões.
195
- 4. Normalizar espaços e truncar textos longos.
196
-
197
- **Estratégias por plataforma (ordem de preferência)**
198
-
199
- - **Android**
200
- 1. `resource-id` → `//*[@resource-id='com.pkg:id/id']`
201
- 2. `content-desc` / `contentDescription` (accessibility) → `//*[@content-desc='x']`
202
- 3. `class` + `text` → `//android.widget.TextView[@class='...' and contains(normalize-space(@text),'...')]`
203
- 4. `class` + raça de atributos (combinações: enabled, clickable, package)
204
- 5. fallback: `//android.widget.Button[position()=n]` (último recurso)
205
-
206
- - **iOS**
207
- 1. `accessibility id` (nome accessibility) → `//*[@name='Submit']`
208
- 2. `label` / `value` → `//*[contains(@label,'...')]`
209
- 3. `type` + `label` → `//XCUIElementTypeButton[@label='OK']`
210
- 4. fallback: hierarquia / indices
211
-
212
- **Exemplo de XPath combinado (alta especificidade):**
213
-
214
- ```xpath
215
- //android.widget.Button[@resource-id='com.example:id/submit' and contains(normalize-space(@text),'Enviar') and @clickable='true']
216
- ```
217
-
218
- ---
219
-
220
- ## Tratamento de Dados e Deduplicação
221
-
222
- - **Truncamento**: atributos com comprimento acima de `attr_truncate_length` são truncados com sufixo `...` para evitar poluição do YAML.
223
- - **Hash único por elemento**: é gerado um hash (sha1) baseado em conjunto de atributos relevantes (class+resource-id+content-desc+text) para identificar duplicados.
224
- - **Remoção de nulos**: atributos vazios ou nulos são omitidos nos YAMLs.
225
- - **Ordenação**: elementos no `all_elements_dump` são ordenados por prioridade de localizador (resource-id primeiro).
226
-
227
- ---
228
-
229
- ## Relatório HTML Interativo
230
-
231
- O HTML gerado possui:
232
- - Visualização inline do `screenshot` (img tag),
233
- - Painel colapsável com o `page_source` (XML formatado e collapsible),
234
- - Lista navegável de elementos com seus `suggested_xpaths` (botões para copiar),
235
- - Ancoragem que permite focalizar: ao clicar em um XPath, realça o fragmento correspondente no XML (se possível),
236
- - Metadados e link rápido para os YAMLs.
237
-
238
- **Observação:** o HTML é gerado de forma estática — para realces dinâmicos é usado JavaScript simples embutido (sem dependências externas).
239
-
240
- ---
241
-
242
- ## Logging e Observabilidade
243
-
244
- - Usa `Logger` padrão do Ruby:
245
- - `DEBUG` para detalhamento completo (padrão em modo dev).
246
- - `INFO` para resumo das ações realizadas.
247
- - `WARN/ERROR` para problemas durante captura/escrita.
248
- - Exemplos de mensagens:
249
- - `[INFO] Creating failure report folder: reports_failure/2025_09_23_173045`
250
- - `[DEBUG] Captured 4123 elements from page_source`
251
- - `[ERROR] Failed to write screenshot: Permission denied`
96
+ ## 📄 Entendendo o Relatório Gerado
252
97
 
253
- ---
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`.
254
99
 
255
- ## Testes e Qualidade
100
+ O relatório HTML é dividido em seções claras para um diagnóstico rápido:
256
101
 
257
- - Estrutura de testes sugerida: RSpec + fixtures com dumps de `page_source` para validar a geração de XPaths.
258
- - Testes unitários para: truncamento, hash de deduplicação, geração de strategies, output YAML válido.
259
- - CI: incluir step que valide YAML/HTML gerados (lint) e execute testes RSpec.
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.
260
106
 
261
- ---
107
+ #### Elemento com Falha (Bloco Vermelho)
108
+ Mostra exatamente qual `Tipo de Seletor` e `Valor Buscado` o Appium usou quando a falha ocorreu.
262
109
 
263
- ## Roadmap e Contribuição
110
+ #### Screenshot da Falha
111
+ Uma imagem exata da tela no momento do erro.
264
112
 
265
- **Funcionalidades previstas**
266
- - Suporte a mapeamento visual (overlay) para apontar elemento sobre screenshot.
267
- - Export para outros formatos (JSON/CSV).
268
- - Integração com ferramentas de observabilidade (Sentry, Datadog).
269
- - Modo headless para gerar relatórios offline em pipelines.
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.
270
115
 
271
- **Como contribuir**
272
- 1. Fork no repositório.
273
- 2. Crie branch com feature/bugfix.
274
- 3. Abra PR com descrição técnica das mudanças e testes.
275
- 4. Mantenha o estilo Ruby (RuboCop) e documentação atualizada.
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.
276
118
 
277
- ---
119
+ ## 🏛️ Arquitetura do Código
278
120
 
279
- ## Segurança e Privacidade
121
+ O código é modular para facilitar a manutenção e a extensibilidade.
280
122
 
281
- - Evite capturar dados sensíveis em ambientes com PII. Implementar filtro por regex para mascarar dados (ex.: emails/telefones) antes de salvar YAMLs.
282
- - Recomendado: executar limpeza em ambientes de produção.
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.).
283
130
 
284
- ---
131
+ ## 🤝 Como Contribuir
285
132
 
286
- ## Licença
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!
287
134
 
288
- MIT veja o arquivo `LICENSE` para os termos.
135
+ ## 📜 Licença
289
136
 
290
- ---
137
+ Este projeto é distribuído sob a licença MIT.
@@ -0,0 +1,13 @@
1
+ module AppiumFailureHelper
2
+ class Configuration
3
+ # Define as opções que o usuário poderá configurar
4
+ attr_accessor :elements_path, :elements_ruby_file
5
+
6
+ def initialize
7
+ # Define os valores PADRÃO.
8
+ # Se o usuário não configurar nada, a GEM usará estes valores.
9
+ @elements_path = 'features/elements'
10
+ @elements_ruby_file = 'elementLists.rb'
11
+ end
12
+ end
13
+ end
@@ -1,49 +1,57 @@
1
1
  module AppiumFailureHelper
2
2
  module ElementRepository
3
+
4
+ def self.load_all
5
+ elements_map = load_from_ruby_file
6
+ elements_map.merge!(load_all_from_yaml)
7
+ elements_map
8
+ end
9
+
10
+ private
11
+
12
+ def self.load_from_ruby_file
13
+ map = {}
14
+ # ALTERADO: Lê os caminhos a partir da configuração central.
15
+ config = AppiumFailureHelper.configuration
16
+ file_path = File.join(Dir.pwd, config.elements_path, config.elements_ruby_file)
17
+
18
+ return map unless File.exist?(file_path)
19
+
20
+ # ... (o resto do método continua igual)
21
+ begin
22
+ require file_path
23
+ instance = OnboardingElementLists.new
24
+ unless instance.respond_to?(:elements)
25
+ Utils.logger.warn("AVISO: A classe OnboardingElementLists não expõe um `attr_reader :elements`.")
26
+ return map
27
+ end
28
+ instance.elements.each do |key, value|
29
+ map[key.to_s] = { 'tipoBusca' => value[0], 'valor' => value[1] }
30
+ end
31
+ rescue => e
32
+ Utils.logger.warn("AVISO: Erro ao processar o arquivo #{file_path}: #{e.message}")
33
+ end
34
+
35
+ map
36
+ end
37
+
3
38
  def self.load_all_from_yaml
4
39
  elements_map = {}
5
- # Procura em todo o diretório de trabalho atual por arquivos .yaml
6
- glob_path = File.join(Dir.pwd, '**', '*.yaml')
40
+ # ALTERADO: o caminho base da configuração central.
41
+ config = AppiumFailureHelper.configuration
42
+ glob_path = File.join(Dir.pwd, config.elements_path, '**', '*.yaml')
7
43
 
8
44
  Dir.glob(glob_path).each do |file|
9
- # Evita ler os próprios relatórios gerados
45
+ # ... (o resto do método continua igual) ...
10
46
  next if file.include?('reports_failure')
11
-
12
47
  begin
13
48
  data = YAML.load_file(file)
14
- if data.is_a?(Hash)
15
- data.each do |key, value|
16
- if value.is_a?(Hash) && value['tipoBusca'] && value['value']
17
- elements_map[key] = value
18
- end
19
- end
20
- end
49
+ elements_map.merge!(data) if data.is_a?(Hash)
21
50
  rescue => e
22
51
  Utils.logger.warn("Aviso: Erro ao carregar o arquivo YAML #{file}: #{e.message}")
23
52
  end
24
53
  end
25
54
  elements_map
26
55
  end
27
-
28
- # NOVO: Método para verificar a existência de um elemento em um arquivo .rb
29
- def self.find_in_ruby_file(element_name, path = 'elements/elements.rb')
30
- return { found: false, path: path, reason: "Arquivo não encontrado" } unless File.exist?(path)
31
-
32
- begin
33
- content = File.read(path)
34
- # Regex flexível para encontrar definições como:
35
- # def nome_do_elemento
36
- # element :nome_do_elemento
37
- # element('nome_do_elemento')
38
- if content.match?(/def #{element_name}|element[ |\(]['|:]#{element_name}/)
39
- return { found: true, path: path }
40
- else
41
- return { found: false, path: path, reason: "Definição não encontrada" }
42
- end
43
- rescue => e
44
- Utils.logger.warn("Aviso: Erro ao ler o arquivo Ruby #{path}: #{e.message}")
45
- return { found: false, path: path, reason: "Erro de leitura" }
46
- end
47
- end
48
56
  end
49
57
  end
@@ -29,20 +29,27 @@ module AppiumFailureHelper
29
29
  File.open("#{@output_folder}/all_elements_dump_#{@data[:timestamp]}.yaml", 'w') { |f| f.write(YAML.dump(@data[:all_page_elements])) }
30
30
  end
31
31
 
32
+ # --- MÉTODO CORRIGIDO COM A LÓGICA COMPLETA ---
32
33
  def generate_html_report
33
- # ... (Lambdas locators_html e all_elements_html permanecem iguais) ...
34
- locators_html = ->(locators) { locators.map { |loc| "..." }.join }
35
- all_elements_html = ->(elements) { elements.map { |el| "..." }.join }
36
-
37
- # Prepara o conteúdo dinâmico
34
+ # Prepara as variáveis a partir do hash de dados
38
35
  failed_info = @data[:failed_element]
39
36
  similar_elements = @data[:similar_elements]
37
+ all_suggestions = @data[:all_page_elements]
40
38
  de_para_yaml = @data[:de_para_yaml_analysis]
41
39
  de_para_rb = @data[:de_para_rb_analysis]
42
- all_suggestions = @data[:all_page_elements]
43
-
44
- # NOVO: Gera dois blocos de HTML, um para cada análise
40
+ timestamp = @data[:timestamp]
41
+ platform = @data[:platform]
42
+ screenshot_base64 = @data[:screenshot_base64]
45
43
 
44
+ # CORREÇÃO: Funções (lambdas) para gerar HTML restauradas na íntegra
45
+ locators_html = lambda do |locators|
46
+ 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].upcase.gsub('_', ' '))}:</span><span class='text-gray-700 ml-2 overflow-auto max-w-[70%]'>#{CGI.escapeHTML(loc[:locator])}</span></li>" }.join
47
+ end
48
+
49
+ all_elements_html = lambda do |elements|
50
+ 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
51
+ end
52
+
46
53
  # Bloco de análise YAML
47
54
  de_para_yaml_html = ""
48
55
  if de_para_yaml
@@ -58,7 +65,7 @@ module AppiumFailureHelper
58
65
  </div>
59
66
  HTML
60
67
  end
61
-
68
+
62
69
  # Bloco de análise Ruby
63
70
  de_para_rb_html = ""
64
71
  if de_para_rb
@@ -80,6 +87,7 @@ module AppiumFailureHelper
80
87
  end
81
88
  end
82
89
 
90
+ # Geração do conteúdo das seções que estavam faltando
83
91
  similar_elements_content = similar_elements.empty? ? "<p class='text-gray-500'>Nenhuma alternativa semelhante foi encontrada na tela atual.</p>" : similar_elements.map { |el|
84
92
  score_percent = (el[:score] * 100).round(1)
85
93
  "<div class='border border-indigo-100 p-3 rounded-lg bg-indigo-50'><p class='font-bold text-indigo-800 mb-2'>#{CGI.escapeHTML(el[:name])} <span class='text-xs font-normal text-green-600 bg-green-100 rounded-full px-2 py-1'>Similaridade: #{score_percent}%</span></p><ul>#{locators_html.call(el[:locators])}</ul></div>"
@@ -91,13 +99,14 @@ module AppiumFailureHelper
91
99
  "<p class='text-sm text-gray-500'>O localizador exato não pôde ser extraído da mensagem de erro.</p>"
92
100
  end
93
101
 
102
+ # Template HTML completo
94
103
  html_content = <<~HTML_REPORT
95
104
  <!DOCTYPE html>
96
105
  <html lang="pt-BR">
97
106
  <head>
98
107
  <meta charset="UTF-8">
99
108
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
100
- <title>Relatório de Falha Appium - #{@data[:timestamp]}</title>
109
+ <title>Relatório de Falha Appium - #{timestamp}</title>
101
110
  <script src="https://cdn.tailwindcss.com"></script>
102
111
  <style> body { font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto; } .tab-content { display: none; } .tab-content.active { display: block; } .tab-button.active { background-color: #4f46e5; color: white; } </style>
103
112
  </head>
@@ -105,18 +114,19 @@ module AppiumFailureHelper
105
114
  <div class="max-w-7xl mx-auto">
106
115
  <header class="mb-8 pb-4 border-b border-gray-300">
107
116
  <h1 class="text-3xl font-bold text-gray-800">Diagnóstico de Falha Automatizada</h1>
108
- <p class="text-sm text-gray-500">Relatório gerado em: #{@data[:timestamp]} | Plataforma: #{@data[:platform].upcase}</p>
117
+ <p class="text-sm text-gray-500">Relatório gerado em: #{timestamp} | Plataforma: #{platform.upcase}</p>
109
118
  </header>
110
119
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
111
120
  <div class="lg:col-span-1">
112
121
  #{de_para_yaml_html}
122
+ #{de_para_rb_html}
113
123
  <div class="bg-white p-4 rounded-lg shadow-xl mb-6 border border-red-200">
114
124
  <h2 class="text-xl font-bold text-red-600 mb-4">Elemento com Falha</h2>
115
125
  #{failed_info_content}
116
126
  </div>
117
127
  <div class="bg-white p-4 rounded-lg shadow-xl">
118
128
  <h2 class="text-xl font-bold text-gray-800 mb-4">Screenshot da Falha</h2>
119
- <img src="data:image/png;base64,#{@data[:screenshot_base64]}" alt="Screenshot da Falha" class="w-full rounded-md shadow-lg border border-gray-200">
129
+ <img src="data:image/png;base64,#{screenshot_base64}" alt="Screenshot da Falha" class="w-full rounded-md shadow-lg border border-gray-200">
120
130
  </div>
121
131
  </div>
122
132
  <div class="lg:col-span-2">
@@ -154,7 +164,7 @@ module AppiumFailureHelper
154
164
  </html>
155
165
  HTML_REPORT
156
166
 
157
- File.write("#{@output_folder}/report_#{@data[:timestamp]}.html", html_content)
167
+ File.write("#{@output_folder}/report_#{timestamp}.html", html_content)
158
168
  end
159
169
  end
160
170
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppiumFailureHelper
4
- VERSION = "0.6.5"
4
+ VERSION = "0.6.7"
5
5
  end
@@ -15,8 +15,22 @@ require_relative 'appium_failure_helper/element_repository'
15
15
  require_relative 'appium_failure_helper/page_analyzer'
16
16
  require_relative 'appium_failure_helper/report_generator'
17
17
  require_relative 'appium_failure_helper/handler'
18
+ require_relative 'appium_failure_helper/configuration'
19
+
18
20
  module AppiumFailureHelper
19
21
  class Error < StandardError; end
22
+ class << self
23
+ attr_writer :configuration
24
+ end
25
+
26
+ def self.configuration
27
+ @configuration ||= Configuration.new
28
+ end
29
+
30
+ def self.configure
31
+ yield(configuration)
32
+ end
33
+
20
34
  def self.handler_failure(driver, exception)
21
35
  Handler.call(driver, exception)
22
36
  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: 0.6.5
4
+ version: 0.6.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Nascimento
@@ -95,6 +95,7 @@ files:
95
95
  - Rakefile
96
96
  - lib/appium_failure_helper.rb
97
97
  - lib/appium_failure_helper/analyzer.rb
98
+ - lib/appium_failure_helper/configuration.rb
98
99
  - lib/appium_failure_helper/element_repository.rb
99
100
  - lib/appium_failure_helper/handler.rb
100
101
  - lib/appium_failure_helper/page_analyzer.rb