appium_failure_helper 0.6.0 → 0.6.1
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/appium_failure_helper/capture.rb +76 -31
- data/lib/appium_failure_helper/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0e272f2150ce88e42b3b414d0afeb9d4e2309311bd271d77bf912ac3967ad03
|
4
|
+
data.tar.gz: 982e97ea6c9a43da40ea9315f554bc734b076b20aaf68b61f1cef83bf3455349
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d431703babb06ffde65176ec6b16233738790261efbee46376f2b6bb90f1fd42717505d4ab6c78b454bf61bc3e656c2f8e9e1ef3936ea8841b585ec152e51f3
|
7
|
+
data.tar.gz: d7df2cb2f3757ae8298ce7b8057e11ea66b0112ba38fb15e01e6e8bcb73b3dad26035bcfdeba8dc97e823bf608de787b2b47c3dceb28d0b988525812b4730ebd
|
@@ -39,7 +39,6 @@ module AppiumFailureHelper
|
|
39
39
|
begin
|
40
40
|
self.setup_logger unless @@logger
|
41
41
|
|
42
|
-
# Remove a pasta reports_failure ao iniciar uma nova execução
|
43
42
|
FileUtils.rm_rf("reports_failure")
|
44
43
|
@@logger.info("Pasta 'reports_failure' removida para uma nova execução.")
|
45
44
|
|
@@ -49,7 +48,6 @@ module AppiumFailureHelper
|
|
49
48
|
FileUtils.mkdir_p(output_folder)
|
50
49
|
@@logger.info("Pasta de saída criada: #{output_folder}")
|
51
50
|
|
52
|
-
# Captura o Base64 e salva o PNG
|
53
51
|
screenshot_base64 = driver.screenshot_as(:base64)
|
54
52
|
screenshot_path = "#{output_folder}/screenshot_#{timestamp}.png"
|
55
53
|
File.open(screenshot_path, 'wb') do |f|
|
@@ -67,7 +65,6 @@ module AppiumFailureHelper
|
|
67
65
|
|
68
66
|
failed_element_info = self.extract_info_from_exception(exception)
|
69
67
|
|
70
|
-
# --- Processamento de todos os elementos ---
|
71
68
|
seen_elements = {}
|
72
69
|
all_elements_suggestions = []
|
73
70
|
doc.xpath('//*').each do |node|
|
@@ -85,7 +82,6 @@ module AppiumFailureHelper
|
|
85
82
|
end
|
86
83
|
end
|
87
84
|
|
88
|
-
# --- Geração do Relatório FOCADO (1) ---
|
89
85
|
targeted_report = {
|
90
86
|
failed_element: failed_element_info,
|
91
87
|
similar_elements: [],
|
@@ -101,14 +97,12 @@ module AppiumFailureHelper
|
|
101
97
|
end
|
102
98
|
@@logger.info("Análise direcionada salva em #{targeted_yaml_path}")
|
103
99
|
|
104
|
-
# --- Geração do Relatório COMPLETO (2) ---
|
105
100
|
full_dump_yaml_path = "#{output_folder}/all_elements_dump_#{timestamp}.yaml"
|
106
101
|
File.open(full_dump_yaml_path, 'w') do |f|
|
107
102
|
f.write(YAML.dump(all_elements_suggestions))
|
108
103
|
end
|
109
104
|
@@logger.info("Dump completo da página salvo em #{full_dump_yaml_path}")
|
110
105
|
|
111
|
-
# --- Geração do Relatório HTML (3) ---
|
112
106
|
html_report_path = "#{output_folder}/report_#{timestamp}.html"
|
113
107
|
html_content = self.generate_html_report(targeted_report, all_elements_suggestions, screenshot_base64, platform, timestamp)
|
114
108
|
File.write(html_report_path, html_content)
|
@@ -122,47 +116,98 @@ module AppiumFailureHelper
|
|
122
116
|
private
|
123
117
|
|
124
118
|
def self.setup_logger
|
125
|
-
@@logger
|
119
|
+
@@logger ||= Logger.new(STDOUT)
|
126
120
|
@@logger.level = Logger::INFO
|
127
121
|
@@logger.formatter = proc do |severity, datetime, progname, msg|
|
128
122
|
"#{datetime.strftime('%Y-%m-%d %H:%M:%S')} [#{severity}] #{msg}\n"
|
129
123
|
end
|
130
124
|
end
|
131
125
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
126
|
+
def self.extract_info_from_exception(exception)
|
127
|
+
message = exception.to_s
|
128
|
+
info = {}
|
129
|
+
|
130
|
+
# normaliza tipos capturados para nomes previsíveis
|
131
|
+
normalize_type = lambda do |t|
|
132
|
+
return 'unknown' unless t
|
133
|
+
t = t.to_s.downcase.strip
|
134
|
+
t = t.gsub(/["']/, '')
|
135
|
+
case t
|
136
|
+
when 'cssselector', 'css selector' then 'css'
|
137
|
+
when 'classname', 'class name' then 'class name'
|
138
|
+
when 'accessibilityid', 'accessibility-id', 'accessibility id' then 'accessibility-id'
|
139
|
+
when 'resourceid', 'resource-id', 'resource id', 'id' then 'resource-id'
|
140
|
+
when 'contentdesc', 'content-desc', 'content desc' then 'content-desc'
|
141
|
+
else
|
142
|
+
t.gsub(/\s+/, '_').gsub(/[^a-z0-9_\-]/, '')
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
patterns = [
|
147
|
+
# ChromeDriver/Selenium JSON style:
|
148
|
+
# no such element: Unable to locate element: {"method":"xpath","selector":"//..."}
|
149
|
+
/no such element: Unable to locate element:\s*\{\s*["']?method["']?\s*:\s*["']?([^"'\}]+)["']?\s*,\s*["']?selector["']?\s*:\s*["']?([^"']+)["']?\s*\}/i,
|
150
|
+
|
151
|
+
# By.xpath: //..., By.id: "foo"
|
152
|
+
/By\.(xpath|id|css selector|cssSelector|name|class name|className):\s*['"]?(.+?)['"]?(?:\s|$)/i,
|
153
|
+
|
154
|
+
# Generic "using <type>=<value>" or using <type>: '<value>'
|
155
|
+
/using\s+([a-zA-Z0-9_\-:]+)\s*[=:]\s*['"]?(.+?)['"]?(?:\s|$)/i,
|
156
|
+
|
157
|
+
# "An element with the selector '...' was not found"
|
158
|
+
/An element with (?:the )?selector ['"](.+?)['"] (?:could not be found|was not found|not found|not be located)/i,
|
159
|
+
|
160
|
+
# "with the resource-id 'xyz'" or "with the accessibility-id 'abc'"
|
161
|
+
/with the (resource-id|accessibility[- ]?id|content-?desc|label|name)\s*[:=]?\s*['"](.+?)['"]/i,
|
162
|
+
|
163
|
+
# "Unable to find element by: id 'xyz'"
|
164
|
+
/Unable to find element by:\s*([a-zA-Z0-9_\- ]+)\s*[:=]?\s*['"]?(.+?)['"]?(?:\s|$)/i,
|
165
|
+
|
166
|
+
# Fallback to any "selector: '...'" occurence
|
167
|
+
/selector['"]?\s*[:=]?\s*['"](.+?)['"]/i
|
168
|
+
]
|
169
|
+
|
170
|
+
patterns.each do |pattern|
|
171
|
+
if (m = message.match(pattern))
|
172
|
+
caps = m.captures.compact
|
173
|
+
if caps.length >= 2
|
174
|
+
raw_type = caps[0].to_s.strip
|
175
|
+
raw_value = caps[1].to_s.strip
|
176
|
+
info[:selector_type] = normalize_type.call(raw_type)
|
177
|
+
info[:selector_value] = raw_value.gsub(/\A['"]|['"]\z/, '')
|
178
|
+
else
|
179
|
+
info[:selector_type] = 'unknown'
|
180
|
+
info[:selector_value] = caps[0].to_s.strip.gsub(/\A['"]|['"]\z/, '')
|
153
181
|
end
|
182
|
+
info[:raw_message] = message[0, 1000]
|
183
|
+
return info
|
154
184
|
end
|
155
|
-
info
|
156
185
|
end
|
157
186
|
|
187
|
+
# tentativa extra: By.<tipo>:<valor> em qualquer lugar da mensagem
|
188
|
+
if (m = message.match(/By\.([a-zA-Z0-9_\- ]+):\s*['"]?(.+?)['"]?/i))
|
189
|
+
info[:selector_type] = normalize_type.call(m[1])
|
190
|
+
info[:selector_value] = m[2].to_s.strip
|
191
|
+
info[:raw_message] = message[0,1000]
|
192
|
+
return info
|
193
|
+
end
|
194
|
+
|
195
|
+
# fallback final: retorna a mensagem inteira recortada (útil para debug)
|
196
|
+
info[:selector_type] = 'unknown'
|
197
|
+
info[:selector_value] = message.strip[0, 500]
|
198
|
+
info[:raw_message] = message[0,1000]
|
199
|
+
info
|
200
|
+
end
|
201
|
+
|
202
|
+
|
158
203
|
def self.find_similar_elements(doc, failed_info, platform)
|
159
204
|
similar_elements = []
|
160
205
|
doc.xpath('//*').each do |node|
|
161
206
|
next if node.name == 'hierarchy'
|
162
207
|
attrs = node.attributes.transform_values(&:value)
|
163
208
|
|
164
|
-
|
165
|
-
|
209
|
+
selector_value = failed_info[:selector_value].to_s.downcase.strip
|
210
|
+
|
166
211
|
is_similar = case platform
|
167
212
|
when 'android'
|
168
213
|
(attrs['resource-id']&.downcase&.include?(selector_value) ||
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appium_failure_helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Nascimento
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-09-
|
11
|
+
date: 2025-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|