cucumber 2.0.0.beta.3 → 2.0.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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/History.md +131 -32
  4. data/Rakefile +0 -2
  5. data/cucumber.gemspec +4 -3
  6. data/examples/i18n/ht/Rakefile +6 -0
  7. data/examples/i18n/ht/features/adisyon.feature +17 -0
  8. data/examples/i18n/ht/features/divizyon.feature +10 -0
  9. data/examples/i18n/ht/features/step_definitions/kalkilatris_steps.rb +25 -0
  10. data/examples/i18n/ht/lib/kalkilatris.rb +14 -0
  11. data/examples/tcl/features/step_definitions/fib_steps.rb +1 -1
  12. data/features/docs/cli/dry_run.feature +48 -0
  13. data/features/docs/cli/exclude_files.feature +1 -2
  14. data/features/docs/cli/run_specific_scenarios.feature +28 -66
  15. data/features/docs/cli/strict_mode.feature +24 -1
  16. data/features/docs/defining_steps/nested_steps.feature +49 -0
  17. data/features/docs/defining_steps/skip_scenario.feature +31 -2
  18. data/features/docs/defining_steps/snippets.feature +15 -0
  19. data/features/docs/exception_in_after_step_hook.feature +1 -1
  20. data/features/docs/exception_in_around_hook.feature +80 -0
  21. data/features/docs/extending_cucumber/custom_filter.feature +29 -0
  22. data/features/docs/extending_cucumber/custom_formatter.feature +65 -7
  23. data/features/docs/formatters/debug_formatter.feature +24 -17
  24. data/features/docs/formatters/json_formatter.feature +65 -1
  25. data/features/docs/formatters/junit_formatter.feature +40 -0
  26. data/features/docs/formatters/pretty_formatter.feature +42 -0
  27. data/features/docs/formatters/rerun_formatter.feature +3 -2
  28. data/features/docs/getting_started.feature +1 -1
  29. data/features/docs/{wire_protocol_erb.feature → wire_protocol/erb_configuration.feature} +2 -2
  30. data/features/docs/wire_protocol/handle_unexpected_response.feature +30 -0
  31. data/features/docs/wire_protocol/invoke_message.feature +216 -0
  32. data/features/docs/wire_protocol/readme.md +26 -0
  33. data/features/docs/wire_protocol/snippets_message.feature +51 -0
  34. data/features/docs/wire_protocol/step_matches_message.feature +81 -0
  35. data/features/docs/{wire_protocol_table_diffing.feature → wire_protocol/table_diffing.feature} +1 -0
  36. data/features/docs/{wire_protocol_tags.feature → wire_protocol/tags.feature} +1 -0
  37. data/features/docs/{wire_protocol_timeouts.feature → wire_protocol/timeouts.feature} +1 -0
  38. data/features/docs/work_in_progress.feature +1 -1
  39. data/features/docs/writing_support_code/after_hooks.feature +24 -0
  40. data/features/docs/writing_support_code/around_hooks.feature +31 -0
  41. data/features/docs/writing_support_code/before_hook.feature +7 -3
  42. data/features/docs/writing_support_code/tagged_hooks.feature +44 -6
  43. data/features/lib/step_definitions/wire_steps.rb +18 -1
  44. data/features/lib/support/fake_wire_server.rb +10 -7
  45. data/lib/cucumber/cli/configuration.rb +6 -11
  46. data/lib/cucumber/cli/main.rb +2 -2
  47. data/lib/cucumber/cli/options.rb +8 -1
  48. data/lib/cucumber/cli/profile_loader.rb +1 -1
  49. data/lib/cucumber/core_ext/instance_exec.rb +1 -1
  50. data/lib/cucumber/encoding.rb +5 -0
  51. data/lib/cucumber/errors.rb +8 -0
  52. data/lib/cucumber/file_specs.rb +3 -1
  53. data/lib/cucumber/filters/activate_steps.rb +33 -0
  54. data/lib/cucumber/filters/apply_after_hooks.rb +9 -0
  55. data/lib/cucumber/filters/apply_after_step_hooks.rb +12 -0
  56. data/lib/cucumber/filters/apply_around_hooks.rb +12 -0
  57. data/lib/cucumber/filters/apply_before_hooks.rb +9 -0
  58. data/lib/cucumber/{runtime → filters}/gated_receiver.rb +5 -1
  59. data/lib/cucumber/filters/prepare_world.rb +45 -0
  60. data/lib/cucumber/filters/quit.rb +28 -0
  61. data/lib/cucumber/filters/randomizer.rb +40 -0
  62. data/lib/cucumber/{runtime → filters}/tag_limits/test_case_index.rb +4 -2
  63. data/lib/cucumber/{runtime → filters}/tag_limits/verifier.rb +4 -2
  64. data/lib/cucumber/filters/tag_limits.rb +45 -0
  65. data/lib/cucumber/filters.rb +9 -0
  66. data/lib/cucumber/formatter/ansicolor.rb +0 -8
  67. data/lib/cucumber/formatter/console.rb +37 -20
  68. data/lib/cucumber/formatter/debug.rb +1 -8
  69. data/lib/cucumber/formatter/fanout.rb +27 -0
  70. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +10 -9
  71. data/lib/cucumber/formatter/html.rb +31 -6
  72. data/lib/cucumber/formatter/ignore_missing_messages.rb +20 -0
  73. data/lib/cucumber/formatter/junit.rb +97 -2
  74. data/lib/cucumber/formatter/legacy_api/adapter.rb +1060 -0
  75. data/lib/cucumber/formatter/legacy_api/ast.rb +376 -0
  76. data/lib/cucumber/formatter/legacy_api/results.rb +51 -0
  77. data/lib/cucumber/formatter/legacy_api/runtime_facade.rb +30 -0
  78. data/lib/cucumber/formatter/pretty.rb +14 -0
  79. data/lib/cucumber/formatter/progress.rb +10 -0
  80. data/lib/cucumber/formatter/rerun.rb +14 -88
  81. data/lib/cucumber/hooks.rb +97 -0
  82. data/lib/cucumber/language_support/language_methods.rb +0 -54
  83. data/lib/cucumber/multiline_argument/data_table.rb +41 -29
  84. data/lib/cucumber/platform.rb +3 -3
  85. data/lib/cucumber/project_initializer.rb +43 -0
  86. data/lib/cucumber/rb_support/rb_hook.rb +2 -2
  87. data/lib/cucumber/rb_support/rb_step_definition.rb +11 -2
  88. data/lib/cucumber/rb_support/rb_transform.rb +3 -1
  89. data/lib/cucumber/rb_support/rb_world.rb +2 -2
  90. data/lib/cucumber/rb_support/snippet.rb +1 -1
  91. data/lib/cucumber/rspec/doubles.rb +1 -1
  92. data/lib/cucumber/running_test_case.rb +115 -0
  93. data/lib/cucumber/runtime/after_hooks.rb +24 -0
  94. data/lib/cucumber/runtime/before_hooks.rb +23 -0
  95. data/lib/cucumber/runtime/for_programming_languages.rb +4 -8
  96. data/lib/cucumber/runtime/step_hooks.rb +22 -0
  97. data/lib/cucumber/runtime/support_code.rb +70 -5
  98. data/lib/cucumber/runtime.rb +56 -112
  99. data/lib/cucumber/step_match.rb +26 -2
  100. data/lib/cucumber.rb +7 -3
  101. data/spec/cucumber/cli/configuration_spec.rb +16 -1
  102. data/spec/cucumber/cli/profile_loader_spec.rb +10 -0
  103. data/spec/cucumber/core_ext/instance_exec_spec.rb +4 -0
  104. data/spec/cucumber/file_specs_spec.rb +21 -2
  105. data/spec/cucumber/filters/activate_steps_spec.rb +57 -0
  106. data/spec/cucumber/{runtime → filters}/gated_receiver_spec.rb +3 -3
  107. data/spec/cucumber/{runtime → filters}/tag_limits/test_case_index_spec.rb +3 -3
  108. data/spec/cucumber/{runtime → filters}/tag_limits/verifier_spec.rb +4 -4
  109. data/spec/cucumber/{runtime/tag_limits/filter_spec.rb → filters/tag_limits_spec.rb} +6 -6
  110. data/spec/cucumber/formatter/debug_spec.rb +25 -530
  111. data/spec/cucumber/formatter/html_spec.rb +140 -0
  112. data/spec/cucumber/formatter/junit_spec.rb +212 -156
  113. data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +2090 -0
  114. data/spec/cucumber/formatter/pretty_spec.rb +248 -2
  115. data/spec/cucumber/formatter/rerun_spec.rb +107 -0
  116. data/spec/cucumber/formatter/spec_helper.rb +17 -8
  117. data/spec/cucumber/hooks_spec.rb +30 -0
  118. data/spec/cucumber/multiline_argument/data_table_spec.rb +53 -47
  119. data/spec/cucumber/project_initializer_spec.rb +87 -0
  120. data/spec/cucumber/rb_support/rb_language_spec.rb +2 -2
  121. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +32 -7
  122. data/spec/cucumber/rb_support/rb_transform_spec.rb +20 -0
  123. data/spec/cucumber/rb_support/snippet_spec.rb +6 -6
  124. data/spec/cucumber/running_test_case_spec.rb +83 -0
  125. data/spec/cucumber/runtime_spec.rb +1 -5
  126. data/spec/spec_helper.rb +3 -4
  127. metadata +149 -107
  128. data/bin/cuke +0 -60
  129. data/features/docs/extending_cucumber/formatter_callbacks.feature +0 -370
  130. data/features/docs/output_from_hooks.feature +0 -128
  131. data/features/docs/report_called_undefined_steps.feature +0 -57
  132. data/features/docs/wire_protocol.feature +0 -337
  133. data/gem_tasks/yard/default/layout/html/bubble_32x32.png +0 -0
  134. data/gem_tasks/yard/default/layout/html/footer.erb +0 -5
  135. data/gem_tasks/yard/default/layout/html/index.erb +0 -1
  136. data/gem_tasks/yard/default/layout/html/layout.erb +0 -25
  137. data/gem_tasks/yard/default/layout/html/logo.erb +0 -1
  138. data/gem_tasks/yard/default/layout/html/setup.rb +0 -4
  139. data/gem_tasks/yard.rake +0 -43
  140. data/lib/cucumber/mappings.rb +0 -238
  141. data/lib/cucumber/reports/legacy_formatter.rb +0 -1349
  142. data/lib/cucumber/runtime/results.rb +0 -64
  143. data/lib/cucumber/runtime/tag_limits/filter.rb +0 -31
  144. data/lib/cucumber/runtime/tag_limits.rb +0 -15
  145. data/spec/cucumber/mappings_spec.rb +0 -180
  146. data/spec/cucumber/reports/legacy_formatter_spec.rb +0 -1860
  147. data/spec/cucumber/runtime/results_spec.rb +0 -88
