daddy 0.3.36 → 0.3.37

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.
@@ -1,214 +0,0 @@
1
- #menu {
2
- float: left;
3
- background: #FFFFFF;
4
- color: #000000;
5
- }
6
-
7
- #menu ol {
8
- margin: 0;
9
- padding: 0;
10
- border-left: 5px solid #65c400;
11
- }
12
-
13
- #menu ol li.master,
14
- #menu ol li.sprint {
15
- margin: 0;
16
- padding: 0 5px;
17
- border-bottom: 1px solid #65c400;
18
- line-height: 40px;
19
- vertical-align: middle;
20
- font-size: 1.2em;
21
- font-weight: bold;
22
- white-space: nowrap;
23
- }
24
-
25
- #menu ol li.sub_menu {
26
- margin: 0;
27
- padding: 0 5px;
28
- border-bottom: 1px solid #65c400;
29
- line-height: 30px;
30
- text-align: right;
31
- vertical-align: middle;
32
- font-size: 1.2em;
33
- font-weight: bold;
34
- }
35
-
36
- .cucumber .scenario h3, td .scenario h3, th .scenario h3, .background h3 {
37
- font-size: 1.2em;
38
- margin: 0;
39
- background: #FFFFFF;
40
- color: #000000;
41
- font-weight: bold;
42
- }
43
-
44
- .cucumber ol li.step, td ol li.step, th ol li.step {
45
- padding: 3px 3px 3px 10px;
46
- margin: 5px 0px 5px 1.2em;
47
- }
48
-
49
- .cucumber ol li.passed, td ol li.passed, th ol li.passed {
50
- border-left: 5px solid #999999;
51
- border-bottom: 1px solid #999999;
52
- background: #FFFFFF;
53
- color: #000000;
54
- }
55
-
56
- .cucumber ol li.expand:hover, td ol li.expand:hover, th ol li.expand:hover {
57
- background: #F0F8FF;
58
- }
59
-
60
- .cucumber ol li.message, td ol li.message, th ol li.message {
61
- border-left: 5px solid #999999;
62
- border-bottom: 1px solid #999999;
63
- background: #F0F8FF;
64
- color: #001111;
65
- margin: 5px 0px 5px 1.2em;
66
- padding: 3px 15px 3px 10px;
67
- }
68
-
69
- .feature_dir {
70
- font-size: 1.2em;
71
- font-weight: bold;
72
- padding: 2px;
73
- margin: 10px 10px 0px 10px;
74
- }
75
-
76
- div.feature_dir span {
77
- cursor: pointer;
78
- }
79
-
80
- div.feature h2 {
81
- font-size: 1.2em;
82
- }
83
-
84
- .step_contents {
85
- display: none;
86
- background: #FFFFFF;
87
- border: solid 1px #999999;
88
- margin-left: 1.2em;
89
- padding: 1em;
90
- }
91
-
92
- div.background {
93
- margin-left: 20px;
94
- }
95
-
96
- div.background ol {
97
- margin-left: 20px;
98
- }
99
-
100
- div.contents {
101
- padding-top: 10px;
102
- }
103
-
104
- div.feature .narrative {
105
- margin: 1.2em;
106
- line-height: 1.5em;
107
- font-size: 1.2em;
108
- }
109
-
110
- div.feature .narrative > div {
111
- margin-left: 10px;
112
- }
113
-
114
- div.feature .narrative > pre {
115
- border: solid 1px #999999;
116
- border-radius: 5px;
117
- padding: 1em 0;
118
- }
119
-
120
- div.scenario {
121
- margin: 10px 10px 10px 1.2em;
122
- }
123
-
124
- div.scenario.faild h3,
125
- div.scenario.faild .scenario_file {
126
- background: #C40D0D;
127
- color: #FFFFFF;
128
- }
129
-
130
- div.scenario.pending h3,
131
- div.scenario.pending .scenario_file {
132
- background: #FAF834;
133
- color: #000000;
134
- }
135
-
136
- div.scenario ol {
137
- margin-top: 1em;
138
- margin-left: 5px;
139
- }
140
-
141
- div.scenario table {
142
- margin: 10px 0;
143
- }
144
-
145
- div.scenario td {
146
- border: solid 1px #999999;
147
- padding: 5px;
148
- }
149
-
150
- span.feature_subtitle {
151
- margin-left: 20px;
152
- color: #999999;
153
- font-size: 0.9em;
154
- }
155
-
156
- span.scenario_file {
157
- padding: 3px;
158
- line-height: 1.2em;
159
- }
160
-
161
- span.new {
162
- color: #006400;
163
- font-weight: bold;
164
- }
165
-
166
- span.edit {
167
- color: #006400;
168
- font-weight: bold;
169
- }
170
-
171
- span.auto {
172
- color: #006400;
173
- font-weight: bold;
174
- }
175
-
176
- ins.differ {
177
- text-decoration: none;
178
- background: #90EE90;
179
- }
180
-
181
- del.differ {
182
- text-decoration: none;
183
- background: #FFB6C1;
184
- }
185
-
186
- .screenshot {
187
- border: solid 1px #999999;
188
- border-radius: 5px 5px;
189
- margin: 5px 0;
190
- padding: 5px;
191
- background: #ffffff;
192
- width: 48%;
193
- height: 48%;
194
- max-width: 98%;
195
- max-height: 98%;
196
- cursor: pointer;
197
- }
198
-
199
- #screenshot_viewer img {
200
- display: block;
201
- border: solid 3px #555555;
202
- border-radius: 5px 5px;
203
- box-shadow: 5px 5px 5px 5px rgba(0,0,0,0.3);
204
- margin: 4%;
205
- padding: 1%;
206
- background: #ffffff;
207
- max-width: 90%;
208
- }
209
-
210
- blockquote {
211
- border: solid 1px #999999;
212
- border-radius: 5px 5px;
213
- padding: 5px;
214
- }
@@ -1,19 +0,0 @@
1
- function toggle_feature_dir(feature_dir) {
2
- $(feature_dir).parent('div.feature_dir').nextUntil('div.feature_dir').toggle(250);
3
- };
4
-
5
- function toggle_step_file(step_file) {
6
- $(step_file).closest('li').next('.step_contents').toggle(250);
7
- event.stopPropagation();
8
- };
9
-
10
- $(document).ready(function() {
11
- $('li.step').each(function() {
12
- var messages = $(this).nextUntil('li.step').filter('.message');
13
- if (messages.length > 0) {
14
- $(this).css('cursor', 'pointer').click(function() {
15
- messages.toggle(250);
16
- });
17
- }
18
- });
19
- });
@@ -1,87 +0,0 @@
1
- require 'erb'
2
- require 'daddy'
3
-
4
- module Daddy
5
- module Formatter
6
- module DaddyHtml
7
-
8
- def ruby_version_dir
9
- unless @_ruby_version_dir
10
- @_ruby_version_dir = RUBY_VERSION.split('.')[0..1].join('.') + '.0'
11
- end
12
- @_ruby_version_dir
13
- end
14
-
15
- def title
16
- ret = ENV['TITLE']
17
- ret ||= Daddy.config.cucumber.title if Daddy.config.cucumber.title?
18
- ret ||= 'Daddy'
19
- ret
20
- end
21
-
22
- def before_menu
23
- if ENV['PUBLISH']
24
- @builder << "<div>"
25
-
26
- @builder.div(:id => 'menu') do
27
- @builder << make_menu_for_publish
28
- end
29
-
30
- @builder << "<div class='contents'>"
31
- end
32
- end
33
-
34
- def after_menu
35
- if ENV['PUBLISH']
36
- @builder << '</div>'
37
- @builder << '</div>'
38
- end
39
- end
40
-
41
- def make_menu_for_publish
42
- template = File.join(File.dirname(__FILE__), 'menu.html.erb')
43
- ERB.new(File.read(template), 0, '-').result
44
- end
45
-
46
- def feature_id
47
- @feature.file.gsub(/(\/|\.|\\)/, '_')
48
- end
49
-
50
- def feature_dir(feature, short = false)
51
- ret = ''
52
-
53
- split = feature.file.split(File::SEPARATOR)
54
- split.reverse[1..-2].each_with_index do |dir, i|
55
- break if dir == '仕様書' or dir == '開発日記'
56
-
57
- if i == 0
58
- if short
59
- ret = dir.split('.').first + '.'
60
- else
61
- ret = dir
62
- end
63
- else
64
- ret = dir.split('.').first + '.' + ret
65
- end
66
- end
67
-
68
- ret
69
- end
70
-
71
- def should_expand
72
- ['t', 'true'].include?(ENV['EXPAND'].to_s.downcase)
73
- end
74
-
75
- def magic_comment?(comment_line)
76
- comment = comment_line.to_s
77
-
78
- ['language', 'format'].each do |magic|
79
- return true if /#\s*#{magic}\s*:.*/ =~ comment
80
- end
81
-
82
- false
83
- end
84
-
85
- end
86
- end
87
- end
@@ -1,720 +0,0 @@
1
- require 'erb'
2
- require 'cucumber/formatter/ordered_xml_markup'
3
- require 'cucumber/formatter/duration'
4
- require 'cucumber/formatter/io'
5
- require 'daddy/formatter/daddy_html'
6
-
7
- module Daddy
8
- module Formatter
9
- class Html
10
- include ERB::Util # for the #h method
11
- include ::Cucumber::Formatter::Duration
12
- include ::Cucumber::Formatter::Io
13
- include Daddy::Formatter::DaddyHtml
14
-
15
- def initialize(runtime, path_or_io, options)
16
- @io = ensure_io(path_or_io, "html")
17
- @runtime = runtime
18
- @options = options
19
- @buffer = {}
20
- @builder = create_builder(@io)
21
- @feature_number = 0
22
- @scenario_number = 0
23
- @step_number = 0
24
- @header_red = nil
25
- @delayed_messages = []
26
- @img_id = 0
27
- @inside_outline = false
28
- end
29
-
30
- def embed(src, mime_type, label)
31
- case(mime_type)
32
- when /^image\/(png|gif|jpg|jpeg)/
33
- embed_image(src, label)
34
- end
35
- end
36
-
37
- def embed_image(src, label)
38
- id = "img_#{@img_id}"
39
- @img_id += 1
40
- @builder.span(:class => 'embed') do |pre|
41
- pre << %{<a href="" onclick="img=document.getElementById('#{id}'); img.style.display = (img.style.display == 'none' ? 'block' : 'none');return false">#{label}</a><br>&nbsp;
42
- <img id="#{id}" style="display: none" src="#{src}"/>}
43
- end
44
- end
45
-
46
-
47
- def before_features(features)
48
- @step_count = features.step_count
49
-
50
- @builder.declare!(:DOCTYPE, :html)
51
-
52
- @builder << '<html>'
53
- @builder.head do
54
- @builder.meta('http-equiv' => 'Content-Type', :content => 'text/html;charset=utf-8')
55
- @builder.title title
56
- inline_css
57
- inline_js
58
- end
59
- @builder << '<body>'
60
- @builder << "<!-- Step count #{@step_count}-->"
61
- @builder << '<div class="cucumber">'
62
- @builder.div(:id => 'cucumber-header') do
63
- @builder.div(:id => 'label') do
64
- @builder.h1(title)
65
- end
66
- @builder.div(:id => 'summary') do
67
- @builder.p('',:id => 'totals')
68
- @builder.p('',:id => 'duration')
69
- @builder.div(:id => 'expand-collapse') do
70
- @builder.p('すべて開く', :id => 'expander')
71
- @builder.p('すべて閉じる', :id => 'collapser')
72
- end
73
- end
74
- end
75
-
76
- before_menu
77
- end
78
-
79
- def after_features(features)
80
- after_menu
81
- print_stats(features)
82
- @builder << '</div>'
83
- @builder << '</body>'
84
- @builder << '</html>'
85
- end
86
-
87
- def before_feature(feature)
88
- dir = feature_dir(feature)
89
- unless dir.empty?
90
- if @feature_dir != dir
91
- @builder << '<div class="feature_dir"><span class="val" onclick="toggle_feature_dir(this);">'
92
- @builder << dir
93
- @builder << '</span></div>'
94
- end
95
-
96
- @feature_dir = dir
97
- end
98
-
99
- @feature = feature
100
- @exceptions = []
101
- @builder << "<div id=\"#{feature_id}\" class=\"feature\">"
102
- end
103
-
104
- def after_feature(feature)
105
- @builder << '</div>'
106
- end
107
-
108
- def before_comment(comment)
109
- @builder << '<pre class="comment">' unless magic_comment?(comment)
110
- end
111
-
112
- def after_comment(comment)
113
- @builder << '</pre>' unless magic_comment?(comment)
114
- end
115
-
116
- def comment_line(comment_line)
117
- unless magic_comment?(comment_line)
118
- @builder.text!(comment_line)
119
- @builder.br
120
- end
121
- end
122
-
123
- def after_tags(tags)
124
- @tag_spacer = nil
125
- end
126
-
127
- def tag_name(tag_name)
128
- @builder.text!(@tag_spacer) if @tag_spacer
129
- @tag_spacer = ' '
130
- @builder.span(tag_name, :class => 'tag')
131
- end
132
-
133
- def feature_name(keyword, name)
134
- title = feature_dir(@feature, true) + @feature.file.split('/').last.gsub(/\.feature/, '')
135
- lines = name.split(/\r?\n/)
136
- return if lines.empty?
137
- @builder.h2 do |h2|
138
- @builder.span(:class => 'val') do
139
- @builder << title
140
-
141
- if Daddy.config.cucumber.use_feature_name?
142
- subtitle = lines.first.to_s.strip
143
- unless subtitle.blank?
144
- @builder.span('(' + subtitle + ')', :class => 'feature_subtitle')
145
- end
146
- end
147
- end
148
- end
149
-
150
- if lines.size > 1
151
- @builder.div(:class => 'narrative') do
152
- @builder << lines[1..-1].join("\n")
153
- end
154
- end
155
- end
156
-
157
- def before_background(background)
158
- @in_background = true
159
- @builder << '<div class="background">'
160
- end
161
-
162
- def after_background(background)
163
- @in_background = nil
164
- @builder << '</div>'
165
- end
166
-
167
- def background_name(keyword, name, file_colon_line, source_indent)
168
- @listing_background = true
169
- @builder.h3 do |h3|
170
- @builder.span(keyword, :class => 'keyword')
171
- @builder.text!(' ')
172
- @builder.span(name, :class => 'val')
173
- end
174
- end
175
-
176
- def before_feature_element(feature_element)
177
- @scenario_number+=1
178
- @scenario_red = false
179
- css_class = {
180
- ::Cucumber::Ast::Scenario => 'scenario',
181
- ::Cucumber::Ast::ScenarioOutline => 'scenario outline'
182
- }[feature_element.class]
183
- @builder << "<div class='#{css_class}'>"
184
- end
185
-
186
- def after_feature_element(feature_element)
187
- @builder << '</div>'
188
- @open_step_list = true
189
- end
190
-
191
- def scenario_name(keyword, name, file_colon_line, source_indent)
192
- @step_number_in_scenario = 0
193
-
194
- @builder.span(:class => 'scenario_file', :style => 'display: none;') do
195
- @builder << file_colon_line
196
- end
197
- @listing_background = false
198
-
199
- lines = name.split("\n")
200
- @builder.h3 do
201
- @builder.span(lines[0], :class => 'val')
202
- end
203
-
204
- if lines.size > 1
205
- @builder.div(:class => 'narrative', :style => 'display: none;') do
206
- @builder << lines[1..-1].join("\n")
207
- end
208
- end
209
- end
210
-
211
- def before_outline_table(outline_table)
212
- @inside_outline = true
213
- @outline_row = 0
214
- @builder << '<table>'
215
- end
216
-
217
- def after_outline_table(outline_table)
218
- @builder << '</table>'
219
- @outline_row = nil
220
- @inside_outline = false
221
- end
222
-
223
- def before_examples(examples)
224
- @builder << '<div class="examples">'
225
- end
226
-
227
- def after_examples(examples)
228
- @builder << '</div>'
229
- end
230
-
231
- def examples_name(keyword, name)
232
- @builder.h4 do
233
- @builder.span(keyword, :class => 'keyword')
234
- @builder.text!(' ')
235
- @builder.span(name, :class => 'val')
236
- end
237
- end
238
-
239
- def before_steps(steps)
240
- @builder << '<ol style="display: none;">'
241
- end
242
-
243
- def after_steps(steps)
244
- @builder << '</ol>'
245
- end
246
-
247
- def before_step(step)
248
- @step_id = step.dom_id
249
- @step_number += 1
250
- @step = step
251
- end
252
-
253
- def after_step(step)
254
- move_progress
255
- end
256
-
257
- def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
258
- @step_match = step_match
259
- @hide_this_step = false
260
- if exception
261
- if @exceptions.include?(exception)
262
- @hide_this_step = true
263
- return
264
- end
265
- @exceptions << exception
266
- end
267
- if status != :failed && @in_background ^ background
268
- @hide_this_step = true
269
- return
270
- end
271
- @status = status
272
- return if @hide_this_step
273
- set_scenario_color(status)
274
-
275
- if ! @delayed_messages.empty? and status == :passed
276
- @builder << "<li class='step #{status} expand'>"
277
- else
278
- @builder << "<li class='step #{status}'>"
279
- end
280
- end
281
-
282
- def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
283
- return if @hide_this_step
284
- # print snippet for undefined steps
285
- if status == :undefined
286
- keyword = @step.actual_keyword if @step.respond_to?(:actual_keyword)
287
- step_multiline_class = @step.multiline_arg ? @step.multiline_arg.class : nil
288
- @builder.pre do |pre|
289
- pre << @runtime.snippet_text(keyword,step_match.instance_variable_get("@name") || '',step_multiline_class)
290
- end
291
- end
292
- @builder << '</li>'
293
-
294
- unless status == :undefined
295
- step_file = step_match.file_colon_line
296
- step_contents = "<div class=\"step_contents\"><pre>"
297
- step_file.gsub(/^([^:]*\.rb):(\d*)/) do
298
- line_index = $2.to_i - 1
299
-
300
- file = $1.force_encoding('UTF-8')
301
- if file.start_with?('daddy-') or file.start_with?('/daddy-')
302
- file = File.join('/usr/local/lib/ruby/gems', ruby_version_dir, 'gems', file)
303
- end
304
-
305
- File.readlines(File.expand_path(file))[line_index..-1].each do |line|
306
- step_contents << line
307
- break if line.chop == 'end' or line.chop.start_with?('end ')
308
- end
309
- end
310
- step_contents << "</pre></div>"
311
- @builder << step_contents
312
- end
313
-
314
- print_messages
315
- end
316
-
317
- def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
318
- background_in_scenario = background && !@listing_background
319
- @skip_step = background_in_scenario
320
-
321
- unless @skip_step
322
- build_step(keyword, step_match, status)
323
- end
324
- end
325
-
326
- def exception(exception, status)
327
- return if @hide_this_step
328
- build_exception_detail(exception)
329
- end
330
-
331
- def extra_failure_content(file_colon_line)
332
- @snippet_extractor ||= SnippetExtractor.new
333
- "<pre class=\"ruby\"><code>#{@snippet_extractor.snippet(file_colon_line)}</code></pre>"
334
- end
335
-
336
- def before_multiline_arg(multiline_arg)
337
- return if @hide_this_step || @skip_step
338
- if ::Cucumber::Ast::Table === multiline_arg
339
- @builder << '<table>'
340
- end
341
- end
342
-
343
- def after_multiline_arg(multiline_arg)
344
- return if @hide_this_step || @skip_step
345
- if ::Cucumber::Ast::Table === multiline_arg
346
- @builder << '</table>'
347
- end
348
- end
349
-
350
- def doc_string(string)
351
- return if @hide_this_step
352
- @builder.pre(:class => 'val') do |pre|
353
- @builder << h(string).gsub("\n", '&#x000A;')
354
- end
355
- end
356
-
357
-
358
- def before_table_row(table_row)
359
- @row_id = table_row.dom_id
360
- @col_index = 0
361
- return if @hide_this_step
362
- @builder << "<tr class='step' id='#{@row_id}'>"
363
- end
364
-
365
- def after_table_row(table_row)
366
- return if @hide_this_step
367
- print_table_row_messages
368
- @builder << '</tr>'
369
- if table_row.exception
370
- @builder.tr do
371
- @builder.td(:colspan => @col_index.to_s, :class => 'failed') do
372
- @builder.pre do |pre|
373
- pre << h(format_exception(table_row.exception))
374
- end
375
- end
376
- end
377
- if table_row.exception.is_a? ::Cucumber::Pending
378
- set_scenario_color_pending
379
- else
380
- set_scenario_color_failed
381
- end
382
- end
383
- if @outline_row
384
- @outline_row += 1
385
- end
386
- @step_number += 1
387
- move_progress
388
- end
389
-
390
- def table_cell_value(value, status)
391
- return if @hide_this_step
392
-
393
- @cell_type = @outline_row == 0 ? :th : :td
394
- attributes = {:id => "#{@row_id}_#{@col_index}", :class => 'step'}
395
- attributes[:class] += " #{status}" if status
396
- build_cell(@cell_type, value, attributes)
397
- set_scenario_color(status) if @inside_outline
398
- @col_index += 1
399
- end
400
-
401
- def puts(message)
402
- @delayed_messages << message
403
- #@builder.pre(message, :class => 'message')
404
- end
405
-
406
- def print_messages
407
- return if @delayed_messages.empty?
408
-
409
- #@builder.ol do
410
- @delayed_messages.each do |ann|
411
- @builder.li(:class => 'message', :style => 'display: none;') do
412
- @builder << ann
413
- end
414
- end
415
- #end
416
- empty_messages
417
- end
418
-
419
- def print_table_row_messages
420
- end
421
-
422
- def empty_messages
423
- @delayed_messages = []
424
- end
425
-
426
- protected
427
-
428
- def build_exception_detail(exception)
429
- backtrace = Array.new
430
- @builder.div(:class => 'message') do
431
- message = exception.message
432
- if defined?(RAILS_ROOT) && message.include?('Exception caught')
433
- matches = message.match(/Showing <i>(.+)<\/i>(?:.+) #(\d+)/)
434
- backtrace += ["#{RAILS_ROOT}/#{matches[1]}:#{matches[2]}"] if matches
435
- matches = message.match(/<code>([^(\/)]+)<\//m)
436
- message = matches ? matches[1] : ""
437
- end
438
-
439
- unless exception.instance_of?(RuntimeError)
440
- message = "#{message} (#{exception.class})"
441
- end
442
-
443
- @builder.pre do
444
- @builder.text!(message)
445
- end
446
- end
447
- @builder.div(:class => 'backtrace') do
448
- @builder.pre do
449
- backtrace = exception.backtrace
450
- backtrace.delete_if { |x| x =~ /\/gems\/(cucumber|rspec)/ }
451
- @builder << backtrace_line(backtrace.join("\n"))
452
- end
453
- end
454
- extra = extra_failure_content(backtrace)
455
- @builder << extra unless extra == ""
456
- end
457
-
458
- def set_scenario_color(status)
459
- if status.nil? or status == :undefined or status == :pending
460
- set_scenario_color_pending
461
- end
462
- if status == :failed
463
- set_scenario_color_failed
464
- end
465
- end
466
-
467
- def set_scenario_color_failed
468
- id = Daddy::Utils::StringUtils.current_time
469
- style = 'display: none; margin: 0; padding: 0;'
470
- @builder << "<div id=\"#{id}\" style=\"#{style}\"></div>"
471
-
472
- @builder.script do
473
- @builder.text!("makeRed('cucumber-header');") unless @header_red
474
- @header_red = true
475
- @builder.text!("$(function() { $('##{id}').closest('.scenario').addClass('faild'); });") unless @scenario_red
476
- @scenario_red = true
477
- end
478
- end
479
-
480
- def set_scenario_color_pending
481
- id = Daddy::Utils::StringUtils.current_time
482
- style = 'display: none; margin: 0; padding: 0;'
483
- @builder << "<div id=\"#{id}\" style=\"#{style}\"></div>"
484
-
485
- @builder.script do
486
- @builder.text!("makeYellow('cucumber-header');") unless @header_red
487
- @builder.text!("$(function() { $('##{id}').closest('.scenario').addClass('pending'); });") unless @scenario_red
488
- end
489
- end
490
-
491
- def build_step(keyword, step_match, status)
492
- if @in_background
493
- display_keyword = keyword.strip + ' '
494
- else
495
- if keyword.strip == '*'
496
- @step_number_in_scenario += 1
497
- display_keyword = ''
498
- display_keyword << '0' if @step_number_in_scenario.to_s.size == 1
499
- display_keyword << @step_number_in_scenario.to_s
500
- display_keyword << '. '
501
- else
502
- display_keyword = keyword.strip + ' '
503
- end
504
- end
505
-
506
- step_name = step_match.format_args(lambda{|param| %{<span class="param">#{param}</span>}})
507
- @builder.div(:class => 'step_name') do |div|
508
- @builder.span(display_keyword, :class => 'keyword')
509
- @builder.span(:class => 'step val') do |name|
510
- name << h(step_name).gsub(/&lt;span class=&quot;(.*?)&quot;&gt;/, '<span class="\1">').gsub(/&lt;\/span&gt;/, '</span>')
511
- end
512
- end
513
-
514
- step_file = step_match.file_colon_line.force_encoding('UTF-8')
515
- step_file.gsub(/^([^:]*\.rb):(\d*)/) do
516
- if index = $1.index('lib/daddy/cucumber/step_definitions/')
517
- step_file = "daddy: #{$1[index..-1]}:#{$2}"
518
- end
519
-
520
- step_file = "<span style=\"cursor: pointer;\" onclick=\"toggle_step_file(this); return false;\">#{step_file}</span>"
521
- end
522
-
523
- @builder.div(:class => 'step_file') do |div|
524
- @builder.span do
525
- @builder << step_file
526
- end
527
- end
528
- end
529
-
530
- def build_cell(cell_type, value, attributes)
531
- @builder.__send__(cell_type, attributes) do
532
- @builder.div do
533
- @builder.span(value,:class => 'step param')
534
- end
535
- end
536
- end
537
-
538
- def inline_css
539
- @builder.style(:type => 'text/css') do
540
- @builder << File.read(File.dirname(__FILE__) + '/cucumber.css')
541
- @builder << File.read(File.dirname(__FILE__) + '/daddy.css')
542
- if File.exist?('features/support/daddy.css')
543
- @builder << File.read('features/support/daddy.css')
544
- end
545
- end
546
- end
547
-
548
- def inline_js
549
- @builder.script(:type => 'text/javascript') do
550
- @builder << inline_jquery
551
- @builder << inline_js_content
552
- @builder << inline_daddy
553
- end
554
- end
555
-
556
- def inline_jquery
557
- File.read(File.dirname(__FILE__) + '/jquery-min.js')
558
- end
559
-
560
- def inline_daddy
561
- ret = ''
562
- ret << File.read(File.join(File.dirname(__FILE__), 'daddy.js'))
563
- ret << File.read(File.join(File.dirname(__FILE__), 'screenshot.js'))
564
-
565
- if should_expand
566
- ret << %w{
567
- $(document).ready(function() {
568
- $('#expander').click();
569
- });
570
- }.join(' ')
571
- end
572
-
573
- ret
574
- end
575
-
576
- def inline_js_content
577
- <<-EOF
578
-
579
- SCENARIOS = "div.scenario h3";
580
-
581
- $(document).ready(function() {
582
- $(SCENARIOS).css('cursor', 'pointer');
583
- $(SCENARIOS).click(function() {
584
- $(this).siblings().toggle(250);
585
- });
586
-
587
- $("#collapser").css('cursor', 'pointer');
588
- $("#collapser").click(function() {
589
- $(SCENARIOS).siblings().hide();
590
- $('li.message').hide();
591
- });
592
-
593
- $("#expander").css('cursor', 'pointer');
594
- $("#expander").click(function() {
595
- $(SCENARIOS).siblings().show();
596
- $('li.message').show();
597
- });
598
- })
599
-
600
- function moveProgressBar(percentDone) {
601
- $("cucumber-header").css('width', percentDone +"%");
602
- }
603
- function makeRed(element_id) {
604
- $('#'+element_id).css('background', '#C40D0D');
605
- $('#'+element_id).css('color', '#FFFFFF');
606
- }
607
- function makeYellow(element_id) {
608
- $('#'+element_id).css('background', '#FAF834');
609
- $('#'+element_id).css('color', '#000000');
610
- }
611
-
612
- EOF
613
- end
614
-
615
- def move_progress
616
- @builder << " <script type=\"text/javascript\">moveProgressBar('#{percent_done}');</script>"
617
- end
618
-
619
- def percent_done
620
- result = 100.0
621
- if @step_count != 0
622
- result = ((@step_number).to_f / @step_count.to_f * 1000).to_i / 10.0
623
- end
624
- result
625
- end
626
-
627
- def format_exception(exception)
628
- (["#{exception.message}"] + exception.backtrace).join("\n")
629
- end
630
-
631
- def backtrace_line(line)
632
- line.gsub(/\A([^:]*\.(?:rb|feature|haml)):(\d*).*\z/) do
633
- if ENV['TM_PROJECT_DIRECTORY']
634
- "<a href=\"txmt://open?url=file://#{File.expand_path($1)}&line=#{$2}\">#{$1}:#{$2}</a> "
635
- else
636
- line
637
- end
638
- end
639
- end
640
-
641
- def print_stats(features)
642
- @builder << "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{format_duration(features.duration)} seconds</strong>\";</script>"
643
- @builder << "<script type=\"text/javascript\">document.getElementById('totals').innerHTML = \"#{print_stat_string(features)}\";</script>"
644
- end
645
-
646
- def print_stat_string(features)
647
- string = String.new
648
- string << dump_count(@runtime.scenarios.length, "scenario")
649
- scenario_count = print_status_counts{|status| @runtime.scenarios(status)}
650
- string << scenario_count if scenario_count
651
- string << "<br />"
652
- string << dump_count(@runtime.steps.length, "step")
653
- step_count = print_status_counts{|status| @runtime.steps(status)}
654
- string << step_count if step_count
655
- end
656
-
657
- def print_status_counts
658
- counts = [:failed, :skipped, :undefined, :pending, :passed].map do |status|
659
- elements = yield status
660
- elements.any? ? "#{elements.length} #{status.to_s}" : nil
661
- end.compact
662
- return " (#{counts.join(', ')})" if counts.any?
663
- end
664
-
665
- def dump_count(count, what, state=nil)
666
- [count, state, "#{what}#{count == 1 ? '' : 's'}"].compact.join(" ")
667
- end
668
-
669
- def create_builder(io)
670
- ::Cucumber::Formatter::OrderedXmlMarkup.new(:target => io, :indent => 0)
671
- end
672
-
673
- class SnippetExtractor #:nodoc:
674
- class NullConverter; def convert(code, pre); code; end; end #:nodoc:
675
- begin; require 'syntax/convertors/html'; @@converter = Syntax::Convertors::HTML.for_syntax "ruby"; rescue LoadError => e; @@converter = NullConverter.new; end
676
-
677
- def snippet(error)
678
- raw_code, line = snippet_for(error[0])
679
- highlighted = @@converter.convert(raw_code, false)
680
- highlighted << "\n<span class=\"comment\"># gem install syntax to get syntax highlighting</span>" if @@converter.is_a?(NullConverter)
681
- post_process(highlighted, line)
682
- end
683
-
684
- def snippet_for(error_line)
685
- if error_line =~ /(.*):(\d+)/
686
- file = $1
687
- line = $2.to_i
688
- [lines_around(file, line), line]
689
- else
690
- ["# Couldn't get snippet for #{error_line}", 1]
691
- end
692
- end
693
-
694
- def lines_around(file, line)
695
- if File.file?(file)
696
- lines = File.open(file).read.split("\n")
697
- min = [0, line-3].max
698
- max = [line+1, lines.length-1].min
699
- selected_lines = []
700
- selected_lines.join("\n")
701
- lines[min..max].join("\n")
702
- else
703
- "# Couldn't get snippet for #{file}"
704
- end
705
- end
706
-
707
- def post_process(highlighted, offending_line)
708
- new_lines = []
709
- highlighted.split("\n").each_with_index do |line, i|
710
- new_line = "<span class=\"linenum\">#{offending_line+i-2}</span>#{line}"
711
- new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
712
- new_lines << new_line
713
- end
714
- new_lines.join("\n")
715
- end
716
-
717
- end
718
- end
719
- end
720
- end