closer 0.12.0 → 0.13.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 +4 -4
- data/HISTORY.md +5 -0
- data/Rakefile +0 -1
- data/closer.gemspec +3 -3
- data/lib/closer/coverage/rcov_formatter.rb +3 -3
- data/lib/closer/formatter/html.rb +5 -611
- data/lib/closer/helpers/capture.rb +2 -2
- data/lib/closer/helpers/snapshot.rb +1 -1
- data/lib/closer/version.rb +1 -1
- data/lib/tasks/close.rake +1 -1
- metadata +5 -12
- data/lib/closer/formatter/closer.css +0 -192
- data/lib/closer/formatter/closer.js +0 -19
- data/lib/closer/formatter/closer_html.rb +0 -73
- data/lib/closer/formatter/cucumber.css +0 -287
- data/lib/closer/formatter/html_builder.rb +0 -144
- data/lib/closer/formatter/jquery-min.js +0 -154
- data/lib/closer/formatter/screenshot.js +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5c8127b7871c95d6b79f5be5a9034bdc0275f759b7e6a8111797cc836ac0d1a
|
4
|
+
data.tar.gz: af47e23f5c6c6e328c61b9fc914692d1e0d7837ac01ed425e5e22944090cc94d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b0f79b3cb25a32c990d3c62d56cd058323f7f59071c013ef817ac0f4798392738ced226987916fcb7f9c2dae62229ef14a9bca2dd84923e7167422ab7450752
|
7
|
+
data.tar.gz: 83530d41db510502c5201018ebd9c369759d4c5410dda5e2c552e924df6a2820ba3f2a0fce77b803e4016d6bd13d60c29614f9e59bbcf9ff79e03c99eabe585e
|
data/HISTORY.md
CHANGED
data/Rakefile
CHANGED
data/closer.gemspec
CHANGED
@@ -19,9 +19,9 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.required_ruby_version = '~> 2.7'
|
21
21
|
|
22
|
-
spec.
|
23
|
-
spec.
|
24
|
-
spec.
|
22
|
+
spec.add_dependency 'cucumber', '>= 4.0', '< 9.0'
|
23
|
+
spec.add_dependency 'capybara', '>= 3.0'
|
24
|
+
spec.add_dependency 'selenium-webdriver', '>= 4.8', '<= 5.0'
|
25
25
|
|
26
26
|
spec.add_development_dependency 'minitest', '~> 5.10'
|
27
27
|
spec.add_development_dependency 'rake', '~> 13.0'
|
@@ -3,11 +3,11 @@ require 'simplecov-rcov'
|
|
3
3
|
module Closer
|
4
4
|
module Coverage
|
5
5
|
class RcovFormatter < SimpleCov::Formatter::RcovFormatter
|
6
|
-
|
6
|
+
|
7
7
|
private
|
8
|
-
|
8
|
+
|
9
9
|
def write_file(template, output_filename, binding)
|
10
|
-
rcov_result = template.result(
|
10
|
+
rcov_result = template.result(binding).force_encoding('UTF-8')
|
11
11
|
|
12
12
|
File.open( output_filename, "w" ) do |file_result|
|
13
13
|
file_result.write rcov_result
|
@@ -1,620 +1,14 @@
|
|
1
|
-
require '
|
2
|
-
require 'cucumber/formatter/duration'
|
3
|
-
require 'cucumber/formatter/io'
|
4
|
-
require 'cucumber/core/report/summary'
|
5
|
-
require 'cucumber/core/test/result'
|
6
|
-
require 'pathname'
|
7
|
-
require_relative 'html_builder'
|
8
|
-
require_relative 'closer_html'
|
1
|
+
require 'cucumber/formatter/html'
|
9
2
|
|
10
3
|
module Closer
|
11
4
|
module Formatter
|
12
|
-
class
|
13
|
-
include CloserHtml
|
5
|
+
class HTML < ::Cucumber::Formatter::HTML
|
14
6
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
Cucumber::Core::Ast::ScenarioOutline => 'scenario outline'
|
19
|
-
}
|
20
|
-
|
21
|
-
AST_DATA_TABLE = ::Cucumber::Formatter::LegacyApi::Ast::MultilineArg::DataTable
|
22
|
-
|
23
|
-
include ERB::Util # for the #h method
|
24
|
-
include ::Cucumber::Formatter::Duration
|
25
|
-
include ::Cucumber::Formatter::Io
|
26
|
-
|
27
|
-
attr_reader :builder
|
28
|
-
private :builder
|
29
|
-
|
30
|
-
def initialize(runtime, path_or_io, options)
|
31
|
-
@io = ensure_io(path_or_io)
|
32
|
-
@runtime = runtime
|
33
|
-
@options = options
|
34
|
-
@buffer = {}
|
35
|
-
@builder = HtmlBuilder.new(target: @io, indent: 0)
|
36
|
-
@feature_number = 0
|
37
|
-
@scenario_number = 0
|
38
|
-
@step_number = 0
|
39
|
-
@header_red = nil
|
40
|
-
@delayed_messages = []
|
41
|
-
@inside_outline = false
|
42
|
-
@previous_step_keyword = nil
|
43
|
-
@summary = ::Cucumber::Core::Report::Summary.new(runtime.configuration.event_bus)
|
44
|
-
end
|
45
|
-
|
46
|
-
def before_features(features)
|
47
|
-
@step_count = features && features.step_count || 0 #TODO: Make this work with core!
|
48
|
-
|
49
|
-
builder.build_document!
|
50
|
-
builder.format_features! features
|
51
|
-
end
|
52
|
-
|
53
|
-
def after_features(features)
|
54
|
-
print_stats(features)
|
55
|
-
builder << '</div>'
|
56
|
-
builder << '</body>'
|
57
|
-
builder << '</html>'
|
58
|
-
end
|
59
|
-
|
60
|
-
def before_feature(_feature)
|
61
|
-
dir = feature_dir(_feature)
|
62
|
-
unless dir.empty?
|
63
|
-
if @feature_dir != dir
|
64
|
-
builder << '<div class="feature_dir"><span class="val" onclick="toggle_feature_dir(this);">'
|
65
|
-
builder << dir
|
66
|
-
builder << '</span></div>'
|
67
|
-
end
|
68
|
-
|
69
|
-
@feature_dir = dir
|
70
|
-
end
|
71
|
-
|
72
|
-
@feature = _feature
|
73
|
-
@exceptions = []
|
74
|
-
builder << "<div id=\"#{feature_id}\" class=\"feature\">"
|
75
|
-
end
|
76
|
-
|
77
|
-
def after_feature(_feature)
|
78
|
-
builder << '</div>'
|
79
|
-
end
|
80
|
-
|
81
|
-
def before_comment(_comment)
|
82
|
-
return if magic_comment?(_comment)
|
83
|
-
|
84
|
-
builder << '<pre class="comment">'
|
85
|
-
end
|
86
|
-
|
87
|
-
def after_comment(_comment)
|
88
|
-
return if magic_comment?(_comment)
|
89
|
-
|
90
|
-
builder << '</pre>'
|
91
|
-
end
|
92
|
-
|
93
|
-
def comment_line(comment_line)
|
94
|
-
return if magic_comment?(comment_line)
|
95
|
-
|
96
|
-
builder.text!(comment_line)
|
97
|
-
builder.br
|
98
|
-
end
|
99
|
-
|
100
|
-
def after_tags(_tags)
|
101
|
-
@tag_spacer = nil
|
102
|
-
end
|
103
|
-
|
104
|
-
def tag_name(tag_name)
|
105
|
-
builder.text!(@tag_spacer) if @tag_spacer
|
106
|
-
@tag_spacer = ' '
|
107
|
-
builder.span(tag_name, :class => 'tag')
|
108
|
-
end
|
109
|
-
|
110
|
-
def feature_name(keyword, name)
|
111
|
-
title = feature_dir(@feature, true) + @feature.file.split('/').last.gsub(/\.feature/, '')
|
112
|
-
lines = name.split(/\r?\n/)
|
113
|
-
return if lines.empty?
|
114
|
-
builder.h2 do |h2|
|
115
|
-
builder.span(:class => 'val') do
|
116
|
-
builder << title
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
if lines.size > 1
|
121
|
-
builder.div(:class => 'narrative') do
|
122
|
-
builder << lines[1..-1].join("\n")
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def before_test_case(_test_case)
|
128
|
-
@previous_step_keyword = nil
|
129
|
-
end
|
130
|
-
|
131
|
-
def before_background(_background)
|
132
|
-
@in_background = true
|
133
|
-
builder << '<div class="background">'
|
134
|
-
end
|
135
|
-
|
136
|
-
def after_background(_background)
|
137
|
-
@in_background = nil
|
138
|
-
builder << '</div>'
|
7
|
+
def output_envelope(envelope)
|
8
|
+
@html_formatter.write_message(envelope)
|
9
|
+
@html_formatter.write_post_message if envelope.test_run_finished
|
139
10
|
end
|
140
11
|
|
141
|
-
def background_name(keyword, name, _file_colon_line, _source_indent)
|
142
|
-
@listing_background = true
|
143
|
-
builder.h3(:id => "background_#{@scenario_number}") do |h3|
|
144
|
-
builder.span(keyword, :class => 'keyword')
|
145
|
-
builder.text!(' ')
|
146
|
-
builder.span(name, :class => 'val')
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def before_feature_element(feature_element)
|
151
|
-
@scenario_number+=1
|
152
|
-
@scenario_red = false
|
153
|
-
css_class = AST_CLASSES[feature_element.class]
|
154
|
-
builder << "<div class='#{css_class}'>"
|
155
|
-
@in_scenario_outline = feature_element.class == Cucumber::Core::Ast::ScenarioOutline
|
156
|
-
end
|
157
|
-
|
158
|
-
def after_feature_element(_feature_element)
|
159
|
-
unless @in_scenario_outline
|
160
|
-
print_messages
|
161
|
-
builder << '</ol>'
|
162
|
-
end
|
163
|
-
builder << '</div>'
|
164
|
-
@in_scenario_outline = nil
|
165
|
-
end
|
166
|
-
|
167
|
-
def scenario_name(keyword, name, file_colon_line, _source_indent)
|
168
|
-
builder.span(:class => 'scenario_file hidden') do
|
169
|
-
builder << file_colon_line
|
170
|
-
end
|
171
|
-
@listing_background = false
|
172
|
-
scenario_id = "scenario_#{@scenario_number}"
|
173
|
-
if @inside_outline
|
174
|
-
@outline_row += 1
|
175
|
-
scenario_id += "_#{@outline_row}"
|
176
|
-
@scenario_red = false
|
177
|
-
end
|
178
|
-
|
179
|
-
lines = name.split("\n")
|
180
|
-
title = lines.shift
|
181
|
-
builder.h3(:id => scenario_id) do
|
182
|
-
builder.span(title, :class => 'val pointer')
|
183
|
-
end
|
184
|
-
|
185
|
-
if lines.size > 0
|
186
|
-
builder.pre(:class => 'narrative hidden') do
|
187
|
-
trim_size = indent_size(lines.first)
|
188
|
-
builder << lines.map{|line| line[trim_size..-1] }.join("\n")
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def before_outline_table(_outline_table)
|
194
|
-
@inside_outline = true
|
195
|
-
@outline_row = 0
|
196
|
-
builder << '<table>'
|
197
|
-
end
|
198
|
-
|
199
|
-
def after_outline_table(_outline_table)
|
200
|
-
builder << '</table>'
|
201
|
-
@outline_row = nil
|
202
|
-
@inside_outline = false
|
203
|
-
end
|
204
|
-
|
205
|
-
def before_examples(_examples)
|
206
|
-
builder << '<div class="examples">'
|
207
|
-
end
|
208
|
-
|
209
|
-
def after_examples(_examples)
|
210
|
-
builder << '</div>'
|
211
|
-
end
|
212
|
-
|
213
|
-
def examples_name(keyword, name)
|
214
|
-
builder.h4 do
|
215
|
-
builder.span(keyword, :class => 'keyword')
|
216
|
-
builder.text!(' ')
|
217
|
-
builder.span(name, :class => 'val')
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
def before_steps(_steps)
|
222
|
-
builder << '<ol class="hidden">'
|
223
|
-
end
|
224
|
-
|
225
|
-
def after_steps(_steps)
|
226
|
-
print_messages
|
227
|
-
builder << '</ol>' if @in_background || @in_scenario_outline
|
228
|
-
end
|
229
|
-
|
230
|
-
def before_step(step)
|
231
|
-
print_messages
|
232
|
-
@step_id = step.dom_id
|
233
|
-
@step_number += 1
|
234
|
-
@step = step
|
235
|
-
end
|
236
|
-
|
237
|
-
def after_step(_step)
|
238
|
-
end
|
239
|
-
|
240
|
-
def before_step_result(_keyword, step_match, _multiline_arg, status, exception, _source_indent, background, _file_colon_line)
|
241
|
-
@step_match = step_match
|
242
|
-
@hide_this_step = false
|
243
|
-
if exception
|
244
|
-
if @exceptions.include?(exception)
|
245
|
-
@hide_this_step = true
|
246
|
-
return
|
247
|
-
end
|
248
|
-
@exceptions << exception
|
249
|
-
end
|
250
|
-
if status != :failed && @in_background ^ background
|
251
|
-
@hide_this_step = true
|
252
|
-
return
|
253
|
-
end
|
254
|
-
@status = status
|
255
|
-
return if @hide_this_step
|
256
|
-
set_scenario_color(status)
|
257
|
-
|
258
|
-
if ! @delayed_messages.empty? and status == :passed
|
259
|
-
builder << "<li id='#{@step_id}' class='step #{status} expand'>"
|
260
|
-
else
|
261
|
-
builder << "<li id='#{@step_id}' class='step #{status}'>"
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
def after_step_result(keyword, step_match, _multiline_arg, status, _exception, _source_indent, _background, _file_colon_line)
|
266
|
-
return if @hide_this_step
|
267
|
-
# print snippet for undefined steps
|
268
|
-
unless outline_step?(@step)
|
269
|
-
keyword = @step.actual_keyword(@previous_step_keyword)
|
270
|
-
@previous_step_keyword = keyword
|
271
|
-
end
|
272
|
-
if status == :undefined
|
273
|
-
builder.pre do |pre|
|
274
|
-
# TODO: snippet text should be an event sent to the formatter so we don't
|
275
|
-
# have this couping to the runtime.
|
276
|
-
pre << @runtime.snippet_text(keyword,step_match.instance_variable_get('@name') || '', @step.multiline_arg)
|
277
|
-
end
|
278
|
-
end
|
279
|
-
builder << '</li>'
|
280
|
-
|
281
|
-
unless status == :undefined
|
282
|
-
step_file = step_match.file_colon_line
|
283
|
-
step_contents = "<div class=\"step_contents hidden\"><pre>"
|
284
|
-
step_file.gsub(/^([^:]*\.rb):(\d*)/) do
|
285
|
-
line_index = $2.to_i - 1
|
286
|
-
|
287
|
-
file = $1.force_encoding('UTF-8')
|
288
|
-
file = File.join(gem_dir, file) unless File.exist?(file)
|
289
|
-
File.readlines(file)[line_index..-1].each do |line|
|
290
|
-
step_contents << line
|
291
|
-
break if line.chop == 'end' or line.chop.start_with?('end ')
|
292
|
-
end
|
293
|
-
end
|
294
|
-
step_contents << "</pre></div>"
|
295
|
-
builder << step_contents
|
296
|
-
end
|
297
|
-
|
298
|
-
print_messages
|
299
|
-
end
|
300
|
-
|
301
|
-
def step_name(keyword, step_match, status, _source_indent, background, _file_colon_line)
|
302
|
-
background_in_scenario = background && !@listing_background
|
303
|
-
@skip_step = background_in_scenario
|
304
|
-
|
305
|
-
unless @skip_step
|
306
|
-
build_step(keyword, step_match, status)
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
def exception(exception, _status)
|
311
|
-
return if @hide_this_step
|
312
|
-
print_messages
|
313
|
-
build_exception_detail(exception)
|
314
|
-
end
|
315
|
-
|
316
|
-
def extra_failure_content(file_colon_line)
|
317
|
-
@snippet_extractor ||= SnippetExtractor.new
|
318
|
-
"<pre class=\"ruby\"><code>#{@snippet_extractor.snippet(file_colon_line)}</code></pre>"
|
319
|
-
end
|
320
|
-
|
321
|
-
def before_multiline_arg(multiline_arg)
|
322
|
-
return if @hide_this_step || @skip_step
|
323
|
-
if AST_DATA_TABLE === multiline_arg
|
324
|
-
builder << '<table>'
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
def after_multiline_arg(multiline_arg)
|
329
|
-
return if @hide_this_step || @skip_step
|
330
|
-
if AST_DATA_TABLE === multiline_arg
|
331
|
-
builder << '</table>'
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
|
-
def doc_string(string)
|
336
|
-
return if @hide_this_step
|
337
|
-
builder.pre(:class => 'val') do |pre|
|
338
|
-
builder << h(string).gsub("\n", '
')
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
def before_table_row(table_row)
|
343
|
-
@row_id = table_row.dom_id
|
344
|
-
@col_index = 0
|
345
|
-
return if @hide_this_step
|
346
|
-
builder << "<tr class='step' id='#{@row_id}'>"
|
347
|
-
end
|
348
|
-
|
349
|
-
def after_table_row(table_row)
|
350
|
-
return if @hide_this_step
|
351
|
-
print_table_row_messages
|
352
|
-
builder << '</tr>'
|
353
|
-
if table_row.exception
|
354
|
-
builder.tr do
|
355
|
-
builder.td(:colspan => @col_index.to_s, :class => 'failed') do
|
356
|
-
builder.pre do |pre|
|
357
|
-
pre << h(format_exception(table_row.exception))
|
358
|
-
end
|
359
|
-
end
|
360
|
-
end
|
361
|
-
if table_row.exception.is_a? ::Cucumber::Pending
|
362
|
-
set_scenario_color_pending
|
363
|
-
else
|
364
|
-
set_scenario_color_failed
|
365
|
-
end
|
366
|
-
end
|
367
|
-
if @outline_row
|
368
|
-
@outline_row += 1
|
369
|
-
end
|
370
|
-
@step_number += 1
|
371
|
-
end
|
372
|
-
|
373
|
-
def table_cell_value(value, status)
|
374
|
-
return if @hide_this_step
|
375
|
-
|
376
|
-
@cell_type = @outline_row == 0 ? :th : :td
|
377
|
-
attributes = {:id => "#{@row_id}_#{@col_index}", :class => 'step'}
|
378
|
-
attributes[:class] += " #{status}" if status
|
379
|
-
build_cell(@cell_type, value, attributes)
|
380
|
-
set_scenario_color(status) if @inside_outline
|
381
|
-
@col_index += 1
|
382
|
-
end
|
383
|
-
|
384
|
-
def puts(message)
|
385
|
-
@delayed_messages << message
|
386
|
-
#builder.pre(message, :class => 'message')
|
387
|
-
end
|
388
|
-
|
389
|
-
def print_messages
|
390
|
-
return if @delayed_messages.empty?
|
391
|
-
|
392
|
-
#builder.ol do
|
393
|
-
@delayed_messages.each do |ann|
|
394
|
-
builder.li(:class => 'message hidden') do
|
395
|
-
builder << ann
|
396
|
-
end
|
397
|
-
end
|
398
|
-
#end
|
399
|
-
empty_messages
|
400
|
-
end
|
401
|
-
|
402
|
-
def print_table_row_messages
|
403
|
-
return if @delayed_messages.empty?
|
404
|
-
|
405
|
-
builder.td(:class => 'message') do
|
406
|
-
builder << @delayed_messages.join(', ')
|
407
|
-
end
|
408
|
-
empty_messages
|
409
|
-
end
|
410
|
-
|
411
|
-
def empty_messages
|
412
|
-
@delayed_messages = []
|
413
|
-
end
|
414
|
-
|
415
|
-
def after_test_case(_test_case, result)
|
416
|
-
if result.failed? && !@scenario_red
|
417
|
-
set_scenario_color_failed
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
protected
|
422
|
-
|
423
|
-
def build_exception_detail(exception)
|
424
|
-
backtrace = Array.new
|
425
|
-
|
426
|
-
builder.div(:class => 'message') do
|
427
|
-
message = exception.message
|
428
|
-
|
429
|
-
if defined?(RAILS_ROOT) && message.include?('Exception caught')
|
430
|
-
matches = message.match(/Showing <i>(.+)<\/i>(?:.+) #(\d+)/)
|
431
|
-
backtrace += ["#{RAILS_ROOT}/#{matches[1]}:#{matches[2]}"] if matches
|
432
|
-
matches = message.match(/<code>([^(\/)]+)<\//m)
|
433
|
-
message = matches ? matches[1] : ''
|
434
|
-
end
|
435
|
-
|
436
|
-
unless exception.instance_of?(RuntimeError)
|
437
|
-
message = "#{message} (#{exception.class})"
|
438
|
-
end
|
439
|
-
|
440
|
-
builder.pre do
|
441
|
-
builder.text!(message)
|
442
|
-
end
|
443
|
-
end
|
444
|
-
|
445
|
-
builder.div(:class => 'backtrace') do
|
446
|
-
builder.pre do
|
447
|
-
backtrace = exception.backtrace
|
448
|
-
backtrace.delete_if { |x| x =~ /\/gems\/(cucumber|rspec)/ }
|
449
|
-
builder << backtrace_line(backtrace.join("\n"))
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
extra = extra_failure_content(backtrace)
|
454
|
-
builder << extra unless extra == ''
|
455
|
-
end
|
456
|
-
|
457
|
-
def set_scenario_color(status)
|
458
|
-
if status.nil? || status == :undefined || status == :pending
|
459
|
-
set_scenario_color_pending
|
460
|
-
end
|
461
|
-
if status == :failed
|
462
|
-
set_scenario_color_failed
|
463
|
-
end
|
464
|
-
end
|
465
|
-
|
466
|
-
def set_scenario_color_failed
|
467
|
-
builder.script do
|
468
|
-
builder.text!("makeRed('cucumber-header');") unless @header_red
|
469
|
-
@header_red = true
|
470
|
-
scenario_or_background = @in_background ? 'background' : 'scenario'
|
471
|
-
builder.text!("makeRed('#{scenario_or_background}_#{@scenario_number}');") unless @scenario_red
|
472
|
-
@scenario_red = true
|
473
|
-
if @options[:expand] && @inside_outline
|
474
|
-
builder.text!("makeRed('#{scenario_or_background}_#{@scenario_number}_#{@outline_row}');")
|
475
|
-
end
|
476
|
-
end
|
477
|
-
end
|
478
|
-
|
479
|
-
def set_scenario_color_pending
|
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
|
484
|
-
end
|
485
|
-
end
|
486
|
-
|
487
|
-
def build_step(keyword, step_match, _status)
|
488
|
-
keyword = display_keyword(keyword)
|
489
|
-
step_name = step_match.format_args(lambda{|param| %{<span class="param">#{param}</span>}})
|
490
|
-
builder.div(:class => 'step_name') do |div|
|
491
|
-
builder.span(keyword, :class => 'keyword')
|
492
|
-
builder.span(:class => 'step val') do |name|
|
493
|
-
name << h(step_name).gsub(/<span class="(.*?)">/, '<span class="\1">').gsub(/<\/span>/, '</span>')
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
step_file = step_match.file_colon_line
|
498
|
-
step_file.gsub(/^([^:]*\.rb):(\d*)/) do
|
499
|
-
step_file = "<span class=\"pointer\" onclick=\"toggle_step_file(this); return false;\">#{step_file}</span>"
|
500
|
-
|
501
|
-
builder.div(:class => 'step_file') do |div|
|
502
|
-
builder.span do
|
503
|
-
builder << step_file
|
504
|
-
end
|
505
|
-
end
|
506
|
-
end
|
507
|
-
end
|
508
|
-
|
509
|
-
def build_cell(cell_type, value, attributes)
|
510
|
-
builder.__send__(cell_type, attributes) do
|
511
|
-
builder.div do
|
512
|
-
builder.span(value,:class => 'step param')
|
513
|
-
end
|
514
|
-
end
|
515
|
-
end
|
516
|
-
|
517
|
-
def format_exception(exception)
|
518
|
-
([exception.message.to_s] + exception.backtrace).join("\n")
|
519
|
-
end
|
520
|
-
|
521
|
-
def backtrace_line(line)
|
522
|
-
line.gsub(/^([^:]*\.(?:rb|feature|haml)):(\d*).*$/) do
|
523
|
-
line
|
524
|
-
end
|
525
|
-
end
|
526
|
-
|
527
|
-
def print_stats(features)
|
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>"
|
530
|
-
end
|
531
|
-
|
532
|
-
def print_stat_string(_features)
|
533
|
-
string = String.new
|
534
|
-
string << dump_count(@summary.test_cases.total, 'scenario')
|
535
|
-
scenario_count = status_counts(@summary.test_cases)
|
536
|
-
string << scenario_count if scenario_count
|
537
|
-
string << '<br />'
|
538
|
-
string << dump_count(@summary.test_steps.total, 'step')
|
539
|
-
step_count = status_counts(@summary.test_steps)
|
540
|
-
string << step_count if step_count
|
541
|
-
end
|
542
|
-
|
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?
|
553
|
-
end
|
554
|
-
|
555
|
-
def dump_count(count, what, state=nil)
|
556
|
-
[count, state, "#{what}#{count == 1 ? '' : 's'}"].compact.join(' ')
|
557
|
-
end
|
558
|
-
|
559
|
-
def outline_step?(_step)
|
560
|
-
not @step.step.respond_to?(:actual_keyword)
|
561
|
-
end
|
562
|
-
|
563
|
-
class SnippetExtractor #:nodoc:
|
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
|
572
|
-
|
573
|
-
def snippet(error)
|
574
|
-
raw_code, line = snippet_for(error[0])
|
575
|
-
highlighted = @@converter.convert(raw_code, false)
|
576
|
-
highlighted << "\n<span class=\"comment\"># gem install syntax to get syntax highlighting</span>" if @@converter.is_a?(NullConverter)
|
577
|
-
post_process(highlighted, line)
|
578
|
-
end
|
579
|
-
|
580
|
-
def snippet_for(error_line)
|
581
|
-
if error_line =~ /(.*):(\d+)/
|
582
|
-
file = $1
|
583
|
-
line = $2.to_i
|
584
|
-
[lines_around(file, line), line]
|
585
|
-
else
|
586
|
-
["# Couldn't get snippet for #{error_line}", 1]
|
587
|
-
end
|
588
|
-
end
|
589
|
-
|
590
|
-
def lines_around(file, line)
|
591
|
-
if File.file?(file)
|
592
|
-
begin
|
593
|
-
lines = File.open(file).read.split("\n")
|
594
|
-
rescue ArgumentError
|
595
|
-
return "# Couldn't get snippet for #{file}"
|
596
|
-
end
|
597
|
-
min = [0, line-3].max
|
598
|
-
max = [line+1, lines.length-1].min
|
599
|
-
selected_lines = []
|
600
|
-
selected_lines.join("\n")
|
601
|
-
lines[min..max].join("\n")
|
602
|
-
else
|
603
|
-
"# Couldn't get snippet for #{file}"
|
604
|
-
end
|
605
|
-
end
|
606
|
-
|
607
|
-
def post_process(highlighted, offending_line)
|
608
|
-
new_lines = []
|
609
|
-
highlighted.split("\n").each_with_index do |line, i|
|
610
|
-
new_line = "<span class=\"linenum\">#{offending_line+i-2}</span>#{line}"
|
611
|
-
new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
|
612
|
-
new_lines << new_line
|
613
|
-
end
|
614
|
-
new_lines.join("\n")
|
615
|
-
end
|
616
|
-
|
617
|
-
end
|
618
12
|
end
|
619
13
|
end
|
620
14
|
end
|
@@ -39,7 +39,7 @@ module Closer
|
|
39
39
|
image_tag = "<img #{attrs.map{|k, v| "#{k}=\"#{v}\"" }.join(' ')} />"
|
40
40
|
|
41
41
|
if options[:flash]
|
42
|
-
|
42
|
+
log(image_tag)
|
43
43
|
else
|
44
44
|
@@_images << image_tag
|
45
45
|
end
|
@@ -68,7 +68,7 @@ module Closer
|
|
68
68
|
|
69
69
|
def flash_image_tags
|
70
70
|
if @@_images.size > 0
|
71
|
-
|
71
|
+
log(@@_images.join("\n"))
|
72
72
|
@@_images.clear
|
73
73
|
end
|
74
74
|
end
|