@@ -21,12 +21,10 @@ module Cucumber
21
21
 
22
22
  def before_background(background)
23
23
  @outline = false
24
- @before_steps = true
25
24
  @gf.background(background.gherkin_statement)
26
25
  end
27
26
 
28
27
  def before_feature_element(feature_element)
29
- @before_steps = true
30
28
  case(feature_element)
31
29
  when Core::Ast::Scenario
32
30
  @outline = false
@@ -44,6 +42,10 @@ module Cucumber
44
42
  end
45
43
  end
46
44
 
45
+ def before_test_case(test_case)
46
+ @delay_output = true
47
+ end
48
+
47
49
  def scenario_name(keyword, name, file_colon_line, source_indent)
48
50
  if @outline and @options[:expand]
49
51
  return if not @in_instantiated_scenario
@@ -70,10 +72,11 @@ module Cucumber
70
72
  unless @outline and @options[:expand]
71
73
  @gf.step(step.gherkin_statement)
72
74
  pass_delayed_output
73
- @before_steps = false
75
+ @delay_output = false
74
76
  else
75
77
  if @in_instantiated_scenario
76
78
  @current_step_hash = to_hash(step.gherkin_statement)
79
+ @delay_output = true
77
80
  end
78
81
  end
79
82
  if @print_empty_match
