report_builder 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/report_builder.rb +301 -302
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3548db4c70ef0f5d6fae4c9b69fd3da24fd09a7c
|
4
|
+
data.tar.gz: ee9feecdbb0c1ed8574b7e87d89bde602906a4b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81ef540f7558c9f8c3f1e37b7a2b9cf5effe24cc0b23499f16163b563859ffc2d833212622d30aaf51f3a63b1deffd48fc571d4a018dc19602c51f8880aa7902
|
7
|
+
data.tar.gz: 23ea000736d6905ac1195d209a1a7fc0830d7bd13e77a7ff66d033fc8f0ac321bbc80a89795a7c0b356d2efa0d8876497a5843bd1bf0903e5cf4e9636753a7fa
|
data/lib/report_builder.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'builder'
|
3
|
+
require 'base64'
|
3
4
|
|
4
5
|
# Add except method to Hash
|
5
6
|
class Hash
|
@@ -17,16 +18,27 @@ end
|
|
17
18
|
class ReportBuilder
|
18
19
|
|
19
20
|
# report_builder:
|
20
|
-
# ReportBuilder.build_report('path/of/json/files/dir')
|
21
21
|
#
|
22
|
-
#
|
22
|
+
# ReportBuilder.build_report()
|
23
|
+
# ReportBuilder.build_report('path/of/json/files/dir')
|
24
|
+
# ReportBuilder.build_report('path/of/json/files/dir','my_test_report_name','json_html')
|
25
|
+
# ReportBuilder.build_report('path/of/json/files/dir','my_test_report_name','json')
|
26
|
+
# ReportBuilder.build_report('path/of/json/files/dir','my_test_report_name','html')
|
23
27
|
#
|
24
|
-
# ReportBuilder.build_report(['path/of/json/file1.json','path/of/json/file2.json','path/of/json/files/dir/'])
|
25
28
|
#
|
26
|
-
#
|
29
|
+
# ReportBuilder.build_report('path/of/json/cucumber.json')
|
27
30
|
#
|
28
|
-
#
|
29
|
-
#
|
31
|
+
#
|
32
|
+
# ReportBuilder.build_report([
|
33
|
+
# 'path/of/json/cucumber1.json',
|
34
|
+
# 'path/of/json/cucumber2.json',
|
35
|
+
# 'path/of/json/files/dir/'
|
36
|
+
# ])
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# ReportBuilder::COLOR[:passed] = '#ffffff'
|
40
|
+
# ReportBuilder::COLOR[:failed] = '#000000'
|
41
|
+
# ReportBuilder.build_report()
|
30
42
|
|
31
43
|
|
32
44
|
# colors corresponding to status
|
@@ -38,7 +50,8 @@ class ReportBuilder
|
|
38
50
|
undefined: '#e4d354',
|
39
51
|
unknown: '#e4d354',
|
40
52
|
pending: '#f7a35c',
|
41
|
-
skipped: '#7cb5ec'
|
53
|
+
skipped: '#7cb5ec',
|
54
|
+
output: '#007fff'
|
42
55
|
}
|
43
56
|
|
44
57
|
# @param [Object] file_or_dir json file, array of json files or path, json files path
|
@@ -49,14 +62,10 @@ class ReportBuilder
|
|
49
62
|
input = files file_or_dir
|
50
63
|
all_features = features input rescue (raise 'ReportBuilderParsingError')
|
51
64
|
|
52
|
-
|
53
|
-
|
54
|
-
file.write JSON.pretty_generate all_features
|
55
|
-
end
|
65
|
+
File.open(output_file_name + '.json', 'w') do |file|
|
66
|
+
file.write JSON.pretty_generate all_features
|
56
67
|
puts "JSON test report generated: '#{output_file_name}.json'"
|
57
|
-
end
|
58
|
-
|
59
|
-
return unless output_file_type.include? 'html'
|
68
|
+
end if output_file_type.to_s.upcase.include? 'JSON'
|
60
69
|
|
61
70
|
all_scenarios = scenarios all_features
|
62
71
|
all_steps = steps all_scenarios
|
@@ -65,334 +74,320 @@ class ReportBuilder
|
|
65
74
|
scenario_data = data all_scenarios
|
66
75
|
step_data = data all_steps
|
67
76
|
|
68
|
-
|
77
|
+
File.open(output_file_name + '.html', 'w:UTF-8') do |file|
|
78
|
+
@builder = Builder::XmlMarkup.new(:target => file, :indent => 0)
|
79
|
+
@builder.declare!(:DOCTYPE, :html)
|
80
|
+
@builder << '<html>'
|
69
81
|
|
70
|
-
|
71
|
-
|
72
|
-
|
82
|
+
@builder.head do
|
83
|
+
@builder.meta(charset: 'UTF-8')
|
84
|
+
@builder.title 'Test Results'
|
73
85
|
|
74
|
-
|
75
|
-
|
76
|
-
|
86
|
+
@builder.style(:type => 'text/css') do
|
87
|
+
@builder << File.read(File.dirname(__FILE__) + '/../vendor/assets/stylesheets/jquery-ui.min.css')
|
88
|
+
COLOR.each do |color|
|
89
|
+
@builder << ".#{color[0].to_s}{background:#{color[1]};color:#434348;padding:2px}"
|
90
|
+
end
|
91
|
+
@builder << '.summary{border: 1px solid #c5c5c5;border-radius:4px;text-align:right;background:#f1f1f1;color:#434348;padding:4px}'
|
92
|
+
end
|
77
93
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
94
|
+
@builder.script(:type => 'text/javascript') do
|
95
|
+
%w(jquery-min jquery-ui.min highcharts highcharts-3d).each do |js|
|
96
|
+
@builder << File.read(File.dirname(__FILE__) + '/../vendor/assets/javascripts/' + js + '.js')
|
97
|
+
end
|
98
|
+
@builder << '$(function(){$("#results").tabs();});'
|
99
|
+
@builder << "$(function(){$('#features').accordion({collapsible: true, heightStyle: 'content', active: false, icons: false});});"
|
100
|
+
(0..all_scenarios.size).each do |n|
|
101
|
+
@builder << "$(function(){$('#scenario#{n}').accordion({collapsible: true, heightStyle: 'content', active: false, icons: false});});"
|
102
|
+
end
|
103
|
+
@builder << "$(function(){$('#status').accordion({collapsible: true, heightStyle: 'content', active: false, icons: false});});"
|
104
|
+
scenario_data.each do |data|
|
105
|
+
@builder << "$(function(){$('##{data[:name]}').accordion({collapsible: true, heightStyle: 'content', active: false, icons: false});});"
|
106
|
+
end
|
82
107
|
end
|
83
|
-
builder << '.summary{border: 1px solid #c5c5c5;border-radius:4px;text-align:right;background:#f1f1f1;color:#434348;padding:4px}'
|
84
108
|
end
|
85
109
|
|
86
|
-
builder
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
(0..all_scenarios.size).each do |n|
|
93
|
-
builder << "$(function(){$('#scenario#{n}').accordion({collapsible: true, heightStyle: 'content', active: false, icons: false});});"
|
110
|
+
@builder << '<body>'
|
111
|
+
|
112
|
+
@builder.h4(:class => 'summary') do
|
113
|
+
@builder << all_features.size.to_s + ' feature ('
|
114
|
+
feature_data.each do |data|
|
115
|
+
@builder << ' ' + data[:count].to_s + ' ' + data[:name]
|
94
116
|
end
|
95
|
-
builder <<
|
117
|
+
@builder << ') ~ ' + all_scenarios.size.to_s + ' scenario ('
|
96
118
|
scenario_data.each do |data|
|
97
|
-
builder <<
|
119
|
+
@builder << ' ' + data[:count].to_s + ' ' + data[:name]
|
98
120
|
end
|
121
|
+
@builder << ') ~ ' + all_steps.size.to_s + ' step ('
|
122
|
+
step_data.each do |data|
|
123
|
+
@builder << ' ' + data[:count].to_s + ' ' + data[:name]
|
124
|
+
end
|
125
|
+
@builder << ') ~ ' + duration(total_time).to_s
|
99
126
|
end
|
100
|
-
end
|
101
|
-
|
102
|
-
builder << '<body>'
|
103
|
-
|
104
|
-
builder.h4(:class => 'summary') do
|
105
|
-
builder << all_features.size.to_s + ' feature ('
|
106
|
-
feature_data.each do |data|
|
107
|
-
builder << ' ' + data[:count].to_s + ' ' + data[:name]
|
108
|
-
end
|
109
|
-
builder << ') ~ ' + all_scenarios.size.to_s + ' scenario ('
|
110
|
-
scenario_data.each do |data|
|
111
|
-
builder << ' ' + data[:count].to_s + ' ' + data[:name]
|
112
|
-
end
|
113
|
-
builder << ') ~ ' + all_steps.size.to_s + ' step ('
|
114
|
-
step_data.each do |data|
|
115
|
-
builder << ' ' + data[:count].to_s + ' ' + data[:name]
|
116
|
-
end
|
117
|
-
builder << ') ~ ' + duration(total_time).to_s
|
118
|
-
end
|
119
127
|
|
120
|
-
|
128
|
+
@builder.div(:id => 'results') do
|
129
|
+
build_menu %w(overview features scenarios errors)
|
121
130
|
|
122
|
-
|
123
|
-
|
124
|
-
builder
|
125
|
-
|
126
|
-
builder << tab.capitalize
|
127
|
-
end
|
128
|
-
end
|
131
|
+
@builder.div(:id => 'overviewTab') do
|
132
|
+
@builder << "<div id='featurePieChart'></div>"
|
133
|
+
@builder << "<div id='scenarioPieChart'></div>"
|
134
|
+
@builder << "<div id='stepPieChart'></div>"
|
129
135
|
end
|
130
|
-
end
|
131
|
-
|
132
|
-
builder.div(:id => 'overviewTab') do
|
133
|
-
builder << "<div id='featurePieChart'></div>"
|
134
|
-
builder << "<div id='scenarioPieChart'></div>"
|
135
|
-
builder << "<div id='stepPieChart'></div>"
|
136
|
-
end
|
137
136
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
137
|
+
@builder.div(:id => 'featuresTab') do
|
138
|
+
@builder.div(:id => 'features') do
|
139
|
+
all_features.each_with_index do |feature, n|
|
140
|
+
@builder.h3 do
|
141
|
+
@builder.span(:class => feature['status']) do
|
142
|
+
@builder << "<strong>#{feature['keyword']}</strong> #{feature['name']} (#{duration(feature['duration'])})"
|
143
|
+
end
|
144
144
|
end
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
feature['elements'].each do |scenario|
|
149
|
-
builder.h3 do
|
150
|
-
builder.span(:class => scenario['status']) do
|
151
|
-
builder << "<strong>#{scenario['keyword']}</strong> #{scenario['name']} (#{duration(scenario['duration'])})"
|
152
|
-
end
|
153
|
-
end
|
154
|
-
builder.div do
|
155
|
-
scenario['before'].each do |before|
|
156
|
-
if before['status'] == 'failed'
|
157
|
-
builder << "<strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
158
|
-
error = before['result']['error_message'].split("\n")
|
159
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
160
|
-
error[0..-2].each do |line|
|
161
|
-
builder << line + '<br/>'
|
162
|
-
end
|
163
|
-
end
|
164
|
-
builder << "<strong>Hook: </strong>#{error[-1]} <br/>"
|
165
|
-
end
|
166
|
-
end
|
167
|
-
scenario['steps'].each do |step|
|
168
|
-
builder.span(:class => step['status']) do
|
169
|
-
builder << "<strong>#{step['keyword']}</strong> #{step['name']} (#{duration(step['duration'])})"
|
170
|
-
end
|
171
|
-
step['output'].each do |output|
|
172
|
-
builder << "<br/> <span style='color:#{COLOR[:skipped]}'>#{output}</span>"
|
173
|
-
end if step['output'] && step['output'].is_a?(Array)
|
174
|
-
if step['status'] == 'failed' && step['result']['error_message']
|
175
|
-
builder << "<br/><strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
176
|
-
error = step['result']['error_message'].split("\n")
|
177
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
178
|
-
error[0..-3].each do |line|
|
179
|
-
builder << line + '<br/>'
|
180
|
-
end
|
181
|
-
end
|
182
|
-
builder << "<strong>SD: </strong>#{error[-2]} <br/>"
|
183
|
-
builder << "<strong>FF: </strong>#{error[-1]}"
|
184
|
-
end
|
185
|
-
step['after'].each do |after|
|
186
|
-
after['output'].each do |output|
|
187
|
-
builder << "<br/> <span style='color:#{COLOR[:skipped]}'>#{output}</span>"
|
188
|
-
end if after['output'] && after['output'].is_a?(Array)
|
189
|
-
if after['result']['error_message']
|
190
|
-
builder << "<br/><strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
191
|
-
error = after['result']['error_message'].split("\n")
|
192
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
193
|
-
(scenario['keyword'] == 'Scenario Outline' ? error[0..-6] : error[0..-4]).each do |line|
|
194
|
-
builder << line + '<br/>'
|
195
|
-
end
|
196
|
-
end
|
197
|
-
builder << "<strong>Hook: </strong>#{scenario['keyword'] == 'Scenario Outline' ? error[-5] : error[-3]} <br/>"
|
198
|
-
builder << "<strong>FF: </strong>#{error[-2]} <br/>"
|
199
|
-
end
|
200
|
-
end if step['after']
|
201
|
-
builder << '<br/>'
|
202
|
-
end
|
203
|
-
scenario['after'].each do |after|
|
204
|
-
after['output'].each do |output|
|
205
|
-
builder << "<br/> <span style='color:#{COLOR[:skipped]}'>#{output}</span>"
|
206
|
-
end if after['output'] && after['output'].is_a?(Array)
|
207
|
-
if after['status'] == 'failed'
|
208
|
-
builder << "<br/><strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
209
|
-
error = after['result']['error_message'].split("\n")
|
210
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
211
|
-
error[0..-2].each do |line|
|
212
|
-
builder << line + '<br/>'
|
213
|
-
end
|
214
|
-
end
|
215
|
-
builder << "<strong>Hook: </strong>#{error[-1]}"
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
145
|
+
@builder.div do
|
146
|
+
@builder.div(:id => "scenario#{n}") do
|
147
|
+
feature['elements'].each{|scenario| build_scenario scenario}
|
219
148
|
end
|
220
149
|
end
|
221
150
|
end
|
222
151
|
end
|
152
|
+
@builder << "<div id='featureTabPieChart'></div>"
|
223
153
|
end
|
224
|
-
builder << "<div id='featureTabPieChart'></div>"
|
225
|
-
end
|
226
154
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
155
|
+
@builder.div(:id => 'scenariosTab') do
|
156
|
+
@builder.div(:id => 'status') do
|
157
|
+
all_scenarios.group_by{|scenario| scenario['status']}.each do |data|
|
158
|
+
@builder.h3 do
|
159
|
+
@builder.sapn(:class => data[0]) do
|
160
|
+
@builder << "<strong>#{data[0].capitalize} scenarios (Count: #{data[1].size})</strong>"
|
161
|
+
end
|
233
162
|
end
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
data[1].each do |scenario|
|
238
|
-
builder.h3 do
|
239
|
-
builder.span(:class => data[0]) do
|
240
|
-
builder << "<strong>#{scenario['keyword']}</strong> #{scenario['name']} (#{duration(scenario['duration'])})"
|
241
|
-
end
|
242
|
-
end
|
243
|
-
builder.div do
|
244
|
-
scenario['before'].each do |before|
|
245
|
-
if before['status'] == 'failed'
|
246
|
-
builder << "<strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
247
|
-
error = before['result']['error_message'].split("\n")
|
248
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
249
|
-
error[0..-2].each do |line|
|
250
|
-
builder << line + '<br/>'
|
251
|
-
end
|
252
|
-
end
|
253
|
-
builder << "<strong>Hook: </strong>#{error[-1]} <br/>"
|
254
|
-
end
|
255
|
-
end
|
256
|
-
scenario['steps'].each do |step|
|
257
|
-
builder.span(:class => step['status']) do
|
258
|
-
builder << "<strong>#{step['keyword']}</strong> #{step['name']} (#{duration(step['duration'])})"
|
259
|
-
end
|
260
|
-
step['output'].each do |output|
|
261
|
-
builder << "<br/> <span style='color:#{COLOR[:skipped]}'>#{output}</span>"
|
262
|
-
end if step['output'] && step['output'].is_a?(Array)
|
263
|
-
if step['status'] == 'failed' && step['result']['error_message']
|
264
|
-
builder << "<br/><strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
265
|
-
error = step['result']['error_message'].split("\n")
|
266
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
267
|
-
error[0..-3].each do |line|
|
268
|
-
builder << line + '<br/>'
|
269
|
-
end
|
270
|
-
end
|
271
|
-
builder << "<strong>SD: </strong>#{error[-2]} <br/>"
|
272
|
-
builder << "<strong>FF: </strong>#{error[-1]}"
|
273
|
-
end
|
274
|
-
step['after'].each do |after|
|
275
|
-
after['output'].each do |output|
|
276
|
-
builder << "<br/> <span style='color:#{COLOR[:skipped]}'>#{output}</span>"
|
277
|
-
end if after['output'] && after['output'].is_a?(Array)
|
278
|
-
if after['result']['error_message']
|
279
|
-
builder << "<br/><strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
280
|
-
error = after['result']['error_message'].split("\n")
|
281
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
282
|
-
(scenario['keyword'] == 'Scenario Outline' ? error[0..-6] : error[0..-4]).each do |line|
|
283
|
-
builder << line + '<br/>'
|
284
|
-
end
|
285
|
-
end
|
286
|
-
builder << "<strong>Hook: </strong>#{scenario['keyword'] == 'Scenario Outline' ? error[-5] : error[-3]} <br/>"
|
287
|
-
builder << "<strong>FF: </strong>#{error[-2]} <br/>"
|
288
|
-
end
|
289
|
-
end if step['after']
|
290
|
-
builder << '<br>'
|
291
|
-
end
|
292
|
-
scenario['after'].each do |after|
|
293
|
-
after['output'].each do |output|
|
294
|
-
builder << "<br/> <span style='color:#{COLOR[:skipped]}'>#{output}</span>"
|
295
|
-
end if after['output'] && after['output'].is_a?(Array)
|
296
|
-
if after['status'] == 'failed'
|
297
|
-
builder << "<br/><strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
298
|
-
error = after['result']['error_message'].split("\n")
|
299
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
300
|
-
error[0..-2].each do |line|
|
301
|
-
builder << line + '<br/>'
|
302
|
-
end
|
303
|
-
end
|
304
|
-
builder << "<strong>Hook: </strong>#{error[-1]}"
|
305
|
-
end
|
306
|
-
end
|
307
|
-
end
|
163
|
+
@builder.div do
|
164
|
+
@builder.div(:id => data[0]) do
|
165
|
+
data[1].each{|scenario| build_scenario scenario}
|
308
166
|
end
|
309
167
|
end
|
310
168
|
end
|
311
169
|
end
|
170
|
+
@builder << "<div id='scenarioTabPieChart'></div>"
|
171
|
+
end
|
172
|
+
|
173
|
+
@builder.div(:id => 'errorsTab') do
|
174
|
+
@builder.ol do
|
175
|
+
all_scenarios.each{|scenario| build_error_list scenario}
|
176
|
+
end
|
312
177
|
end
|
313
|
-
builder << "<div id='scenarioTabPieChart'></div>"
|
314
178
|
end
|
315
179
|
|
316
|
-
builder.
|
317
|
-
builder
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
builder << line + '<br/>'
|
340
|
-
end
|
341
|
-
end
|
342
|
-
builder << "<strong>Hook: </strong>#{scenario['keyword'] == 'Scenario Outline' ? error[-5] : error[-3]} <br/>"
|
343
|
-
builder << "<strong>FF: </strong>#{error[-2]} <br/>"
|
344
|
-
end
|
345
|
-
end if step['after']
|
346
|
-
next unless step['status'] == 'failed' && step['result']['error_message']
|
347
|
-
builder.li do
|
348
|
-
error = step['result']['error_message'].split("\n")
|
349
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
350
|
-
error[0..-3].each do |line|
|
351
|
-
builder << line + '<br/>'
|
352
|
-
end
|
353
|
-
end
|
354
|
-
builder << "<strong>SD: </strong>#{error[-2]} <br/>"
|
355
|
-
builder << "<strong>FF: </strong>#{error[-1]}"
|
356
|
-
end
|
357
|
-
end
|
358
|
-
scenario['after'].each do |after|
|
359
|
-
next unless after['status'] == 'failed'
|
360
|
-
builder.li do
|
361
|
-
error = after['result']['error_message'].split("\n")
|
362
|
-
builder.span(:style => "color:#{COLOR[:failed]}") do
|
363
|
-
error[0..-2].each do |line|
|
364
|
-
builder << line + '<br/>'
|
365
|
-
end
|
366
|
-
end
|
367
|
-
builder << "<strong>Hook: </strong>#{error[-1]} <br/>"
|
368
|
-
builder << "<strong>Scenario: </strong>#{scenario['name']}"
|
369
|
-
end
|
370
|
-
end
|
180
|
+
@builder.script(:type => 'text/javascript') do
|
181
|
+
@builder << pie_chart_js('featurePieChart', 'Features', feature_data)
|
182
|
+
@builder << donut_js('featureTabPieChart', 'Features', feature_data)
|
183
|
+
@builder << pie_chart_js('scenarioPieChart', 'Scenarios', scenario_data)
|
184
|
+
@builder << donut_js('scenarioTabPieChart', 'Scenarios', scenario_data)
|
185
|
+
@builder << pie_chart_js('stepPieChart', 'Steps', step_data)
|
186
|
+
end
|
187
|
+
|
188
|
+
@builder << '</body>'
|
189
|
+
@builder << '</html>'
|
190
|
+
|
191
|
+
puts "HTML test report generated: '#{output_file_name}.html'"
|
192
|
+
end if output_file_type.to_s.upcase.include? 'HTML'
|
193
|
+
|
194
|
+
[total_time, feature_data, scenario_data, step_data]
|
195
|
+
end
|
196
|
+
|
197
|
+
def self.build_menu(tabs)
|
198
|
+
@builder.ul do
|
199
|
+
tabs.each do |tab|
|
200
|
+
@builder.li do
|
201
|
+
@builder.a(:href => "##{tab}Tab") do
|
202
|
+
@builder << tab.capitalize
|
371
203
|
end
|
372
204
|
end
|
373
205
|
end
|
374
206
|
end
|
207
|
+
end
|
375
208
|
|
376
|
-
|
377
|
-
|
378
|
-
builder
|
379
|
-
|
380
|
-
|
381
|
-
|
209
|
+
def self.build_scenario(scenario)
|
210
|
+
@builder.h3 do
|
211
|
+
@builder.span(:class => scenario['status']) do
|
212
|
+
@builder << "<strong>#{scenario['keyword']}</strong> #{scenario['name']} (#{duration(scenario['duration'])})"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
@builder.div do
|
216
|
+
scenario['before'].each do |before|
|
217
|
+
build_hook_error before
|
218
|
+
end
|
219
|
+
scenario['steps'].each do |step|
|
220
|
+
build_step step, scenario['keyword']
|
221
|
+
end
|
222
|
+
scenario['after'].each do |after|
|
223
|
+
build_output after['output']
|
224
|
+
build_hook_error after
|
225
|
+
build_embedding after['embeddings']
|
226
|
+
end
|
382
227
|
end
|
228
|
+
end
|
383
229
|
|
384
|
-
|
385
|
-
builder
|
230
|
+
def self.build_step(step, scenario_keyword)
|
231
|
+
@builder.span(:class => step['status']) do
|
232
|
+
@builder << "<strong>#{step['keyword']}</strong> #{step['name']} (#{duration(step['duration'])})"
|
233
|
+
end
|
234
|
+
build_output step['output']
|
235
|
+
build_step_error step
|
236
|
+
build_embedding step['embeddings']
|
237
|
+
step['after'].each do |after|
|
238
|
+
build_output after['output']
|
239
|
+
build_step_hook_error after, scenario_keyword
|
240
|
+
build_embedding after['embeddings']
|
241
|
+
end if step['after']
|
242
|
+
@builder << '<br/>'
|
243
|
+
end
|
386
244
|
|
387
|
-
|
245
|
+
def self.build_output(outputs)
|
246
|
+
outputs.each do |output|
|
247
|
+
@builder << "<br/><span style='color:#{COLOR[:output]}'>#{output.gsub("\n",'</br>').gsub("\t",' ').gsub(' ',' ')}</span>"
|
248
|
+
end if outputs.is_a?(Array)
|
249
|
+
end
|
388
250
|
|
389
|
-
|
390
|
-
[
|
251
|
+
def self.build_step_error(step)
|
252
|
+
if step['status'] == 'failed' && step['result']['error_message']
|
253
|
+
@builder << "<br/><strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
254
|
+
error = step['result']['error_message'].split("\n")
|
255
|
+
@builder.span(:style => "color:#{COLOR[:failed]}") do
|
256
|
+
error[0..-3].each do |line|
|
257
|
+
@builder << line + '<br/>'
|
258
|
+
end
|
259
|
+
end
|
260
|
+
@builder << "<strong>SD: </strong>#{error[-2]} <br/>"
|
261
|
+
@builder << "<strong>FF: </strong>#{error[-1]}"
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def self.build_hook_error(hook)
|
266
|
+
if hook['status'] == 'failed'
|
267
|
+
@builder << "<br/><strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
268
|
+
error = hook['result']['error_message'].split("\n")
|
269
|
+
@builder.span(:style => "color:#{COLOR[:failed]}") do
|
270
|
+
error[0..-2].each do |line|
|
271
|
+
@builder << line + '<br/>'
|
272
|
+
end
|
273
|
+
end
|
274
|
+
@builder << "<strong>Hook: </strong>#{error[-1]}<br/>"
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def self.build_step_hook_error(hook, scenario_keyword)
|
279
|
+
if hook['result']['error_message']
|
280
|
+
@builder << "<br/><strong style=color:#{COLOR[:failed]}>Error: </strong>"
|
281
|
+
error = hook['result']['error_message'].split("\n")
|
282
|
+
@builder.span(:style => "color:#{COLOR[:failed]}") do
|
283
|
+
(scenario_keyword == 'Scenario Outline' ? error[0..-6] : error[0..-4]).each do |line|
|
284
|
+
@builder << line + '<br/>'
|
285
|
+
end
|
286
|
+
end
|
287
|
+
@builder << "<strong>Hook: </strong>#{scenario_keyword == 'Scenario Outline' ? error[-5] : error[-3]} <br/>"
|
288
|
+
@builder << "<strong>FF: </strong>#{error[-2]}"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def self.build_embedding(embeddings)
|
293
|
+
@embedding_count ||= 0
|
294
|
+
embeddings.each do |embedding|
|
295
|
+
id = "embedding_#{@embedding_count}"
|
296
|
+
if embedding['mime_type'] =~ /^image\/(png|gif|jpg|jpeg)/
|
297
|
+
@builder.span(:class => 'image') do
|
298
|
+
@builder << '<br/>'
|
299
|
+
@builder.a(:href => '', :style => 'text-decoration: none;', :onclick => "img=document.getElementById('#{id}');img.style.display = (img.style.display == 'none' ? 'block' : 'none');return false") do
|
300
|
+
@builder.span(:style => "color: #{COLOR[:output]}; font-weight: bold; border-bottom: 1px solid #{COLOR[:output]};") do
|
301
|
+
@builder << 'Screenshot'
|
302
|
+
end
|
303
|
+
end
|
304
|
+
@builder << '<br/>'
|
305
|
+
begin
|
306
|
+
src = Base64.decode64(embedding['data'])
|
307
|
+
src = 'data:' + embedding['mime_type'] + ';base64,' + src unless src =~ /^data:image\/(png|gif|jpg|jpeg);base64,/
|
308
|
+
@builder << %{<img id='#{id}' style='display: none; border: 1px solid #{COLOR[:output]};' src='#{src}'/>}
|
309
|
+
rescue
|
310
|
+
src = embedding['data']
|
311
|
+
src = 'data:' + embedding['mime_type'] + ';base64,' + src unless src =~ /^data:image\/(png|gif|jpg|jpeg);base64,/
|
312
|
+
@builder << %{<img id='#{id}' style='display: none; border: 1px solid #{COLOR[:output]};' src='#{src}'/>}
|
313
|
+
end rescue puts('Image embedding skipped!')
|
314
|
+
end
|
315
|
+
elsif embedding['mime_type'] =~ /^text\/plain/
|
316
|
+
@builder.span(:class => 'link') do
|
317
|
+
@builder << '<br/>'
|
318
|
+
src = Base64.decode64(embedding['data'])
|
319
|
+
@builder.a(:id => id, :style => 'text-decoration: none;', :href => src, :title => 'Link') do
|
320
|
+
@builder.span(:style => "color: #{COLOR[:output]}; font-weight: bold; border-bottom: 1px solid #{COLOR[:output]};") do
|
321
|
+
@builder << src
|
322
|
+
end
|
323
|
+
end
|
324
|
+
@builder << '<br/>'
|
325
|
+
end rescue puts('Link embedding skipped!')
|
326
|
+
end
|
327
|
+
@embedding_count += 1
|
328
|
+
end if embeddings.is_a?(Array)
|
329
|
+
end
|
330
|
+
|
331
|
+
def self.build_error_list(scenario)
|
332
|
+
scenario['before'].each do |before|
|
333
|
+
next unless before['status'] == 'failed'
|
334
|
+
@builder.li do
|
335
|
+
error = before['result']['error_message'].split("\n")
|
336
|
+
@builder.span(:style => "color:#{COLOR[:failed]}") do
|
337
|
+
error[0..-2].each do |line|
|
338
|
+
@builder << line + '<br/>'
|
339
|
+
end
|
340
|
+
end
|
341
|
+
@builder << "<strong>Hook: </strong>#{error[-1]} <br/>"
|
342
|
+
@builder << "<strong>Scenario: </strong>#{scenario['name']} <br/><hr/>"
|
343
|
+
end
|
344
|
+
end
|
345
|
+
scenario['steps'].each do |step|
|
346
|
+
step['after'].each do |after|
|
347
|
+
next unless after['status'] == 'failed'
|
348
|
+
@builder.li do
|
349
|
+
error = after['result']['error_message'].split("\n")
|
350
|
+
@builder.span(:style => "color:#{COLOR[:failed]}") do
|
351
|
+
(scenario['keyword'] == 'Scenario Outline' ? error[0..-6] : error[0..-4]).each do |line|
|
352
|
+
@builder << line + '<br/>'
|
353
|
+
end
|
354
|
+
end
|
355
|
+
@builder << "<strong>Hook: </strong>#{scenario['keyword'] == 'Scenario Outline' ? error[-5] : error[-3]} <br/>"
|
356
|
+
@builder << "<strong>FF: </strong>#{error[-2]} <br/><hr/>"
|
357
|
+
end
|
358
|
+
end if step['after']
|
359
|
+
next unless step['status'] == 'failed' && step['result']['error_message']
|
360
|
+
@builder.li do
|
361
|
+
error = step['result']['error_message'].split("\n")
|
362
|
+
@builder.span(:style => "color:#{COLOR[:failed]}") do
|
363
|
+
error[0..-3].each do |line|
|
364
|
+
@builder << line + '<br/>'
|
365
|
+
end
|
366
|
+
end
|
367
|
+
@builder << "<strong>SD: </strong>#{error[-2]} <br/>"
|
368
|
+
@builder << "<strong>FF: </strong>#{error[-1]} <br/><hr/>"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
scenario['after'].each do |after|
|
372
|
+
next unless after['status'] == 'failed'
|
373
|
+
@builder.li do
|
374
|
+
error = after['result']['error_message'].split("\n")
|
375
|
+
@builder.span(:style => "color:#{COLOR[:failed]}") do
|
376
|
+
error[0..-2].each do |line|
|
377
|
+
@builder << line + '<br/>'
|
378
|
+
end
|
379
|
+
end
|
380
|
+
@builder << "<strong>Hook: </strong>#{error[-1]} <br/>"
|
381
|
+
@builder << "<strong>Scenario: </strong>#{scenario['name']} <br/><hr/>"
|
382
|
+
end
|
383
|
+
end
|
391
384
|
end
|
392
385
|
|
393
386
|
def self.features(files)
|
394
387
|
files.each_with_object([]) { |file, features|
|
395
|
-
|
388
|
+
data = File.read(file)
|
389
|
+
next if data.empty?
|
390
|
+
features << JSON.parse(data)
|
396
391
|
}.flatten.group_by { |feature|
|
397
392
|
feature['uri']+feature['id']+feature['line'].to_s
|
398
393
|
}.values.each_with_object([]) { |group, features|
|
@@ -461,7 +456,7 @@ class ReportBuilder
|
|
461
456
|
files = if path.is_a? String
|
462
457
|
(path =~ /\.json$/) ? [path] : Dir.glob("#{path}/*.json")
|
463
458
|
elsif path.nil?
|
464
|
-
Dir.glob(
|
459
|
+
Dir.glob('*.json')
|
465
460
|
elsif path.is_a? Array
|
466
461
|
path.map do |file|
|
467
462
|
(file =~ /\.json$/) ? file : Dir.glob("#{file}/*.json")
|
@@ -531,5 +526,9 @@ class ReportBuilder
|
|
531
526
|
private_class_method :donut_js, :pie_chart_js, :files,
|
532
527
|
:features, :feature_status,
|
533
528
|
:scenarios, :scenario_status, :steps,
|
534
|
-
:data, :duration, :total_time
|
529
|
+
:data, :duration, :total_time,
|
530
|
+
:build_scenario, :build_step,
|
531
|
+
:build_menu, :build_output, :build_embedding,
|
532
|
+
:build_error_list, :build_step_error,
|
533
|
+
:build_hook_error, :build_step_hook_error
|
535
534
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: report_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rajat Thareja
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: builder
|