cucumber 0.2.3 → 0.3.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.
Files changed (128) hide show
  1. data/History.txt +56 -1
  2. data/Manifest.txt +70 -49
  3. data/config/hoe.rb +1 -1
  4. data/cucumber.yml +1 -1
  5. data/examples/i18n/bg/Rakefile +6 -0
  6. data/examples/i18n/bg/features/addition.feature +11 -0
  7. data/examples/i18n/bg/features/consecutive_calculations.feature +18 -0
  8. data/examples/i18n/bg/features/division.feature +16 -0
  9. data/examples/i18n/bg/features/step_definitons/calculator_steps.rb +24 -0
  10. data/examples/i18n/bg/features/support/env.rb +6 -0
  11. data/examples/i18n/bg/features/support/world.rb +8 -0
  12. data/examples/i18n/bg/lib/calculator.rb +24 -0
  13. data/examples/i18n/ru/features/support/world.rb +4 -3
  14. data/examples/i18n/sk/Rakefile +6 -0
  15. data/examples/i18n/sk/features/addition.feature +16 -0
  16. data/examples/i18n/sk/features/division.feature +9 -0
  17. data/examples/i18n/sk/features/step_definitons/calculator_steps.rb +24 -0
  18. data/examples/i18n/sk/lib/calculator.rb +14 -0
  19. data/examples/self_test/features/background/background_with_name.feature +7 -0
  20. data/examples/self_test/features/background/passing_background.feature +2 -2
  21. data/examples/self_test/features/step_definitions/sample_steps.rb +18 -2
  22. data/examples/self_test/features/undefined_multiline_args.feature +12 -0
  23. data/examples/sinatra/features/support/env.rb +2 -6
  24. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +1 -4
  25. data/examples/tickets/Rakefile +1 -1
  26. data/examples/tickets/features/229/tagged_hooks.feature +8 -0
  27. data/examples/tickets/features/229/tagged_hooks.rb +14 -0
  28. data/examples/tickets/features/270/back.feature +14 -0
  29. data/examples/tickets/features/270/back.steps.rb +14 -0
  30. data/examples/tickets/features/279/py_string_indent.feature +25 -0
  31. data/examples/tickets/features/279/py_string_indent.steps.rb +12 -0
  32. data/examples/tickets/features/279/wrong.feature_ +11 -0
  33. data/examples/tickets/features/step_definitons/tickets_steps.rb +0 -7
  34. data/features/background.feature +21 -3
  35. data/features/cucumber_cli.feature +18 -5
  36. data/features/cucumber_cli_outlines.feature +4 -1
  37. data/features/rake_task.feature +132 -0
  38. data/features/snippet.feature +23 -0
  39. data/features/step_definitions/cucumber_steps.rb +46 -15
  40. data/features/support/env.rb +61 -4
  41. data/features/usage.feature +5 -0
  42. data/gem_tasks/deployment.rake +1 -1
  43. data/lib/cucumber/ast/background.rb +14 -4
  44. data/lib/cucumber/ast/examples.rb +0 -12
  45. data/lib/cucumber/ast/feature.rb +2 -12
  46. data/lib/cucumber/ast/feature_element.rb +4 -8
  47. data/lib/cucumber/ast/features.rb +1 -1
  48. data/lib/cucumber/ast/outline_table.rb +20 -20
  49. data/lib/cucumber/ast/py_string.rb +6 -11
  50. data/lib/cucumber/ast/scenario.rb +1 -8
  51. data/lib/cucumber/ast/scenario_outline.rb +1 -11
  52. data/lib/cucumber/ast/step.rb +3 -9
  53. data/lib/cucumber/ast/step_collection.rb +0 -4
  54. data/lib/cucumber/ast/step_invocation.rb +5 -6
  55. data/lib/cucumber/ast/table.rb +5 -22
  56. data/lib/cucumber/ast/tags.rb +9 -9
  57. data/lib/cucumber/ast/visitor.rb +12 -25
  58. data/lib/cucumber/cli/configuration.rb +4 -4
  59. data/lib/cucumber/cli/main.rb +10 -3
  60. data/lib/cucumber/core_ext/instance_exec.rb +17 -4
  61. data/lib/cucumber/formatter/ansicolor.rb +1 -1
  62. data/lib/cucumber/formatter/console.rb +2 -1
  63. data/lib/cucumber/formatter/html.rb +21 -7
  64. data/lib/cucumber/formatter/pretty.rb +27 -20
  65. data/lib/cucumber/formatter/usage.rb +16 -0
  66. data/lib/cucumber/languages.yml +23 -5
  67. data/lib/cucumber/parser/feature.rb +231 -114
  68. data/lib/cucumber/parser/feature.tt +120 -25
  69. data/lib/cucumber/parser/table.rb +37 -25
  70. data/lib/cucumber/parser/table.tt +15 -3
  71. data/lib/cucumber/parser/treetop_ext.rb +48 -9
  72. data/lib/cucumber/rake/task.rb +29 -6
  73. data/lib/cucumber/step_definition.rb +4 -2
  74. data/lib/cucumber/step_mother.rb +143 -26
  75. data/lib/cucumber/version.rb +2 -2
  76. data/rails_generators/cucumber/templates/paths.rb +13 -4
  77. data/rails_generators/cucumber/templates/webrat_steps.rb +16 -0
  78. data/{specs → spec}/cucumber/ast/background_spec.rb +1 -0
  79. data/{specs → spec}/cucumber/ast/feature_factory.rb +1 -1
  80. data/{specs → spec}/cucumber/ast/feature_spec.rb +2 -2
  81. data/{specs → spec}/cucumber/ast/py_string_spec.rb +0 -0
  82. data/{specs → spec}/cucumber/ast/scenario_outline_spec.rb +0 -0
  83. data/{specs → spec}/cucumber/ast/scenario_spec.rb +0 -27
  84. data/{specs → spec}/cucumber/ast/step_collection_spec.rb +0 -0
  85. data/{specs → spec}/cucumber/ast/step_spec.rb +0 -0
  86. data/{specs → spec}/cucumber/ast/table_spec.rb +2 -2
  87. data/{specs → spec}/cucumber/broadcaster_spec.rb +0 -0
  88. data/{specs → spec}/cucumber/cli/configuration_spec.rb +0 -0
  89. data/{specs → spec}/cucumber/cli/main_spec.rb +5 -1
  90. data/spec/cucumber/core_ext/proc_spec.rb +54 -0
  91. data/{specs → spec}/cucumber/core_ext/string_spec.rb +0 -0
  92. data/{specs → spec}/cucumber/formatter/ansicolor_spec.rb +0 -0
  93. data/{specs → spec}/cucumber/formatter/color_io_spec.rb +0 -0
  94. data/{specs → spec}/cucumber/formatter/html/cucumber.css +0 -0
  95. data/{specs → spec}/cucumber/formatter/html/cucumber.js +0 -0
  96. data/{specs → spec}/cucumber/formatter/html/index.html +0 -0
  97. data/{specs → spec}/cucumber/formatter/html/jquery-1.3.min.js +0 -0
  98. data/{specs → spec}/cucumber/formatter/html/jquery.uitableedit.js +0 -0
  99. data/{specs → spec}/cucumber/formatters/profile_formatter_spec.rb +0 -0
  100. data/{specs → spec}/cucumber/parser/feature_parser_spec.rb +43 -41
  101. data/{specs → spec}/cucumber/parser/table_parser_spec.rb +0 -0
  102. data/{specs → spec}/cucumber/rails/stubs/mini_rails.rb +0 -0
  103. data/{specs → spec}/cucumber/rails/stubs/test_help.rb +0 -0
  104. data/{specs → spec}/cucumber/rails/world_spec.rb +0 -0
  105. data/{specs → spec}/cucumber/sell_cucumbers.feature +0 -0
  106. data/{specs → spec}/cucumber/step_definition_spec.rb +0 -0
  107. data/{specs → spec}/cucumber/step_mother_spec.rb +63 -4
  108. data/{specs → spec}/cucumber/treetop_parser/empty_feature.feature +0 -0
  109. data/{specs → spec}/cucumber/treetop_parser/empty_scenario.feature +0 -0
  110. data/{specs → spec}/cucumber/treetop_parser/empty_scenario_outline.feature +0 -0
  111. data/{specs → spec}/cucumber/treetop_parser/fit_scenario.feature +0 -0
  112. data/{specs → spec}/cucumber/treetop_parser/given_scenario.feature +0 -0
  113. data/{specs → spec}/cucumber/treetop_parser/invalid_scenario_outlines.feature +0 -0
  114. data/{specs → spec}/cucumber/treetop_parser/multiline_steps.feature +0 -0
  115. data/{specs → spec}/cucumber/treetop_parser/multiple_tables.feature +0 -0
  116. data/{specs → spec}/cucumber/treetop_parser/scenario_outline.feature +0 -0
  117. data/{specs → spec}/cucumber/treetop_parser/spaces.feature +0 -0
  118. data/{specs → spec}/cucumber/treetop_parser/test_dos.feature +0 -0
  119. data/{specs → spec}/cucumber/treetop_parser/with_comments.feature +0 -0
  120. data/{specs → spec}/cucumber/treetop_parser/with_tags.feature +0 -0
  121. data/{specs → spec}/cucumber/world/pending_spec.rb +0 -0
  122. data/{specs → spec}/spec.opts +0 -0
  123. data/{specs → spec}/spec_helper.rb +2 -11
  124. metadata +72 -51
  125. data/examples/tickets/cucumber.yml +0 -3
  126. data/lib/cucumber/parser/basic.rb +0 -0
  127. data/specs/cucumber/ast/tags_spec.rb +0 -19
  128. data/specs/cucumber/core_ext/proc_spec.rb +0 -37