@@ -84,7 +87,6 @@ module Cucumber
84
87
  end
85
88
  @gf.match(match)
86
89
  end
87
- @step_time = Time.now
88
90
  end
89
91
 
90
92
  def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
@@ -121,7 +123,7 @@ module Cucumber
121
123
  @current_step_hash['rows'],
122
124
  @current_step_hash['doc_string']))
123
125
  pass_delayed_output
124
- @before_steps = false
126
+ @delay_output = false
125
127
  @gf.match(@current_match)
126
128
  @gf.result(@current_result)
127
129
  end
@@ -139,9 +141,8 @@ module Cucumber
139
141
 
140
142
  #used for capturing duration
141
143
  def after_step(step)
142
- step_finish = (Time.now - @step_time)
143
144
  unless @outline and @options[:expand] and not @in_instantiated_scenario
144
- @gf.append_duration(step_finish)
145
+ step.duration.tap { |duration| @gf.append_duration(duration.nanoseconds / 10 ** 9.0) }
145
146
  end
146
147
  end
147
148
 
@@ -167,7 +168,7 @@ module Cucumber
167
168
  if defined?(JRUBY_VERSION)
168
169
  data = data.to_java_bytes
169
170
  end
170
- unless @before_steps
171
+ unless @delay_output
171
172
  @gf.embedding(mime_type, data)
