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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/report_builder.rb +301 -302
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 601a48967da3d12319d801c9febed718aa5a856a
4
- data.tar.gz: 253cda6a5c4fc55185f11789ac6c8892296a0008
3
+ metadata.gz: 3548db4c70ef0f5d6fae4c9b69fd3da24fd09a7c
4
+ data.tar.gz: ee9feecdbb0c1ed8574b7e87d89bde602906a4b5
5
5
  SHA512:
6
- metadata.gz: faa57482fbc784b5d48d30a64fd67b6533acff31077cd5d7e630d6a7689584871442f13b36061f531a6987a54471f6470d082bb78bde259e235ad6d48b3203e9
7
- data.tar.gz: fcf99dddafcf2f6c177304bf4c52fde0197d4933e5c91bf5d3613eb992d70747ac41e4b21a46606227539d2c12a1aa3222ac420f11b096bb65f153aa77f20e48
6
+ metadata.gz: 81ef540f7558c9f8c3f1e37b7a2b9cf5effe24cc0b23499f16163b563859ffc2d833212622d30aaf51f3a63b1deffd48fc571d4a018dc19602c51f8880aa7902
7
+ data.tar.gz: 23ea000736d6905ac1195d209a1a7fc0830d7bd13e77a7ff66d033fc8f0ac321bbc80a89795a7c0b356d2efa0d8876497a5843bd1bf0903e5cf4e9636753a7fa
@@ -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
- # ReportBuilder.build_report('path/of/json/file.json')
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
- # ReportBuilder.build_report()
29
+ # ReportBuilder.build_report('path/of/json/cucumber.json')
27
30
  #
28
- # ReportBuilder::COLOR[:passed] = '#ffffff'
29
- # ReportBuilder.build_report()
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
- if output_file_type.include? 'json'
53
- File.open(output_file_name + '.json', "w") do |file|
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
- file = File.open(output_file_name + '.html', 'w:UTF-8')
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
- builder = Builder::XmlMarkup.new(:target => file, :indent => 0)
71
- builder.declare!(:DOCTYPE, :html)
72
- builder << '<html>'
82
+ @builder.head do
83
+ @builder.meta(charset: 'UTF-8')
84
+ @builder.title 'Test Results'
73
85
 
74
- builder.head do
75
- builder.meta(charset: 'UTF-8')
76
- builder.title 'Test Results'
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
- builder.style(:type => 'text/css') do
79
- builder << File.read(File.dirname(__FILE__) + '/../vendor/assets/stylesheets/jquery-ui.min.css')
80
- COLOR.each do |color|
81
- builder << ".#{color[0].to_s}{background:#{color[1]};color:#434348;padding:2px}"
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.script(:type => 'text/javascript') do
87
- %w(jquery-min jquery-ui.min highcharts highcharts-3d).each do |file|
88
- builder << File.read(File.dirname(__FILE__) + '/../vendor/assets/javascripts/' + file + '.js')
89
- end
90
- builder << '$(function(){$("#results").tabs();});'
91
- builder << "$(function(){$('#features').accordion({collapsible: true, heightStyle: 'content', active: false, icons: false});});"
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 << "$(function(){$('#status').accordion({collapsible: true, heightStyle: 'content', active: false, icons: false});});"
117
+ @builder << ') ~ ' + all_scenarios.size.to_s + ' scenario ('
96
118
  scenario_data.each do |data|
97
- builder << "$(function(){$('##{data[:name]}').accordion({collapsible: true, heightStyle: 'content', active: false, icons: false});});"
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
- builder.div(:id => 'results') do
128
+ @builder.div(:id => 'results') do
129
+ build_menu %w(overview features scenarios errors)
121
130
 
122
- builder.ul do
123
- %w(overview features scenarios errors).each do |tab|
124
- builder.li do
125
- builder.a(:href => "##{tab}Tab") do
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
- builder.div(:id => 'featuresTab') do
139
- builder.div(:id => 'features') do
140
- all_features.each_with_index do |feature, n|
141
- builder.h3 do
142
- builder.span(:class => feature['status']) do
143
- builder << "<strong>#{feature['keyword']}</strong> #{feature['name']} (#{duration(feature['duration'])})"
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
- end
146
- builder.div do
147
- builder.div(:id => "scenario#{n}") do
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
- builder.div(:id => 'scenariosTab') do
228
- builder.div(:id => 'status') do
229
- all_scenarios.group_by{|scenario| scenario['status']}.each do |data|
230
- builder.h3 do
231
- builder.sapn(:class => data[0]) do
232
- builder << "<strong>#{data[0].capitalize} scenarios (Count: #{data[1].size})</strong>"
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
- end
235
- builder.div do
236
- builder.div(:id => data[0]) do
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.div(:id => 'errorsTab') do
317
- builder.ol do
318
- all_scenarios.each do |scenario|
319
- scenario['before'].each do |before|
320
- next unless before['status'] == 'failed'
321
- builder.li do
322
- error = before['result']['error_message'].split("\n")
323
- builder.span(:style => "color:#{COLOR[:failed]}") do
324
- error[0..-2].each do |line|
325
- builder << line + '<br/>'
326
- end
327
- end
328
- builder << "<strong>Hook: </strong>#{error[-1]} <br/>"
329
- builder << "<strong>Scenario: </strong>#{scenario['name']}"
330
- end
331
- end
332
- scenario['steps'].each do |step|
333
- step['after'].each do |after|
334
- next unless after['status'] == 'failed'
335
- builder.li do
336
- error = after['result']['error_message'].split("\n")
337
- builder.span(:style => "color:#{COLOR[:failed]}") do
338
- (scenario['keyword'] == 'Scenario Outline' ? error[0..-6] : error[0..-4]).each do |line|
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
- builder.script(:type => 'text/javascript') do
377
- builder << pie_chart_js('featurePieChart', 'Features', feature_data)
378
- builder << donut_js('featureTabPieChart', 'Features', feature_data)
379
- builder << pie_chart_js('scenarioPieChart', 'Scenarios', scenario_data)
380
- builder << donut_js('scenarioTabPieChart', 'Scenarios', scenario_data)
381
- builder << pie_chart_js('stepPieChart', 'Steps', step_data)
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
- builder << '</body>'
385
- builder << '</html>'
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
- file.close
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",'&nbsp;&nbsp;').gsub(' ','&nbsp;')}</span>"
248
+ end if outputs.is_a?(Array)
249
+ end
388
250
 
389
- puts "HTML test report generated: '#{output_file_name}.html'"
390
- [total_time, feature_data, scenario_data, step_data]
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
- features << JSON.parse(File.read(file))
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("*.json")
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.7
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-10 00:00:00.000000000 Z
11
+ date: 2016-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: builder