closer 0.5.5 → 0.6.0
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 +5 -5
- data/HISTORY.md +7 -0
- data/closer.gemspec +3 -3
- data/lib/closer/formatter/closer_html.rb +2 -6
- data/lib/closer/formatter/html.rb +175 -252
- data/lib/closer/formatter/html_builder.rb +144 -0
- data/lib/closer/formatter/jquery-min.js +154 -4
- data/lib/closer/version.rb +1 -1
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 74f23eec764f2465f266ac3ccbd0c31c128d849de9775b9fac70cebe407e0f39
|
4
|
+
data.tar.gz: aee97eff5fec4ca6422878f3d67ed722d46e17feaaf649d549f5776dced70c03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12a70b65bd851a1860ac84639e56a9f31c6c8f6ae18ccb74591c25b633f25615249d53d975d0dc1787bac78f1bce73fcaeca5fa4b71de2ea74f7b7aa604bd040
|
7
|
+
data.tar.gz: 5c28933a567304c82f8a99d90a9f97f163ba8681908e0fa9c81f26e63e004204015f50b78ad3e4de2c79359eb22092047c29a948c8caaa4d959645d715c730f7
|
data/HISTORY.md
CHANGED
data/closer.gemspec
CHANGED
@@ -17,13 +17,13 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features|user_stories)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
-
spec.required_ruby_version = '~> 2.
|
20
|
+
spec.required_ruby_version = '~> 2.2'
|
21
21
|
|
22
|
-
spec.add_runtime_dependency 'cucumber', '>=
|
22
|
+
spec.add_runtime_dependency 'cucumber', '>= 3.0', '<= 4.0'
|
23
23
|
spec.add_runtime_dependency 'poltergeist', '>= 1.16'
|
24
24
|
spec.add_runtime_dependency 'selenium-webdriver', '~> 3.0'
|
25
25
|
|
26
|
-
spec.add_development_dependency 'bundler', '~> 1.
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
27
27
|
spec.add_development_dependency 'minitest', '~> 5.10'
|
28
28
|
spec.add_development_dependency 'rake', '~> 12.0'
|
29
29
|
end
|
@@ -12,7 +12,7 @@ module Closer
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def gem_dir
|
15
|
-
File.join(Gem.dir, 'gems')
|
15
|
+
::File.join(Gem.dir, 'gems')
|
16
16
|
end
|
17
17
|
|
18
18
|
def feature_id
|
@@ -38,10 +38,6 @@ module Closer
|
|
38
38
|
ret
|
39
39
|
end
|
40
40
|
|
41
|
-
def should_expand
|
42
|
-
['t', 'true'].include?(ENV['EXPAND'].to_s.downcase)
|
43
|
-
end
|
44
|
-
|
45
41
|
def magic_comment?(comment_line)
|
46
42
|
comment = comment_line.to_s
|
47
43
|
|
@@ -53,7 +49,7 @@ module Closer
|
|
53
49
|
end
|
54
50
|
|
55
51
|
def current_time_string
|
56
|
-
Time.now.instance_eval{ '%s%03d' % [strftime('%Y%m%d%H%M%S'), (usec / 1000.0).round] }
|
52
|
+
::Time.now.instance_eval{ '%s%03d' % [strftime('%Y%m%d%H%M%S'), (usec / 1000.0).round] }
|
57
53
|
end
|
58
54
|
|
59
55
|
def display_keyword(keyword)
|
@@ -1,163 +1,149 @@
|
|
1
1
|
require 'erb'
|
2
|
-
require 'builder'
|
3
2
|
require 'cucumber/formatter/duration'
|
4
3
|
require 'cucumber/formatter/io'
|
4
|
+
require 'cucumber/core/report/summary'
|
5
|
+
require 'cucumber/core/test/result'
|
5
6
|
require 'pathname'
|
7
|
+
require_relative 'html_builder'
|
6
8
|
require_relative 'closer_html'
|
7
9
|
|
8
10
|
module Closer
|
9
11
|
module Formatter
|
10
12
|
class Html
|
13
|
+
include CloserHtml
|
11
14
|
|
12
|
-
#
|
15
|
+
# TODO: remove coupling to types
|
13
16
|
AST_CLASSES = {
|
14
17
|
Cucumber::Core::Ast::Scenario => 'scenario',
|
15
18
|
Cucumber::Core::Ast::ScenarioOutline => 'scenario outline'
|
16
19
|
}
|
20
|
+
|
17
21
|
AST_DATA_TABLE = ::Cucumber::Formatter::LegacyApi::Ast::MultilineArg::DataTable
|
18
22
|
|
19
23
|
include ERB::Util # for the #h method
|
20
24
|
include ::Cucumber::Formatter::Duration
|
21
25
|
include ::Cucumber::Formatter::Io
|
22
|
-
|
26
|
+
|
27
|
+
attr_reader :builder
|
28
|
+
private :builder
|
23
29
|
|
24
30
|
def initialize(runtime, path_or_io, options)
|
25
31
|
@io = ensure_io(path_or_io)
|
26
32
|
@runtime = runtime
|
27
33
|
@options = options
|
28
34
|
@buffer = {}
|
29
|
-
@builder =
|
35
|
+
@builder = HtmlBuilder.new(target: @io, indent: 0)
|
30
36
|
@feature_number = 0
|
31
37
|
@scenario_number = 0
|
32
38
|
@step_number = 0
|
33
39
|
@header_red = nil
|
34
40
|
@delayed_messages = []
|
35
|
-
@
|
36
|
-
@text_id = 0
|
37
|
-
@inside_outline = false
|
41
|
+
@inside_outline = false
|
38
42
|
@previous_step_keyword = nil
|
43
|
+
@summary = ::Cucumber::Core::Report::Summary.new(runtime.configuration.event_bus)
|
39
44
|
end
|
40
45
|
|
41
46
|
def before_features(features)
|
42
47
|
@step_count = features && features.step_count || 0 #TODO: Make this work with core!
|
43
48
|
|
44
|
-
|
45
|
-
|
46
|
-
@builder << '<html>'
|
47
|
-
@builder.head do
|
48
|
-
@builder.meta('http-equiv' => 'Content-Type', :content => 'text/html;charset=utf-8')
|
49
|
-
@builder.title 'Cucumber'
|
50
|
-
inline_css
|
51
|
-
inline_js
|
52
|
-
end
|
53
|
-
@builder << '<body>'
|
54
|
-
@builder << "<!-- Step count #{@step_count}-->"
|
55
|
-
@builder << '<div class="cucumber">'
|
56
|
-
@builder.div(:id => 'cucumber-header') do
|
57
|
-
@builder.div(:id => 'label') do
|
58
|
-
@builder.h1('Cucumber Features')
|
59
|
-
end
|
60
|
-
@builder.div(:id => 'summary') do
|
61
|
-
@builder.p('',:id => 'totals')
|
62
|
-
@builder.p('',:id => 'duration')
|
63
|
-
@builder.div(:id => 'expand-collapse') do
|
64
|
-
@builder.p('Expand All', :id => 'expander')
|
65
|
-
@builder.p('Collapse All', :id => 'collapser')
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
49
|
+
builder.build_document!
|
50
|
+
builder.format_features! features
|
69
51
|
end
|
70
52
|
|
71
53
|
def after_features(features)
|
72
54
|
print_stats(features)
|
73
|
-
|
74
|
-
|
75
|
-
|
55
|
+
builder << '</div>'
|
56
|
+
builder << '</body>'
|
57
|
+
builder << '</html>'
|
76
58
|
end
|
77
59
|
|
78
|
-
def before_feature(
|
79
|
-
dir = feature_dir(
|
60
|
+
def before_feature(_feature)
|
61
|
+
dir = feature_dir(_feature)
|
80
62
|
unless dir.empty?
|
81
63
|
if @feature_dir != dir
|
82
|
-
|
83
|
-
|
84
|
-
|
64
|
+
builder << '<div class="feature_dir"><span class="val" onclick="toggle_feature_dir(this);">'
|
65
|
+
builder << dir
|
66
|
+
builder << '</span></div>'
|
85
67
|
end
|
86
68
|
|
87
69
|
@feature_dir = dir
|
88
70
|
end
|
89
71
|
|
90
|
-
@feature =
|
72
|
+
@feature = _feature
|
91
73
|
@exceptions = []
|
92
|
-
|
74
|
+
builder << "<div id=\"#{feature_id}\" class=\"feature\">"
|
93
75
|
end
|
94
76
|
|
95
|
-
def after_feature(
|
96
|
-
|
77
|
+
def after_feature(_feature)
|
78
|
+
builder << '</div>'
|
97
79
|
end
|
98
80
|
|
99
|
-
def before_comment(
|
100
|
-
|
81
|
+
def before_comment(_comment)
|
82
|
+
return if magic_comment?(_comment)
|
83
|
+
|
84
|
+
builder << '<pre class="comment">'
|
101
85
|
end
|
102
86
|
|
103
|
-
def after_comment(
|
104
|
-
|
87
|
+
def after_comment(_comment)
|
88
|
+
return if magic_comment?(_comment)
|
89
|
+
|
90
|
+
builder << '</pre>'
|
105
91
|
end
|
106
92
|
|
107
93
|
def comment_line(comment_line)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
94
|
+
return if magic_comment?(comment_line)
|
95
|
+
|
96
|
+
builder.text!(comment_line)
|
97
|
+
builder.br
|
112
98
|
end
|
113
99
|
|
114
|
-
def after_tags(
|
100
|
+
def after_tags(_tags)
|
115
101
|
@tag_spacer = nil
|
116
102
|
end
|
117
103
|
|
118
104
|
def tag_name(tag_name)
|
119
|
-
|
105
|
+
builder.text!(@tag_spacer) if @tag_spacer
|
120
106
|
@tag_spacer = ' '
|
121
|
-
|
107
|
+
builder.span(tag_name, :class => 'tag')
|
122
108
|
end
|
123
109
|
|
124
110
|
def feature_name(keyword, name)
|
125
111
|
title = feature_dir(@feature, true) + @feature.file.split('/').last.gsub(/\.feature/, '')
|
126
112
|
lines = name.split(/\r?\n/)
|
127
113
|
return if lines.empty?
|
128
|
-
|
129
|
-
|
130
|
-
|
114
|
+
builder.h2 do |h2|
|
115
|
+
builder.span(:class => 'val') do
|
116
|
+
builder << title
|
131
117
|
end
|
132
118
|
end
|
133
119
|
|
134
120
|
if lines.size > 1
|
135
|
-
|
136
|
-
|
121
|
+
builder.div(:class => 'narrative') do
|
122
|
+
builder << lines[1..-1].join("\n")
|
137
123
|
end
|
138
124
|
end
|
139
125
|
end
|
140
126
|
|
141
|
-
def before_test_case(
|
127
|
+
def before_test_case(_test_case)
|
142
128
|
@previous_step_keyword = nil
|
143
129
|
end
|
144
130
|
|
145
|
-
def before_background(
|
131
|
+
def before_background(_background)
|
146
132
|
@in_background = true
|
147
|
-
|
133
|
+
builder << '<div class="background">'
|
148
134
|
end
|
149
135
|
|
150
|
-
def after_background(
|
136
|
+
def after_background(_background)
|
151
137
|
@in_background = nil
|
152
|
-
|
138
|
+
builder << '</div>'
|
153
139
|
end
|
154
140
|
|
155
|
-
def background_name(keyword, name,
|
141
|
+
def background_name(keyword, name, _file_colon_line, _source_indent)
|
156
142
|
@listing_background = true
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
143
|
+
builder.h3(:id => "background_#{@scenario_number}") do |h3|
|
144
|
+
builder.span(keyword, :class => 'keyword')
|
145
|
+
builder.text!(' ')
|
146
|
+
builder.span(name, :class => 'val')
|
161
147
|
end
|
162
148
|
end
|
163
149
|
|
@@ -165,22 +151,22 @@ module Closer
|
|
165
151
|
@scenario_number+=1
|
166
152
|
@scenario_red = false
|
167
153
|
css_class = AST_CLASSES[feature_element.class]
|
168
|
-
|
154
|
+
builder << "<div class='#{css_class}'>"
|
169
155
|
@in_scenario_outline = feature_element.class == Cucumber::Core::Ast::ScenarioOutline
|
170
156
|
end
|
171
157
|
|
172
|
-
def after_feature_element(
|
158
|
+
def after_feature_element(_feature_element)
|
173
159
|
unless @in_scenario_outline
|
174
160
|
print_messages
|
175
|
-
|
161
|
+
builder << '</ol>'
|
176
162
|
end
|
177
|
-
|
163
|
+
builder << '</div>'
|
178
164
|
@in_scenario_outline = nil
|
179
165
|
end
|
180
166
|
|
181
|
-
def scenario_name(keyword, name, file_colon_line,
|
182
|
-
|
183
|
-
|
167
|
+
def scenario_name(keyword, name, file_colon_line, _source_indent)
|
168
|
+
builder.span(:class => 'scenario_file hidden') do
|
169
|
+
builder << file_colon_line
|
184
170
|
end
|
185
171
|
@listing_background = false
|
186
172
|
scenario_id = "scenario_#{@scenario_number}"
|
@@ -192,53 +178,53 @@ module Closer
|
|
192
178
|
|
193
179
|
lines = name.split("\n")
|
194
180
|
title = lines.shift
|
195
|
-
|
196
|
-
|
181
|
+
builder.h3(:id => scenario_id) do
|
182
|
+
builder.span(title, :class => 'val pointer')
|
197
183
|
end
|
198
184
|
|
199
185
|
if lines.size > 0
|
200
|
-
|
186
|
+
builder.pre(:class => 'narrative hidden') do
|
201
187
|
trim_size = indent_size(lines.first)
|
202
|
-
|
188
|
+
builder << lines.map{|line| line[trim_size..-1] }.join("\n")
|
203
189
|
end
|
204
190
|
end
|
205
191
|
end
|
206
192
|
|
207
|
-
def before_outline_table(
|
193
|
+
def before_outline_table(_outline_table)
|
208
194
|
@inside_outline = true
|
209
195
|
@outline_row = 0
|
210
|
-
|
196
|
+
builder << '<table>'
|
211
197
|
end
|
212
198
|
|
213
|
-
def after_outline_table(
|
214
|
-
|
199
|
+
def after_outline_table(_outline_table)
|
200
|
+
builder << '</table>'
|
215
201
|
@outline_row = nil
|
216
202
|
@inside_outline = false
|
217
203
|
end
|
218
204
|
|
219
|
-
def before_examples(
|
220
|
-
|
205
|
+
def before_examples(_examples)
|
206
|
+
builder << '<div class="examples">'
|
221
207
|
end
|
222
208
|
|
223
|
-
def after_examples(
|
224
|
-
|
209
|
+
def after_examples(_examples)
|
210
|
+
builder << '</div>'
|
225
211
|
end
|
226
212
|
|
227
213
|
def examples_name(keyword, name)
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
214
|
+
builder.h4 do
|
215
|
+
builder.span(keyword, :class => 'keyword')
|
216
|
+
builder.text!(' ')
|
217
|
+
builder.span(name, :class => 'val')
|
232
218
|
end
|
233
219
|
end
|
234
220
|
|
235
|
-
def before_steps(
|
236
|
-
|
221
|
+
def before_steps(_steps)
|
222
|
+
builder << '<ol class="hidden">'
|
237
223
|
end
|
238
224
|
|
239
|
-
def after_steps(
|
225
|
+
def after_steps(_steps)
|
240
226
|
print_messages
|
241
|
-
|
227
|
+
builder << '</ol>' if @in_background || @in_scenario_outline
|
242
228
|
end
|
243
229
|
|
244
230
|
def before_step(step)
|
@@ -248,10 +234,10 @@ module Closer
|
|
248
234
|
@step = step
|
249
235
|
end
|
250
236
|
|
251
|
-
def after_step(
|
237
|
+
def after_step(_step)
|
252
238
|
end
|
253
239
|
|
254
|
-
def before_step_result(
|
240
|
+
def before_step_result(_keyword, step_match, _multiline_arg, status, exception, _source_indent, background, _file_colon_line)
|
255
241
|
@step_match = step_match
|
256
242
|
@hide_this_step = false
|
257
243
|
if exception
|
@@ -270,13 +256,13 @@ module Closer
|
|
270
256
|
set_scenario_color(status)
|
271
257
|
|
272
258
|
if ! @delayed_messages.empty? and status == :passed
|
273
|
-
|
259
|
+
builder << "<li id='#{@step_id}' class='step #{status} expand'>"
|
274
260
|
else
|
275
|
-
|
261
|
+
builder << "<li id='#{@step_id}' class='step #{status}'>"
|
276
262
|
end
|
277
263
|
end
|
278
264
|
|
279
|
-
def after_step_result(keyword, step_match,
|
265
|
+
def after_step_result(keyword, step_match, _multiline_arg, status, _exception, _source_indent, _background, _file_colon_line)
|
280
266
|
return if @hide_this_step
|
281
267
|
# print snippet for undefined steps
|
282
268
|
unless outline_step?(@step)
|
@@ -284,13 +270,13 @@ module Closer
|
|
284
270
|
@previous_step_keyword = keyword
|
285
271
|
end
|
286
272
|
if status == :undefined
|
287
|
-
|
288
|
-
# TODO: snippet text should be an event sent to the formatter so we don't
|
273
|
+
builder.pre do |pre|
|
274
|
+
# TODO: snippet text should be an event sent to the formatter so we don't
|
289
275
|
# have this couping to the runtime.
|
290
|
-
pre << @runtime.snippet_text(keyword,step_match.instance_variable_get(
|
276
|
+
pre << @runtime.snippet_text(keyword,step_match.instance_variable_get('@name') || '', @step.multiline_arg)
|
291
277
|
end
|
292
278
|
end
|
293
|
-
|
279
|
+
builder << '</li>'
|
294
280
|
|
295
281
|
unless status == :undefined
|
296
282
|
step_file = step_match.file_colon_line
|
@@ -306,13 +292,13 @@ module Closer
|
|
306
292
|
end
|
307
293
|
end
|
308
294
|
step_contents << "</pre></div>"
|
309
|
-
|
295
|
+
builder << step_contents
|
310
296
|
end
|
311
297
|
|
312
298
|
print_messages
|
313
299
|
end
|
314
300
|
|
315
|
-
def step_name(keyword, step_match, status,
|
301
|
+
def step_name(keyword, step_match, status, _source_indent, background, _file_colon_line)
|
316
302
|
background_in_scenario = background && !@listing_background
|
317
303
|
@skip_step = background_in_scenario
|
318
304
|
|
@@ -321,7 +307,7 @@ module Closer
|
|
321
307
|
end
|
322
308
|
end
|
323
309
|
|
324
|
-
def exception(exception,
|
310
|
+
def exception(exception, _status)
|
325
311
|
return if @hide_this_step
|
326
312
|
print_messages
|
327
313
|
build_exception_detail(exception)
|
@@ -335,21 +321,21 @@ module Closer
|
|
335
321
|
def before_multiline_arg(multiline_arg)
|
336
322
|
return if @hide_this_step || @skip_step
|
337
323
|
if AST_DATA_TABLE === multiline_arg
|
338
|
-
|
324
|
+
builder << '<table>'
|
339
325
|
end
|
340
326
|
end
|
341
327
|
|
342
328
|
def after_multiline_arg(multiline_arg)
|
343
329
|
return if @hide_this_step || @skip_step
|
344
330
|
if AST_DATA_TABLE === multiline_arg
|
345
|
-
|
331
|
+
builder << '</table>'
|
346
332
|
end
|
347
333
|
end
|
348
334
|
|
349
335
|
def doc_string(string)
|
350
336
|
return if @hide_this_step
|
351
|
-
|
352
|
-
|
337
|
+
builder.pre(:class => 'val') do |pre|
|
338
|
+
builder << h(string).gsub("\n", '
')
|
353
339
|
end
|
354
340
|
end
|
355
341
|
|
@@ -357,17 +343,17 @@ module Closer
|
|
357
343
|
@row_id = table_row.dom_id
|
358
344
|
@col_index = 0
|
359
345
|
return if @hide_this_step
|
360
|
-
|
346
|
+
builder << "<tr class='step' id='#{@row_id}'>"
|
361
347
|
end
|
362
348
|
|
363
349
|
def after_table_row(table_row)
|
364
350
|
return if @hide_this_step
|
365
351
|
print_table_row_messages
|
366
|
-
|
352
|
+
builder << '</tr>'
|
367
353
|
if table_row.exception
|
368
|
-
|
369
|
-
|
370
|
-
|
354
|
+
builder.tr do
|
355
|
+
builder.td(:colspan => @col_index.to_s, :class => 'failed') do
|
356
|
+
builder.pre do |pre|
|
371
357
|
pre << h(format_exception(table_row.exception))
|
372
358
|
end
|
373
359
|
end
|
@@ -397,16 +383,16 @@ module Closer
|
|
397
383
|
|
398
384
|
def puts(message)
|
399
385
|
@delayed_messages << message
|
400
|
-
|
386
|
+
#builder.pre(message, :class => 'message')
|
401
387
|
end
|
402
388
|
|
403
389
|
def print_messages
|
404
390
|
return if @delayed_messages.empty?
|
405
391
|
|
406
|
-
|
392
|
+
#builder.ol do
|
407
393
|
@delayed_messages.each do |ann|
|
408
|
-
|
409
|
-
|
394
|
+
builder.li(:class => 'message hidden') do
|
395
|
+
builder << ann
|
410
396
|
end
|
411
397
|
end
|
412
398
|
#end
|
@@ -416,8 +402,8 @@ module Closer
|
|
416
402
|
def print_table_row_messages
|
417
403
|
return if @delayed_messages.empty?
|
418
404
|
|
419
|
-
|
420
|
-
|
405
|
+
builder.td(:class => 'message') do
|
406
|
+
builder << @delayed_messages.join(', ')
|
421
407
|
end
|
422
408
|
empty_messages
|
423
409
|
end
|
@@ -426,8 +412,8 @@ module Closer
|
|
426
412
|
@delayed_messages = []
|
427
413
|
end
|
428
414
|
|
429
|
-
def after_test_case(
|
430
|
-
if result.failed?
|
415
|
+
def after_test_case(_test_case, result)
|
416
|
+
if result.failed? && !@scenario_red
|
431
417
|
set_scenario_color_failed
|
432
418
|
end
|
433
419
|
end
|
@@ -436,36 +422,40 @@ module Closer
|
|
436
422
|
|
437
423
|
def build_exception_detail(exception)
|
438
424
|
backtrace = Array.new
|
439
|
-
|
425
|
+
|
426
|
+
builder.div(:class => 'message') do
|
440
427
|
message = exception.message
|
428
|
+
|
441
429
|
if defined?(RAILS_ROOT) && message.include?('Exception caught')
|
442
430
|
matches = message.match(/Showing <i>(.+)<\/i>(?:.+) #(\d+)/)
|
443
431
|
backtrace += ["#{RAILS_ROOT}/#{matches[1]}:#{matches[2]}"] if matches
|
444
432
|
matches = message.match(/<code>([^(\/)]+)<\//m)
|
445
|
-
message = matches ? matches[1] :
|
433
|
+
message = matches ? matches[1] : ''
|
446
434
|
end
|
447
435
|
|
448
436
|
unless exception.instance_of?(RuntimeError)
|
449
437
|
message = "#{message} (#{exception.class})"
|
450
438
|
end
|
451
439
|
|
452
|
-
|
453
|
-
|
440
|
+
builder.pre do
|
441
|
+
builder.text!(message)
|
454
442
|
end
|
455
443
|
end
|
456
|
-
|
457
|
-
|
444
|
+
|
445
|
+
builder.div(:class => 'backtrace') do
|
446
|
+
builder.pre do
|
458
447
|
backtrace = exception.backtrace
|
459
448
|
backtrace.delete_if { |x| x =~ /\/gems\/(cucumber|rspec)/ }
|
460
|
-
|
449
|
+
builder << backtrace_line(backtrace.join("\n"))
|
461
450
|
end
|
462
451
|
end
|
452
|
+
|
463
453
|
extra = extra_failure_content(backtrace)
|
464
|
-
|
454
|
+
builder << extra unless extra == ''
|
465
455
|
end
|
466
456
|
|
467
457
|
def set_scenario_color(status)
|
468
|
-
if status.nil?
|
458
|
+
if status.nil? || status == :undefined || status == :pending
|
469
459
|
set_scenario_color_pending
|
470
460
|
end
|
471
461
|
if status == :failed
|
@@ -474,32 +464,32 @@ module Closer
|
|
474
464
|
end
|
475
465
|
|
476
466
|
def set_scenario_color_failed
|
477
|
-
|
478
|
-
|
467
|
+
builder.script do
|
468
|
+
builder.text!("makeRed('cucumber-header');") unless @header_red
|
479
469
|
@header_red = true
|
480
|
-
scenario_or_background = @in_background ?
|
481
|
-
|
470
|
+
scenario_or_background = @in_background ? 'background' : 'scenario'
|
471
|
+
builder.text!("makeRed('#{scenario_or_background}_#{@scenario_number}');") unless @scenario_red
|
482
472
|
@scenario_red = true
|
483
|
-
if @options[:expand]
|
484
|
-
|
473
|
+
if @options[:expand] && @inside_outline
|
474
|
+
builder.text!("makeRed('#{scenario_or_background}_#{@scenario_number}_#{@outline_row}');")
|
485
475
|
end
|
486
476
|
end
|
487
477
|
end
|
488
478
|
|
489
479
|
def set_scenario_color_pending
|
490
|
-
|
491
|
-
|
492
|
-
scenario_or_background = @in_background ?
|
493
|
-
|
480
|
+
builder.script do
|
481
|
+
builder.text!("makeYellow('cucumber-header');") unless @header_red
|
482
|
+
scenario_or_background = @in_background ? 'background' : 'scenario'
|
483
|
+
builder.text!("makeYellow('#{scenario_or_background}_#{@scenario_number}');") unless @scenario_red
|
494
484
|
end
|
495
485
|
end
|
496
486
|
|
497
|
-
def build_step(keyword, step_match,
|
487
|
+
def build_step(keyword, step_match, _status)
|
498
488
|
keyword = display_keyword(keyword)
|
499
489
|
step_name = step_match.format_args(lambda{|param| %{<span class="param">#{param}</span>}})
|
500
|
-
|
501
|
-
|
502
|
-
|
490
|
+
builder.div(:class => 'step_name') do |div|
|
491
|
+
builder.span(keyword, :class => 'keyword')
|
492
|
+
builder.span(:class => 'step val') do |name|
|
503
493
|
name << h(step_name).gsub(/<span class="(.*?)">/, '<span class="\1">').gsub(/<\/span>/, '</span>')
|
504
494
|
end
|
505
495
|
end
|
@@ -508,97 +498,24 @@ module Closer
|
|
508
498
|
step_file.gsub(/^([^:]*\.rb):(\d*)/) do
|
509
499
|
step_file = "<span class=\"pointer\" onclick=\"toggle_step_file(this); return false;\">#{step_file}</span>"
|
510
500
|
|
511
|
-
|
512
|
-
|
513
|
-
|
501
|
+
builder.div(:class => 'step_file') do |div|
|
502
|
+
builder.span do
|
503
|
+
builder << step_file
|
514
504
|
end
|
515
505
|
end
|
516
506
|
end
|
517
507
|
end
|
518
508
|
|
519
509
|
def build_cell(cell_type, value, attributes)
|
520
|
-
|
521
|
-
|
522
|
-
|
510
|
+
builder.__send__(cell_type, attributes) do
|
511
|
+
builder.div do
|
512
|
+
builder.span(value,:class => 'step param')
|
523
513
|
end
|
524
514
|
end
|
525
515
|
end
|
526
516
|
|
527
|
-
def inline_css
|
528
|
-
@builder.style do
|
529
|
-
@builder << File.read(File.dirname(__FILE__) + '/cucumber.css')
|
530
|
-
@builder << File.read(File.dirname(__FILE__) + '/closer.css')
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
|
-
def inline_js
|
535
|
-
@builder.script do
|
536
|
-
@builder << inline_jquery
|
537
|
-
@builder << inline_js_content
|
538
|
-
@builder << inline_closer
|
539
|
-
end
|
540
|
-
end
|
541
|
-
|
542
|
-
def inline_jquery
|
543
|
-
File.read(File.dirname(__FILE__) + '/jquery-min.js')
|
544
|
-
end
|
545
|
-
|
546
|
-
def inline_closer
|
547
|
-
ret = ''
|
548
|
-
ret << File.read(File.join(File.dirname(__FILE__), 'closer.js'))
|
549
|
-
ret << File.read(File.join(File.dirname(__FILE__), 'screenshot.js'))
|
550
|
-
|
551
|
-
if should_expand
|
552
|
-
ret << %w{
|
553
|
-
$(document).ready(function() {
|
554
|
-
$('#expander').click();
|
555
|
-
});
|
556
|
-
}.join(' ')
|
557
|
-
end
|
558
|
-
|
559
|
-
ret
|
560
|
-
end
|
561
|
-
|
562
|
-
def inline_js_content
|
563
|
-
<<-EOF
|
564
|
-
|
565
|
-
SCENARIOS = "h3[id^='scenario_'],h3[id^=background_]";
|
566
|
-
|
567
|
-
$(document).ready(function() {
|
568
|
-
$(SCENARIOS).delegate('.val', 'click', function() {
|
569
|
-
$(this).parent().siblings().toggle(100);
|
570
|
-
});
|
571
|
-
|
572
|
-
$("#collapser").css('cursor', 'pointer');
|
573
|
-
$("#collapser").click(function() {
|
574
|
-
$(SCENARIOS).siblings().addClass('hidden');
|
575
|
-
$('li.message').addClass('hidden');
|
576
|
-
});
|
577
|
-
|
578
|
-
$("#expander").css('cursor', 'pointer');
|
579
|
-
$("#expander").click(function() {
|
580
|
-
$(SCENARIOS).siblings().removeClass('hidden');
|
581
|
-
$('li.message').removeClass('hidden');
|
582
|
-
});
|
583
|
-
})
|
584
|
-
|
585
|
-
function moveProgressBar(percentDone) {
|
586
|
-
$("cucumber-header").css('width', percentDone +"%");
|
587
|
-
}
|
588
|
-
function makeRed(element_id) {
|
589
|
-
$('#'+element_id).css('background', '#C40D0D');
|
590
|
-
$('#'+element_id).css('color', '#FFFFFF');
|
591
|
-
}
|
592
|
-
function makeYellow(element_id) {
|
593
|
-
$('#'+element_id).css('background', '#FAF834');
|
594
|
-
$('#'+element_id).css('color', '#000000');
|
595
|
-
}
|
596
|
-
|
597
|
-
EOF
|
598
|
-
end
|
599
|
-
|
600
517
|
def format_exception(exception)
|
601
|
-
([
|
518
|
+
([exception.message.to_s] + exception.backtrace).join("\n")
|
602
519
|
end
|
603
520
|
|
604
521
|
def backtrace_line(line)
|
@@ -608,44 +525,50 @@ module Closer
|
|
608
525
|
end
|
609
526
|
|
610
527
|
def print_stats(features)
|
611
|
-
|
612
|
-
|
528
|
+
builder << "<script>document.getElementById('duration').innerHTML = \"Finished in <strong>#{format_duration(features.duration)} seconds</strong>\";</script>"
|
529
|
+
builder << "<script>document.getElementById('totals').innerHTML = \"#{print_stat_string(features)}\";</script>"
|
613
530
|
end
|
614
531
|
|
615
|
-
def print_stat_string(
|
532
|
+
def print_stat_string(_features)
|
616
533
|
string = String.new
|
617
|
-
string << dump_count(@
|
618
|
-
scenario_count =
|
534
|
+
string << dump_count(@summary.test_cases.total, 'scenario')
|
535
|
+
scenario_count = status_counts(@summary.test_cases)
|
619
536
|
string << scenario_count if scenario_count
|
620
|
-
string <<
|
621
|
-
string << dump_count(@
|
622
|
-
step_count =
|
537
|
+
string << '<br />'
|
538
|
+
string << dump_count(@summary.test_steps.total, 'step')
|
539
|
+
step_count = status_counts(@summary.test_steps)
|
623
540
|
string << step_count if step_count
|
624
541
|
end
|
625
542
|
|
626
|
-
def
|
627
|
-
counts =
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
543
|
+
def status_counts(summary)
|
544
|
+
counts = ::Cucumber::Core::Test::Result::TYPES.map { |status|
|
545
|
+
count = summary.total(status)
|
546
|
+
[status, count]
|
547
|
+
}.select { |status, count|
|
548
|
+
count > 0
|
549
|
+
}.map { |status, count|
|
550
|
+
"#{count} #{status}"
|
551
|
+
}
|
552
|
+
"(#{counts.join(", ")})" if counts.any?
|
632
553
|
end
|
633
554
|
|
634
555
|
def dump_count(count, what, state=nil)
|
635
|
-
[count, state, "#{what}#{count == 1 ? '' : 's'}"].compact.join(
|
636
|
-
end
|
637
|
-
|
638
|
-
def create_builder(io)
|
639
|
-
Builder::XmlMarkup.new(:target => io, :indent => 0)
|
556
|
+
[count, state, "#{what}#{count == 1 ? '' : 's'}"].compact.join(' ')
|
640
557
|
end
|
641
558
|
|
642
|
-
def outline_step?(
|
559
|
+
def outline_step?(_step)
|
643
560
|
not @step.step.respond_to?(:actual_keyword)
|
644
561
|
end
|
645
562
|
|
646
563
|
class SnippetExtractor #:nodoc:
|
647
|
-
class NullConverter; def convert(code,
|
648
|
-
|
564
|
+
class NullConverter; def convert(code, _pre); code; end; end #:nodoc:
|
565
|
+
|
566
|
+
begin
|
567
|
+
require 'syntax/convertors/html'
|
568
|
+
@@converter = Syntax::Convertors::HTML.for_syntax 'ruby'
|
569
|
+
rescue LoadError
|
570
|
+
@@converter = NullConverter.new
|
571
|
+
end
|
649
572
|
|
650
573
|
def snippet(error)
|
651
574
|
raw_code, line = snippet_for(error[0])
|
@@ -694,4 +617,4 @@ module Closer
|
|
694
617
|
end
|
695
618
|
end
|
696
619
|
end
|
697
|
-
end
|
620
|
+
end
|