@@ -8,7 +8,7 @@ module Cucumber
8
8
  def initialize(background, comment, tags, line, keyword, name, steps)
9
9
  @background, @comment, @tags, @line, @keyword, @name = background, comment, tags, line, keyword, name
10
10
  attach_steps(steps)
11
-
11
+
12
12
  step_invocations = steps.map{|step| step.step_invocation}
13
13
  if @background
14
14
  @steps = @background.step_collection(step_invocations)
@@ -22,13 +22,6 @@ module Cucumber
22
22
  @background.feature = feature if @background
23
23
  end
24
24
 
25
- def descend?(visitor)
26
- visitor.matches_lines?(self) &&
27
- visitor.included_by_tags?(self) &&
28
- !visitor.excluded_by_tags?(self) &&
29
- visitor.matches_scenario_names?(self)
30
- end
31
-
32
25
  def accept(visitor)
33
26
  visitor.visit_comment(@comment)
34
27
  visitor.visit_tags(@tags)
@@ -30,16 +30,6 @@ module Cucumber
30
30
  @background.feature = feature if @background
31
31
  end
32
32
 
33
- def descend?(visitor)
34
- @examples_array.detect { |examples| examples.descend?(visitor) }
35
- end
36
-
37
- def matches_tags_and_name?(visitor)
38
- visitor.included_by_tags?(self) &&
39
- !visitor.excluded_by_tags?(self) &&
40
- visitor.matches_scenario_names?(self)
41
- end
42
-
43
33
  def accept(visitor)
