report_builder_fix 0.2 → 0.4

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: a9ea84f88068bfa904e1b9aa62e800b8b37206868f4cb853f52056dad0ea754d
4
- data.tar.gz: 3e2d9aea4dd3974db954b9de71c883588d314e3f62991ca372961cd758c494e3
3
+ metadata.gz: 8c7e0aa0fce00a40e7f73b0caf3afab44b258df6a8b0ac85b4e03a341ed8cc89
4
+ data.tar.gz: c2a0627eb5ad90c8d80886b554be1e34d718dea3893060010b392112c8e19d80
5
5
  SHA512:
6
- metadata.gz: a997659999521cb95b643259e67b61f821c3d766ffcf76cfca7fcec97d09efbe0ea96cb9a682ea7e0bbc316b52e4a69dd922e53a17b298b49672faf5ffc8c780
7
- data.tar.gz: c5931db52b66962b7df8ac4e00097126789df34f7274d515c27e95d50b493288dfd5ba53e7af26f1d7310a5521e6b761b3ee99f42df9a7e76f9f362f1c7a942b
6
+ metadata.gz: 97200d64868e061f0a59d8e4dd89d6552e521e4d5994fb6780ef7e7c5afeb7d745bd56c0ce6602dd24866f7871e4784e773e5208bd9c36daac12ea109ba3a573
7
+ data.tar.gz: dedaacfc0f2a12294a5f7f9a2c70bf726e505f8d2c609272e129af750c1d6baae057881da6813b81ce82d997b4d8e44cfa09db1705f7f766fe1c001bf3b16fea
data/bin/report_builder CHANGED
@@ -74,7 +74,7 @@ opt_parser = OptionParser.new do |opts|
74
74
  end
75
75
 
76
76
  opts.on_tail('-v', '--version', 'Show version') do
77
- puts 'ReportBuilder v' + Gem.loaded_specs['report_builder'].version.to_s rescue puts "Something want wrong. \nUse 'gem list report_builder'"
77
+ puts 'ReportBuilderFix v' + Gem.loaded_specs['report_builder_fix'].version.to_s rescue puts "Something want wrong. \nUse 'gem list report_builder'"
78
78
  exit
79
79
  end
80
80
  end
@@ -74,7 +74,7 @@ opt_parser = OptionParser.new do |opts|
74
74
  end
75
75
 
76
76
  opts.on_tail('-v', '--version', 'Show version') do
77
- puts 'ReportBuilder v' + Gem.loaded_specs['report_builder'].version.to_s rescue puts "Something want wrong. \nUse 'gem list report_builder'"
77
+ puts 'ReportBuilderFix v' + Gem.loaded_specs['report_builder_fix'].version.to_s rescue puts "Something want wrong. \nUse 'gem list report_builder'"
78
78
  exit
79
79
  end
80
80
  end
