report_builder 0.0.7 → 0.0.8
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/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
|