44
34
  visitor.visit_comment(@comment)
45
35
  visitor.visit_tags(@tags)
@@ -48,7 +38,7 @@ module Cucumber
48
38
 
49
39
  skip_invoke! if @background && @background.failed?
50
40
  @examples_array.each do |examples|
51
- visitor.visit_examples(examples) if examples.descend?(visitor)
41
+ visitor.visit_examples(examples)
52
42
  end
53
43
  end
54
44
 
@@ -33,13 +33,11 @@ module Cucumber
33
33
  def accept(visitor)
34
34
  # The only time a Step is visited is when it is in a ScenarioOutline.
35
35
  # Otherwise it's always StepInvocation that gest visited instead.
36
- visit_step_details(visitor, first_match(visitor), @multiline_arg, :skipped, nil, nil)
36
+ visit_step_result(visitor, first_match(visitor), @multiline_arg, :skipped, nil, nil)
37
37
  end
38
38
 
39
- def visit_step_details(visitor, step_match, multiline_arg, status, exception, background)
40
- visitor.visit_step_name(@keyword, step_match, status, source_indent, background)
41
- visitor.visit_multiline_arg(@multiline_arg) if @multiline_arg
42
- visitor.visit_exception(exception, status) if exception
39
+ def visit_step_result(visitor, step_match, multiline_arg, status, exception, background)
40
+ visitor.visit_step_result(@keyword, step_match, @multiline_arg, status, exception, source_indent, background)
43
41
  end