data/lib/.DS_Store CHANGED
Binary file
@@ -0,0 +1,284 @@
1
+ require 'json'
2
+ require 'erb'
3
+ require 'pathname'
4
+ require 'base64'
5
+ require 'ostruct'
6
+
7
+ require 'report_builder/core-ext/hash'
8
+
9
+ module ReportBuilder
10
+
11
+ ##
12
+ # ReportBuilder Main class
13
+ #
14
+ class Builder
15
+
16
+ ##
17
+ # ReportBuilder Main method
18
+ #
19
+ def build_report
20
+ options = ReportBuilder.options
21
+
22
+ groups = get_groups options[:input_path]
23
+
24
+ json_report_path = options[:json_report_path] || options[:report_path]
25
+ if options[:report_types].include? 'JSON'
26
+ File.open(json_report_path + '.json', 'w') do |file|
27
+ file.write JSON.pretty_generate(groups.size > 1 ? groups : groups.first['features'])
28
+ end
29
+ end
30
+
31
+ if options[:additional_css] and Pathname.new(options[:additional_css]).file?
32
+ options[:additional_css] = File.read(options[:additional_css])
33
+ end
34
+
35
+ if options[:additional_js] and Pathname.new(options[:additional_js]).file?
36
+ options[:additional_js] = File.read(options[:additional_js])
37
+ end
38
+
39
+ html_report_path = options[:html_report_path] || options[:report_path]
40
+ if options[:report_types].include? 'HTML'
41
+ File.open(html_report_path + '.html', 'w') do |file|
42
+ file.write get(groups.size > 1 ? 'group_report' : 'report').result(binding)
43
+ end
44
+ end
45
+
46
+ retry_report_path = options[:retry_report_path] || options[:report_path]
47
+ if options[:report_types].include? 'RETRY'
48
+ File.open(retry_report_path + '.retry', 'w') do |file|
49
+ groups.each do |group|
50
+ group['features'].each do |feature|
51
+ if feature['status'] == 'broken'
52
+ feature['elements'].each do |scenario|
53
+ file.puts "#{feature['uri']}:#{scenario['line']}" if scenario['status'] == 'failed'
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ [json_report_path, html_report_path, retry_report_path]
61
+ end
62
+
63
+ private
64
+
65
+ def get(template)
66
+ @erb ||= {}
67
+ template_text = File.read(File.dirname(__FILE__) + '/../../template/' + template + '.erb')
68
+
69
+ # TODO: Remove once older Rubies are not longer supported
70
+ # Only use the deprecated method parameters for older versions of Ruby
71
+ if RUBY_VERSION =~ /^2\.[012345]/
72
+ @erb[template] ||= ERB.new(template_text, nil, nil, '_' + template)
73
+ else
74
+ @erb[template] ||= ERB.new(template_text, eoutvar: '_' + template)
75
+ end
76
+ end
77
+
78
+ def get_groups(input_path)
79
+ groups = []
80
+ if input_path.is_a? Hash
81
+ input_path.each do |group_name, group_path|
82
+ files = get_files group_path
83
+ puts "Error:: No file(s) found at #{group_path}" if files.empty?
84
+ groups << {'name' => group_name, 'features' => get_features(files)}
85
+ end
86
+ else
87
+ files = get_files input_path
88
+ raise "Error:: No file(s) found at #{input_path}" if files.empty?
89
+ groups << {'features' => get_features(files)}
90
+ end
91
+ groups.each do |this_group|
92
+ this_group['features'].each do |feature|
93
+ feature['elements'] = feature['elements'].sort_by { |v| v['line']}
94
+ end
95
+ end
96
+ groups
97
+ end
98
+
99
+ def get_files(path)
100
+ if path.is_a?(String) and Pathname.new(path).exist?
101
+ if Pathname.new(path).directory?
102
+ Dir.glob("#{path}/*.json")
103
+ else
104
+ [path]
105
+ end
106
+ elsif path.is_a? Array
107
+ path.map do |file|
108
+ if Pathname.new(file).exist?
109
+ if Pathname.new(file).directory?
110
+ Dir.glob("#{file}/*.json")
111
+ else
112
+ file
113
+ end
114
+ else
115
+ []
116
+ end
117
+ end.flatten
118
+ else
119
+ []
120
+ end.uniq
121
+ end
122
+
123
+ def get_features(files)
124
+ files.each_with_object([]) do |file, features|
125
+ data = File.read(file)
126
+ next if data.empty?
127
+ begin
128
+ features << JSON.parse(data)
129
+ rescue StandardError
130
+ puts 'Warning:: Invalid Input File ' + file
131
+ puts 'JSON Error:: ' + $!.to_s
132
+ next
133
+ end
134
+ end.flatten.group_by do |feature|
135
+ feature['uri'] + feature['id'] + feature['line'].to_s
136
+ end.values.each_with_object([]) do |group, features|
137
+ features << group.first.except('elements').merge('elements' => group.map {|feature| feature['elements']}.flatten)
138
+ end.sort_by! do |feature|
139
+ feature['name']
140
+ end.each do |feature|
141
+ feature['name'] = ERB::Util.html_escape feature['name']
142
+ if feature['elements'][0]['type'] == 'background'
143
+ (0..feature['elements'].size-1).step(2) do |i|
144
+ feature['elements'][i]['steps'] ||= []
145
+ feature['elements'][i]['steps'].each {|step| step['name'] += (' (' + feature['elements'][i]['keyword'] + ')')}
146
+ if feature['elements'][i+1]
147
+ feature['elements'][i+1]['steps'] = feature['elements'][i]['steps'] + feature['elements'][i+1]['steps']
148
+ feature['elements'][i+1]['before'] = feature['elements'][i]['before'] if feature['elements'][i]['before']
149
+ end
150
+ end
151
+ feature['elements'].reject! do |element|
152
+ element['type'] == 'background'
153
+ end
154
+ end
155
+ feature['elements'].each do |scenario|
156
+ scenario['name'] = ERB::Util.html_escape scenario['name']
157
+ scenario['before'] ||= []
158
+ scenario['before'].each do |before|
159
+ before['result']['duration'] ||= 0
160
+ if before['embeddings']
161
+ before['embeddings'].map! do |embedding|
162
+ decode_embedding(embedding)
163
+ end
164
+ end
165
+ before.merge! 'status' => before['result']['status'], 'duration' => before['result']['duration']
166
+ end
167
+ scenario['steps'] ||= []
168
+ scenario['steps'].each do |step|
169
+ step['name'] = ERB::Util.html_escape step['name']
170
+ step['result']['duration'] ||= 0
171
+ duration = step['result']['duration']
172
+ status = step['result']['status']
173
+ if step['after']
174
+ step['after'].each do |after|
175
+ after['result']['duration'] ||= 0
176
+ duration += after['result']['duration']
177
+ status = 'failed' if after['result']['status'] == 'failed'
178
+ if after['embeddings']
179
+ after['embeddings'].map! do |embedding|
180
+ decode_embedding(embedding)
181
+ end
182
+ end
183
+ after.merge! 'status' => after['result']['status'], 'duration' => after['result']['duration']
184
+ end
185
+ end
186
+ if step['embeddings']
187
+ step['embeddings'].map! do |embedding|
188
+ decode_embedding(embedding)
189
+ end
190
+ end
191
+ step.merge! 'status' => status, 'duration' => duration
192
+ end
193
+ scenario['after'] ||= []
194
+ scenario['after'].each do |after|
195
+ after['result']['duration'] ||= 0
196
+ if after['embeddings']
197
+ after['embeddings'].map! do |embedding|
198
+ decode_embedding(embedding)
199
+ end
200
+ end
201
+ after.merge! 'status' => after['result']['status'], 'duration' => after['result']['duration']
202
+ end
203
+ scenario.merge! 'status' => scenario_status(scenario), 'duration' => total_time(scenario['before']) + total_time(scenario['steps']) + total_time(scenario['after'])
204
+ end
205
+ feature['elements'] = feature['elements'].group_by do |scenario|
206
+ scenario['id'] + ':' + scenario['line'].to_s
207
+ end.values.map do |scenario_group|
208
+ the_scenario = scenario_group.find do |scenario|
209
+ scenario['status'] == 'passed'
210
+ end || scenario_group.last
211
+ if scenario_group.size > 1
212
+ the_scenario['name'] += " (x#{scenario_group.size})"
213
+ end
214
+ the_scenario
215
+ end
216
+ feature.merge! 'status' => feature_status(feature), 'duration' => total_time(feature['elements'])
217
+ end
218
+ end
219
+
220
+ def feature_status(feature)
221
+ feature_status = 'working'
222
+ feature['elements'].each do |scenario|
223
+ status = scenario['status']
224
+ return 'broken' if status == 'failed'
225
+ feature_status = 'incomplete' if %w(undefined pending).include?(status)
226
+ end
227
+ feature_status
228
+ end
229
+
230
+ def scenario_status(scenario)
231
+ (scenario['before'] + scenario['steps'] + scenario['after']).each do |step|
232
+ status = step['status']
233
+ return status unless status == 'passed'
234
+ end
235
+ 'passed'
236
+ end
237
+
238
+ def decode_image(data)
239
+ base64 = %r{^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{4}|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)$}
240
+ if data =~ base64
241
+ data_base64 = Base64.urlsafe_decode64(data).gsub(%r{^data:image\/(png|gif|jpg|jpeg)\;base64,}, '') rescue data
242
+ if data_base64 =~ base64
243
+ data_base64
244
+ else
245
+ data
246
+ end
247
+ else
248
+ ''
249
+ end
250
+ end
251
+
252
+ def decode_text(data)
253
+ Base64.urlsafe_decode64 data rescue ''
254
+ end
255
+
256
+ def decode_embedding(embedding)
257
+ if embedding['mime_type'] =~ /^image\/(png|gif|jpg|jpeg)/
258
+ embedding['data'] = decode_image(embedding['data'])
259
+ elsif embedding['mime_type'] =~ /^text\/(plain|html)/
260
+ embedding['data'] = decode_text(embedding['data'])
261
+ end
262
+ embedding
263
+ end
264
+
265
+ def total_time(data)
266
+ total_time = 0
267
+ data.each {|item| total_time += item['duration']}
268
+ total_time
269
+ end
270
+
271
+ def duration(ms)
272
+ s = ms.to_f/1000000000
273
+ m, s = s.divmod(60)
274
+ if m > 59
275
+ h, m = m.divmod(60)
276
+ "#{h}h #{m}m #{'%.2f' % s}s"
277
+ elsif m > 0
278
+ "#{m}m #{'%.2f' % s}s"
279
+ else
280
+ "#{'%.3f' % s}s"
281
+ end
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,10 @@
1
+ class Hash
2
+ def except(*keys)
3
+ dup.except!(*keys)
4
+ end
5
+
6
+ def except!(*keys)
7
+ keys.each { |key| delete(key) }
8
+ self
9
+ end
10
+ end