diff --git a/features/docs/formatters/pretty_formatter.feature b/features/docs/formatters/pretty_formatter.feature index b8f9bf5352..d2c65a3818 100644 --- a/features/docs/formatters/pretty_formatter.feature +++ b/features/docs/formatters/pretty_formatter.feature @@ -28,4 +28,46 @@ Feature: Pretty output formatter """ Using the default profile... """ + Scenario: Hook output should be printed before hook exception + Given the standard step definitions + And a file named "features/test.feature" with: + """ + Feature: + Scenario: + Given this step passes + """ + And a file named "features/step_definitions/output_steps.rb" with: + """ + Before do + puts "Before hook" + end + AfterStep do + puts "AfterStep hook" + end + + After do + puts "After hook" + raise "error" + end + """ + When I run `cucumber -q -f pretty features/test.feature` + Then the stderr should not contain anything + Then it should fail with: + """ + Feature: + + Scenario: + Before hook + Given this step passes + AfterStep hook + After hook + error (RuntimeError) + ./features/step_definitions/output_steps.rb:11:in `After' + + Failing Scenarios: + cucumber features/test.feature:2 + + 1 scenario (1 failed) + 1 step (1 passed) + """ diff --git a/features/docs/output_from_hooks.feature b/features/docs/output_from_hooks.feature index 74a105a439..f8444b7550 100644 --- a/features/docs/output_from_hooks.feature +++ b/features/docs/output_from_hooks.feature @@ -110,15 +110,15 @@ Feature: Hook output feature before_table_cell table_cell_value after_table_cell + puts + embed + puts + embed + puts + embed + puts + embed after_table_row - puts - embed - puts - embed - puts - embed - puts - embed after_outline_table after_examples after_examples_array diff --git a/lib/cucumber/formatter/pretty.rb b/lib/cucumber/formatter/pretty.rb index 5e78c86ce2..eabb92ff94 100644 --- a/lib/cucumber/formatter/pretty.rb +++ b/lib/cucumber/formatter/pretty.rb @@ -72,6 +72,7 @@ def before_feature_element(feature_element) end def after_feature_element(feature_element) + print_messages @io.puts @io.flush end @@ -125,6 +126,7 @@ def scenario_name(keyword, name, file_colon_line, source_indent) def before_step(step) @current_step = step @indent = 6 + print_messages end def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line) @@ -161,6 +163,7 @@ def doc_string(string) def exception(exception, status) return if @hide_this_step + print_messages print_exception(exception, status, @indent) @io.flush end diff --git a/lib/cucumber/reports/legacy_formatter.rb b/lib/cucumber/reports/legacy_formatter.rb index b1c5c70ed0..959cb47179 100644 --- a/lib/cucumber/reports/legacy_formatter.rb +++ b/lib/cucumber/reports/legacy_formatter.rb @@ -205,7 +205,7 @@ def before attr_reader :current_test_step_source def before_test_case(test_case) - @before_hook_results = Legacy::Ast::NodeCollection.new + @before_hook_results = Legacy::Ast::HookResultCollection.new end def before_test_step(test_step) @@ -401,7 +401,7 @@ def indented(nasty_old_conflation_of_name_and_description) module PrintsAfterHooks def after_hook_results - @after_hook_results ||= Legacy::Ast::NodeCollection.new + @after_hook_results ||= Legacy::Ast::HookResultCollection.new end def after_hook(result) @@ -739,8 +739,8 @@ class TableRowPrinterBase < Struct.new(:formatter, :node, :before_hook_results) include PrintsAfterHooks def after_step_hook(result) - @after_step_hook_result ||= [] - @after_step_hook_result.push result + @after_step_hook_result ||= Legacy::Ast::HookResultCollection.new + @after_step_hook_result << result end def after_test_case(*args) @@ -804,9 +804,11 @@ def after formatter.table_cell_value(value, @status || :skipped) formatter.after_table_cell(value) end + @after_step_hook_result.send_output_to(formatter) if @after_step_hook_result + after_hook_results.send_output_to(formatter) formatter.after_table_row(legacy_table_row) - @after_step_hook_result.each { |result| result.accept formatter } if @after_step_hook_result - after_hook_results.accept(formatter) + @after_step_hook_result.describe_exception_to(formatter) if @after_step_hook_result + after_hook_results.describe_exception_to(formatter) @done = true self end @@ -840,7 +842,7 @@ def step_invocation(step_invocation, source) def after return if @done @child.after if @child - @after_step_hook_result.each { |result| result.accept formatter } if @after_step_hook_result + @after_step_hook_result.accept(formatter) if @after_step_hook_result after_hook_results.accept(formatter) @done = true self @@ -1046,7 +1048,7 @@ def accept(formatter) private :node end - class NodeCollection + class HookResultCollection def initialize @children = [] end @@ -1055,6 +1057,14 @@ def accept(formatter) @children.each { |child| child.accept(formatter) } end + def send_output_to(formatter) + @children.each { |child| child.send_output_to(formatter) } + end + + def describe_exception_to(formatter) + @children.each { |child| child.describe_exception_to(formatter) } + end + def <<(child) @children << child end @@ -1077,13 +1087,25 @@ def initialize(result, messages, embeddings) end def accept(formatter) + unless @already_accepted + send_output_to(formatter) + describe_exception_to(formatter) + end + self + end + + def send_output_to(formatter) unless @already_accepted @messages.each { |message| formatter.puts(message) } @embeddings.each { |embedding| embedding.send_to_formatter(formatter) } + end + end + + def describe_exception_to(formatter) + unless @already_accepted @result.describe_exception_to(formatter) @already_accepted = true end - self end end diff --git a/spec/cucumber/formatter/pretty_spec.rb b/spec/cucumber/formatter/pretty_spec.rb index adcdd35e92..4dcb846ad9 100644 --- a/spec/cucumber/formatter/pretty_spec.rb +++ b/spec/cucumber/formatter/pretty_spec.rb @@ -263,6 +263,54 @@ module Formatter """ bar """ +OUTPUT + end + end + + describe "with a output from hooks" do + define_feature <<-FEATURE + Feature: + Scenario: + Given this step passes + Scenario Outline: + Given this step + Examples: + | status | + | passes | + FEATURE + + define_steps do + Before do + puts "Before hook" + end + AfterStep do + puts "AfterStep hook" + end + After do + puts "After hook" + end + Given(/^this step passes$/) {} + end + + it "displays hook output appropriately " do + expect( @out.string ).to include < + + Examples: + | status | + | passes | Before hook, AfterStep hook, After hook + +2 scenarios (2 passed) +2 steps (2 passed) OUTPUT end end