172
173
  else
173
174
  @delayed_embeddings.push [mime_type, data]
@@ -175,7 +176,7 @@ module Cucumber
175
176
  end
176
177
 
177
178
  def puts(message)
178
- unless @before_steps
179
+ unless @delay_output
179
180
  @gf.write(message)
180
181
  else
181
182
  @delayed_messages.push message
@@ -2,6 +2,7 @@ require 'erb'
2
2
  require 'builder'
3
3
  require 'cucumber/formatter/duration'
4
4
  require 'cucumber/formatter/io'
5
+ require 'pathname'
5
6
 
6
7
  module Cucumber
7
8
  module Formatter
@@ -12,7 +13,7 @@ module Cucumber
12
13
  Cucumber::Core::Ast::Scenario => 'scenario',
13
14
  Cucumber::Core::Ast::ScenarioOutline => 'scenario outline'
14
15
  }
15
- AST_DATA_TABLE = Cucumber::Reports::Legacy::Ast::MultilineArg::DataTable
16
+ AST_DATA_TABLE = LegacyApi::Ast::MultilineArg::DataTable
16
17
 
17
18
  include ERB::Util # for the #h method
18
19
  include Duration
@@ -32,6 +33,7 @@ module Cucumber
32
33
  @img_id = 0
33
34
  @text_id = 0
34
35
  @inside_outline = false
36
+ @previous_step_keyword = nil
35
37
  end
36
38
 
37
39
  def embed(src, mime_type, label)
@@ -50,6 +52,10 @@ module Cucumber
50
52
  def embed_image(src, label)
51
53
  id = "img_#{@img_id}"
52
54
  @img_id += 1
55
+ if @io.respond_to?(:path) and File.file?(src)
56
+ out_dir = Pathname.new(File.dirname(File.absolute_path(@io.path)))
57
+ src = Pathname.new(File.absolute_path(src)).relative_path_from(out_dir)
58
+ end
53
59
  @builder.span(:class => 'embed') do |pre|
54
60
  pre << %{<a href="" onclick="img=document.getElementById('#{id}'); img.style.display = (img.style.display == 'none' ? 'block' : 'none');return false">#{label}</a><br>&nbsp;
55
61
  <img id="#{id}" style="display: none" src="#{src}"/>}