44
42
 
45
43
  def first_match(visitor)
@@ -58,10 +56,6 @@ module Cucumber
58
56
  [:step, @line, @keyword, @name, (@multiline_arg.nil? ? nil : @multiline_arg.to_sexp)].compact
59
57
  end
60
58
 
61
- def matches_lines?(lines)
62
- lines.index(@line) || (@multiline_arg && @multiline_arg.matches_lines?(lines))
63
- end
64
-
65
59
  def source_indent
66
60
  @feature_element.source_indent(text_length)
67
61
  end
@@ -41,10 +41,6 @@ module Cucumber
41
41
  @steps[i-1]
42
42
  end
43
43
 
44
- def matches_lines?(lines)
45
- @steps.detect {|step| step.matches_lines?(lines)}
46
- end
47
-
48
44
  def empty?
49
45
  @steps.empty?
50
46
  end
@@ -20,7 +20,7 @@ module Cucumber
20
20
 
21
21
  def accept(visitor)
22
22
  invoke(visitor.step_mother, visitor.options)
23
- @step.visit_step_details(visitor, @step_match, @multiline_arg, @status, @exception, @background)
23
+ @step.visit_step_result(visitor, @step_match, @multiline_arg, @status, @exception, @background)
24
24
  end
25
25
 
26
26
  def invoke(step_mother, options)
@@ -68,7 +68,6 @@ module Cucumber
68
68
 
69
69
  def status!(status)
70
70
  @status = status
71
- @multiline_arg.status = status if @multiline_arg
72
71
  @matched_cells.each do |cell|
73
72
  cell.status = status
74
73
  end
@@ -86,10 +85,6 @@ module Cucumber
86
85
  end
87
86
  end
88
87
 
89
- def matches_lines?(lines)
90
- @step.matches_lines?(lines)
91
- end
92
-
93
88
  def text_length
94
89
  @step.text_length
95
90
  end
@@ -98,6 +93,10 @@ module Cucumber
98
93
  @step.keyword
99
94
  end
100
95
 
96
+ def multiline_arg
97
+ @step.multiline_arg
98
+ end
99
+
101
100
  def file_colon_line
102
101
  @step.file_colon_line
103
102
  end
@@ -12,6 +12,10 @@ module Cucumber
12
12
 
13
13
  attr_accessor :file
14
14
 
15
+ def self.default_arg_name
16
+ "table"
17
+ end
18
+
15
19
  def initialize(raw, conversions = NULL_CONVERSIONS.dup)
16
20
  # Verify that it's square
17
21
  raw.transpose
@@ -101,10 +105,6 @@ module Cucumber
101
105
  cells_rows.each(&proc)
102
106
  end
103
107
 
104
- def matches_lines?(lines)
105
- cells_rows.detect{|row| row.matches_lines?(lines)}
106
- end
107
-
108
108
  def accept(visitor)
109
109
  cells_rows.each do |row|
110
110
  visitor.visit_table_row(row)
@@ -112,12 +112,6 @@ module Cucumber
112
112
  nil
113
113
  end
114
114
 
115
- def status=(status)
116
- cells_rows.each do |row|
117
- row.status = status
118
- end
119
- end
120
-
121
115
  # For testing only
122
116
  def to_sexp #:nodoc:
123
117
  [:table, *cells_rows.map{|row| row.to_sexp}]
@@ -253,10 +247,6 @@ module Cucumber
253
247
  @table, @cells = table, cells
254
248
  end
