diff --git a/lib/cucumber/reports/legacy_formatter.rb b/lib/cucumber/reports/legacy_formatter.rb index 2be45c3f79..0ec4c60815 100644 --- a/lib/cucumber/reports/legacy_formatter.rb +++ b/lib/cucumber/reports/legacy_formatter.rb @@ -223,12 +223,14 @@ def after_test_case(*args) end def before_hook(location, result) - @before_hook_results << Legacy::Ast::BeforeHookResult.new(LegacyResultBuilder.new(result)) + @before_hook_results << Legacy::Ast::HookResult.new(LegacyResultBuilder.new(result)) end def after_hook(location, result) - return unless @child - @child.after_hook LegacyResultBuilder.new(result) + # if the scenario has no steps, we can hit this before we've created the scenario printer + # ideally we should call switch_step_container in before_step_step + switch_step_container if !@child + @child.after_hook Legacy::Ast::HookResult.new(LegacyResultBuilder.new(result)) end def after_step_hook(hook, result) @@ -378,6 +380,27 @@ def indented(nasty_old_conflation_of_name_and_description) end + module PrintsAfterHooks + def after_hook_results + @after_hook_results ||= Legacy::Ast::NodeCollection.new + end + + def after_hook(result) + after_hook_results << result + end + end + + # Basic printer used by default + class AfterHookPrinter + include Cucumber.initializer(:formatter) + + include PrintsAfterHooks + + def after + after_hook_results.accept(formatter) + end + end + BackgroundPrinter = Struct.new(:formatter, :runtime, :node, :before_hook_results) do def before @@ -439,6 +462,7 @@ def after_test_case(*);end end ScenarioPrinter = Struct.new(:formatter, :runtime, :node, :before_hook_results) do + include PrintsAfterHooks def before formatter.before_feature_element(node) @@ -454,10 +478,6 @@ def step_invocation(step_invocation, source) @last_step_result = source.step_result end - def after_hook(result) - @after_hook_result = result - end - def after_step_hook(result) result.describe_exception_to formatter end @@ -472,7 +492,7 @@ def after # TODO - the last step result might not accurately reflect the # overall scenario result. scenario = last_step_result.scenario(node.name, node.location) - @after_hook_result.describe_exception_to(formatter) if @after_hook_result + after_hook_results.accept(formatter) formatter.after_feature_element(scenario) @done = true self @@ -526,10 +546,6 @@ def before self end - def after_hook(result) - @child.after_hook(result) - end - def step_invocation(step_invocation, source) node, result = source.step, source.step_result @last_step_result = result @@ -701,9 +717,7 @@ def char_length_of(cell) end class TableRowPrinterBase < Struct.new(:formatter, :runtime, :node, :before_hook_results) - def after_hook(result) - @after_hook_result = result - end + include PrintsAfterHooks def after_step_hook(result) @after_step_hook_result = result @@ -772,7 +786,7 @@ def after end formatter.after_table_row(legacy_table_row) @after_step_hook_result.describe_exception_to formatter if @after_step_hook_result - @after_hook_result.describe_exception_to(formatter) if @after_hook_result + after_hook_results.accept(formatter) @done = true self end @@ -807,7 +821,7 @@ def after return if @done @child.after if @child @after_step_hook_result.describe_exception_to formatter if @after_step_hook_result - @after_hook_result.describe_exception_to(formatter) if @after_hook_result + after_hook_results.accept(formatter) @done = true self end @@ -1036,7 +1050,7 @@ def accept(formatter) end end - class BeforeHookResult + class HookResult def initialize(result) @result = result @already_accepted = false diff --git a/spec/cucumber/reports/legacy_formatter_spec.rb b/spec/cucumber/reports/legacy_formatter_spec.rb index beb1a58faa..c304be90d1 100644 --- a/spec/cucumber/reports/legacy_formatter_spec.rb +++ b/spec/cucumber/reports/legacy_formatter_spec.rb @@ -1729,6 +1729,75 @@ module Cucumber ]) end end + + context 'with exception in the first of several after hooks' do + it 'prints the exception after the steps' do + define_steps do + After { raise 'an exception' } + After { } + end + execute_gherkin do + feature do + scenario do + step 'passing' + end + end + end + + expect( formatter.messages ).to eq([ + :before_features, + :before_feature, + :before_tags, + :after_tags, + :feature_name, + :before_feature_element, + :before_tags, + :after_tags, + :scenario_name, + :before_steps, + :before_step, + :before_step_result, + :step_name, + :after_step_result, + :after_step, + :after_steps, + :exception, + :after_feature_element, + :after_feature, + :after_features + ]) + end + end + + context 'with an exception in an after hook but no steps' do + it 'prints the exception after the steps' do + define_steps do + After { fail } + end + execute_gherkin do + feature do + scenario do + end + end + end + + expect( formatter.messages ).to eq([ + :before_features, + :before_feature, + :before_tags, + :after_tags, + :feature_name, + :before_feature_element, + :before_tags, + :after_tags, + :scenario_name, + :exception, + :after_feature_element, + :after_feature, + :after_features + ]) + end + end end it 'passes an object responding to failed? with the after_feature_element message' do