@@ -155,6 +161,10 @@ module Cucumber
155
161
  end
156
162
  end
157
163
 
164
+ def before_test_case(test_case)
165
+ @previous_step_keyword = nil
166
+ end
167
+
158
168
  def before_background(background)
159
169
  @in_background = true
160
170
  @builder << '<div class="background">'
@@ -179,11 +189,16 @@ module Cucumber
179
189
  @scenario_red = false
180
190
  css_class = AST_CLASSES[feature_element.class]
181
191
  @builder << "<div class='#{css_class}'>"
192
+ @in_scenario_outline = feature_element.class == Cucumber::Core::Ast::ScenarioOutline
182
193
  end
183
194
 
184
195
  def after_feature_element(feature_element)
196
+ unless @in_scenario_outline
197
+ print_messages
198
+ @builder << '</ol>'
199
+ end
185
200
  @builder << '</div>'
186
- @open_step_list = true
201
+ @in_scenario_outline = nil
187
202
  end
188
203
 
189
204
  def scenario_name(keyword, name, file_colon_line, source_indent)
@@ -211,7 +226,7 @@ module Cucumber
211
226
  end
212
227
 
213
228
  def before_examples(examples)
214
- @builder << '<div class="examples">'
229
+ @builder << '<div class="examples">'
215
230
  end
216
231
 
217
232
  def after_examples(examples)
@@ -231,10 +246,12 @@ module Cucumber
231
246
  end
232
247
 
233
248
  def after_steps(steps)
234
- @builder << '</ol>'
249
+ print_messages
250
+ @builder << '</ol>' if @in_background or @in_scenario_outline
235
251
  end
236
252
 
237
253
  def before_step(step)
254
+ print_messages
238
255
  @step_id = step.dom_id
239
256
  @step_number += 1
240
257
  @step = step
@@ -267,8 +284,11 @@ module Cucumber
267
284
  def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
268
285
  return if @hide_this_step
269
286
  # print snippet for undefined steps
287
+ unless outline_step?(@step)
288
+ keyword = @step.actual_keyword(@previous_step_keyword)
289
+ @previous_step_keyword = keyword
290
+ end
270
291
  if status == :undefined
271
- keyword = @step.actual_keyword if @step.respond_to?(:actual_keyword)
272
292
  @builder.pre do |pre|
273
293
  # TODO: snippet text should be an event sent to the formatter so we don't
274
294
  # have this couping to the runtime.
@@ -290,6 +310,7 @@ module Cucumber
290
310
 
291
311
  def exception(exception, status)
292
312
  return if @hide_this_step
313
+ print_messages
293
314
  build_exception_detail(exception)
294
315
  end
295
316
 
@@ -554,7 +575,7 @@ module Cucumber
554
575
  end
555
576
 
556
577
  def backtrace_line(line)
557
- line.gsub(/\A([^:]*\.(?:rb|feature|haml)):(\d*).*\z/) do
578
+ line.gsub(/^([^:]*\.(?:rb|feature|haml)):(\d*).*$/) do
558
579
  if ENV['TM_PROJECT_DIRECTORY']
559
580
  "<a href=\"txmt://open?url=file://#{File.expand_path($1)}&line=#{$2}\">#{$1}:#{$2}</a> "
560
581
  else
@@ -595,6 +616,10 @@ module Cucumber
595
616
  Builder::XmlMarkup.new(:target => io, :indent => 0)
596
617
  end
597
618
 
619
+ def outline_step?(step)
620
+ not @step.step.respond_to?(:actual_keyword)
621
+ end
622
+
598
623
  class SnippetExtractor #:nodoc:
599
624
  class NullConverter; def convert(code, pre); code; end; end #:nodoc:
600
625
  begin; require 'syntax/convertors/html'; @@converter = Syntax::Convertors::HTML.for_syntax "ruby"; rescue LoadError => e; @@converter = NullConverter.new; end