255
249
 
256
- def matches_lines?(lines)
257
- lines.index(line)
258
- end
259
-
260
250
  def accept(visitor)
261
251
  each do |cell|
262
252
  visitor.visit_table_cell(cell)
@@ -266,7 +256,7 @@ module Cucumber
266
256
 
267
257
  # For testing only
268
258
  def to_sexp #:nodoc:
269
- [:row, *@cells.map{|cell| cell.to_sexp}]
259
+ [:row, line, *@cells.map{|cell| cell.to_sexp}]
270
260
  end
271
261
 
272
262
  def to_hash #:nodoc:
@@ -289,12 +279,6 @@ module Cucumber
289
279
  "row_#{line}"
290
280
  end
291
281
 
292
- def status=(status)
293
- each do |cell|
294
- cell.status = status
295
- end
296
- end
297
-
298
282
  private
299
283
 
300
284
  def index
@@ -316,7 +300,6 @@ module Cucumber
316
300
 
317
301
  def initialize(value, table, row, col, line)
318
302
  @value, @table, @row, @col, @line = value, table, row, col, line
319
- @status = :passed
320
303
  end
321
304
 
322
305
  def accept(visitor)
@@ -7,24 +7,24 @@ module Cucumber
7
7
  # This gets stored internally as <tt>["invoice", "release_2"]</tt>
8
8
  #
9
9
  class Tags
10
+ def self.strip_prefix(tag_name)
11
+ tag_name =~ /^@(.*)/ ? $1 : tag_name
12
+ end
13
+
10
14
  def initialize(line, tag_names)
11
15
  @line, @tag_names = line, tag_names
12
16
  end
13
17
 
14
- def has_tags?(tags)
15
- (@tag_names & tags).any?
16
- end
17
-
18
- def matches_lines?(lines)
19
- lines.index(@line)
20
- end
21
-
22
18
  def accept(visitor)
23
19
  @tag_names.each do |tag_name|
24
20
  visitor.visit_tag_name(tag_name)
25
21
  end
26
22
  end
27
-
23
+
24
+ def accept_hook?(hook)
25
+ hook.matches_tag_names?(@tag_names)
26
+ end
27
+
28
28
  def to_sexp
29
29
  @tag_names.map{|tag_name| [:tag, tag_name]}
30
30
  end
@@ -8,25 +8,6 @@ module Cucumber
8
8
  def initialize(step_mother)
9
9
  @options = {}
10
10
  @step_mother = step_mother
11
- @current_feature_lines = []
12
- end
13
-
14
- def current_feature_lines=(lines)
15
- @current_feature_lines = lines
16
- end
17
-
18
- def matches_lines?(node)
19
- @current_feature_lines.empty? || node.matches_lines?(@current_feature_lines)
20
- end
21
-
22
- def included_by_tags?(node)
23
- tags = options[:include_tags] || []
24
- tags.empty? || node.has_tags?(tags)
25
- end
26
-
27
- def excluded_by_tags?(node)
28
- tags = options[:exclude_tags] || []
29
- tags.any? && node.has_tags?(tags)
30
11
  end
31
12
 
32
13
  def matches_scenario_names?(node)
@@ -93,14 +74,23 @@ module Cucumber
93
74
  step.accept(self)
94
75
  end
95
76
 
96
- def visit_step_name(keyword, step_match, status, source_indent, background)
77
+ def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
78
+ visit_step_name(keyword, step_match, status, source_indent, background)
79
+ visit_multiline_arg(multiline_arg) if multiline_arg
80
+ visit_exception(exception, status) if exception
81
+ end
82
+
83
+ def visit_step_name(keyword, step_match, status, source_indent, background) #:nodoc:
97
84
  end
98
85
 
99
- def visit_multiline_arg(multiline_arg)
86
+ def visit_multiline_arg(multiline_arg) #:nodoc:
100
87
  multiline_arg.accept(self)
101
88
  end
102
89
 
103
- def visit_py_string(string, status)
90
+ def visit_exception(exception, status) #:nodoc:
91
+ end
92
+
93
+ def visit_py_string(string)
104
94
  end