@@ -0,0 +1,20 @@
1
+ module Cucumber
2
+ module Formatter
3
+
4
+ class IgnoreMissingMessages < BasicObject
5
+ def initialize(receiver)
6
+ @receiver = receiver
7
+ end
8
+
9
+ def method_missing(message, *args)
10
+ @receiver.send(message, *args) if @receiver.respond_to?(message)
11
+ end
12
+
13
+ def respond_to_missing?(name, include_private = false)
14
+ @receiver.respond_to?(name, include_private)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+
@@ -9,8 +9,8 @@ module Cucumber
9
9
  class Junit
10
10
 
11
11
  # TODO: remove coupling to types
12
- AST_SCENARIO_OUTLINE = Cucumber::Core::Ast::ScenarioOutline
13
- AST_EXAMPLE_ROW = Reports::LegacyExampleTableRow
12
+ AST_SCENARIO_OUTLINE = Core::Ast::ScenarioOutline
13
+ AST_EXAMPLE_ROW = LegacyApi::Ast::ExampleTableRow
14
14
 
15
15
  include Io
16
16
 
@@ -129,6 +129,34 @@ module Cucumber
129
129
  @header_row = false if @header_row
130
130
  end
131
131
 
132
+ def before_test_case(test_case)
133
+ if @options[:expand] and test_case.keyword == "Scenario Outline"
134
+ @exception = nil
135
+ end
136
+ end
137
+
138
+ def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
139
+ if @options[:expand] and @in_examples
140
+ if not @exception and exception
141
+ @exception = exception
142
+ end
143
+ end
144
+ end
145
+
146
+ def after_test_case(test_case, result)
147
+ if @options[:expand] and test_case.keyword == "Scenario Outline"
148
+ test_case_name = NameBuilder.new(test_case)
149
+ @scenario = test_case_name.outline_name
150
+ @output = "#{test_case.keyword}: #{@scenario}\n\n"
151
+ if result.failed?
152
+ @output += "Example row: #{test_case_name.row_name}\n"
153
+ @output += "\nMessage:\n"
154
+ end
155
+ test_case_result = ResultBuilder.new(result)
156
+ build_testcase(test_case_result.test_case_duration, test_case_result.status, @exception, test_case_name.name_suffix)
157
+ end
158
+ end
159
+
132
160
  private
133
161
 
134
162
  def build_testcase(duration, status, exception = nil, suffix = "")
@@ -176,5 +204,72 @@ module Cucumber
176
204
  end
177
205
 
178
206
  end
207
+
208
+ class NameBuilder
209
+ attr_reader :outline_name, :name_suffix, :row_name
210
+
211
+ def initialize(test_case)
212
+ test_case.describe_source_to self
213
+ end
214
+
215
+ def feature(*)
216
+ self
217
+ end
218
+
219
+ def scenario(*)
220
+ self
221
+ end
222
+
223
+ def scenario_outline(outline)
224
+ @outline_name = outline.name
225
+ self
226
+ end
227
+
228
+ def examples_table(*)
229
+ self
230
+ end
231
+
232
+ def examples_table_row(row)
233
+ @row_name = '| ' + row.values.join(' | ') + ' |'
234
+ @name_suffix = " (outline example : #{@row_name})"
235
+ self
236
+ end
237
+ end
238
+
239
+ class ResultBuilder
240
+ attr_reader :status, :test_case_duration
241
+ def initialize(result)
242
+ @test_case_duration = 0
243
+ result.describe_to(self)
244
+ end
245
+
246
+ def passed
247
+ @status = :passed
248
+ end
249
+
250
+ def failed
251
+ @status = :failed
252
+ end
253
+
254
+ def undefined
255
+ @status = :undefined
256
+ end
257
+
258
+ def skipped
259
+ @status = :skipped
260
+ end
261
+
262
+ def pending(*)
263
+ @status = :pending
264
+ end
265
+
266
+ def exception(*)
267
+ end
268
+
269
+ def duration(duration, *)
270
+ duration.tap { |duration| @test_case_duration = duration.nanoseconds / 10 ** 9.0 }
271
+ end
272
+ end
273
+
179
274
  end
180
275
  end