105
95
 
106
96
  def visit_table_row(table_row)
@@ -114,9 +104,6 @@ module Cucumber
114
104
  def visit_table_cell_value(value, width, status)
115
105
  end
116
106
 
117
- def visit_exception(exception, status)
118
- end
119
-
120
107
  def announce(announcement)
121
108
  end
122
109
 
@@ -187,8 +187,8 @@ module Cucumber
187
187
  excludes = excludes.map{|tag| tag[1..-1]}
188
188
 
189
189
  # Strip @
190
- includes = includes.map{|tag| tag =~ /^@(.*)/ ? $1 : tag}
191
- excludes = excludes.map{|tag| tag =~ /^@(.*)/ ? $1 : tag}
190
+ includes = includes.map{|tag| Ast::Tags.strip_prefix(tag)}
191
+ excludes = excludes.map{|tag| Ast::Tags.strip_prefix(tag)}
192
192
  [includes, excludes]
193
193
  end
194
194
 
@@ -257,11 +257,11 @@ module Cucumber
257
257
 
258
258
  potential_feature_files
259
259
  end
260
-
260
+
261
261
  protected
262
262
 
263
263
  def feature_dirs
264
- feature_files.map { |f| File.directory?(f) ? f : File.dirname(f) }.uniq
264
+ @paths.map { |f| File.directory?(f) ? f : File.dirname(f) }.uniq
265
265
  end
266
266
 
267
267
  def constantize(camel_cased_word)
@@ -52,8 +52,11 @@ module Cucumber
52
52
 
53
53
  verbose_log("Features:")
54
54
  configuration.feature_files.each do |f|
55
- features.add_feature(parser.parse_file(f))
56
- verbose_log(" * #{f}")
55
+ feature = parser.parse_file(f, configuration.options)
56
+ if feature
57
+ features.add_feature(feature)
58
+ verbose_log(" * #{f}")
59
+ end
57
60
  end
58
61
  verbose_log("\n"*2)
59
62
  features
@@ -89,7 +92,11 @@ module Cucumber
89
92
 
90
93
  def enable_diffing
91
94
  if configuration.diff_enabled? && defined?(::Spec)
92
- require 'spec/expectations/differs/default'
95
+ begin
96
+ require 'spec/runner/differs/default' # RSpec >=1.2.4
97
+ rescue ::LoadError
98
+ require 'spec/expectations/differs/default' # RSpec <=1.2.3
99
+ end
93
100
  options = OpenStruct.new(:diff_format => :unified, :context_lines => 3)
94
101
  ::Spec::Expectations.differ = ::Spec::Expectations::Differs::Default.new(options)
95
102
  end
@@ -7,12 +7,14 @@ end
7
7
 
8
8
  class Object
9
9
  def cucumber_instance_exec(check_arity, pseudo_method, *args, &block)
10
- arity = block.arity
11
- arity = 0 if arity == -1
12
10
  cucumber_run_with_backtrace_filtering(pseudo_method) do
13
- if check_arity && args.length != arity
11
+ if check_arity && !cucumber_compatible_arity?(args, block)
14
12
  instance_exec do
15
- raise Cucumber::ArityMismatchError.new("expected #{arity} block argument(s), got #{args.length}")
13
+ s1 = cucumber_arity(block) == 1 ? "" : "s"
14
+ s2 = args.length == 1 ? "" : "s"
15
+ raise Cucumber::ArityMismatchError.new(
16
+ "Your block takes #{cucumber_arity(block)} argument#{s1}, but the Regexp matched #{args.length} argument#{s2}."
17
+ )
16
18
  end
17
19
  else
18
20
  instance_exec(*args, &block)
@@ -20,6 +22,17 @@ class Object
20
22
  end
21
23
  end
22
24
 
25
+ def cucumber_arity(block)
26
+ a = block.arity
27
+ Cucumber::RUBY_1_9 ? a : (a == -1 ? 0 : a)
28
+ end
29
+
30
+ def cucumber_compatible_arity?(args, block)
31
+ a = cucumber_arity(block)
32
+ return true if (a == -1) && Cucumber::RUBY_1_9
33
+ a == args.length
34
+ end
35
+
23
36
  def cucumber_run_with_backtrace_filtering(pseudo_method)
24
37
  begin
25
38
  yield
@@ -19,7 +19,7 @@ elsif Cucumber::WINDOWS && Cucumber::JRUBY
19
19
  end
20
20
  end
21
21
 
22
- Term::ANSIColor.coloring = false if !STDOUT.tty?
22
+ Term::ANSIColor.coloring = false if !STDOUT.tty? and not ENV.has_key?("AUTOTEST")
23
23
 
24
24
  module Cucumber
25
25
  module Formatter
@@ -74,7 +74,8 @@ module Cucumber
74
74
  return if undefined.empty?
75
75
  snippets = undefined.map do |step|
76
76
  step_name = Undefined === step.exception ? step.exception.step_name : step.name
77
- snippet = @step_mother.snippet_text(step.actual_keyword, step_name)
77
+ step_multiline_class = step.multiline_arg ? step.multiline_arg.class : nil
78
+ snippet = @step_mother.snippet_text(step.actual_keyword, step_name, step_multiline_class)
78
79
  snippet
79
80
  end.compact.uniq
80
81
 
@@ -1,3 +1,4 @@
1
+ require 'erb'
1
2
  begin
2
3
  require 'builder'
3
4
  rescue LoadError
@@ -8,6 +9,8 @@ end
8
9
  module Cucumber
9
10
  module Formatter
10
11
  class Html < Ast::Visitor
12
+ include ERB::Util # for the #h method
13
+
11
14
  def initialize(step_mother, io, options)
12
15
  super(step_mother)
13
16
  @builder = Builder::XmlMarkup.new(:target => io, :indent => 2)
@@ -74,9 +77,11 @@ module Cucumber
74
77
  end
75
78
 
76
79
  def visit_outline_table(outline_table)
80
+ @outline_row = 0
77
81
  @builder.table do
78
82
  super(outline_table)
79
83
  end
84
+ @outline_row = nil
80
85
  end
81
86
 
82
87
  def visit_examples_name(keyword, name)
@@ -91,8 +96,13 @@ module Cucumber
91
96
 
92
97
  def visit_step(step)
93
98
  @step_id = step.dom_id
94
- @builder.li(:id => @step_id) do
95
- super
99
+ super
100
+ end
101
+
102
+ def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
103
+ @status = status
104
+ @builder.li(:id => @step_id, :class => status) do
105
+ super(keyword, step_match, multiline_arg, status, exception, source_indent, background)
96
106
  end
97
107
  end
98
108
 
@@ -103,8 +113,8 @@ module Cucumber
103
113
 
104
114
  unless @skip_step
105
115
  step_name = step_match.format_args(lambda{|param| "<span>#{param}</span>"})
106
- @builder.div(:class => status) do |div|
107
- div << "#{keyword} #{step_name}"
116
+ @builder.div do |div|
117
+ div << h("#{keyword} #{step_name}")
108
118
  end
109
119
  end
110
120
  end
@@ -124,8 +134,8 @@ module Cucumber
124
134
  end
125
135
  end
126
136
 
127
- def visit_py_string(string, status)
128
- @builder.pre(:class => status) do |pre|
137
+ def visit_py_string(string)
138
+ @builder.pre(:class => @status) do |pre|
129
139
  pre << string
130
140
  end
131
141
  end
@@ -145,10 +155,14 @@ module Cucumber
145
155
  end
146
156
  end
147
157
  end
158
+ @outline_row += 1 if @outline_row
148
159
  end
149
160
 
150
161
  def visit_table_cell_value(value, width, status)
151
- @builder.td(value, :class => status, :id => "#{@row_id}_#{@col_index}")
162
+ cell_type = @outline_row == 0 ? :th : :td
163
+ attributes = {:id => "#{@row_id}_#{@col_index}"}
164
+ attributes[:class] = status if status
165
+ @builder.__send__(cell_type, value, attributes)
152
166
  @col_index += 1
153
167
  end
154
168