From 20e2fef9bba12eb5626f7200c9a4e866c4cf04d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Rasmusson?= Date: Sat, 30 May 2015 16:06:37 +0200 Subject: [PATCH 1/2] Add specs for the Progress Formatter when hooks are used. --- spec/cucumber/formatter/progress_spec.rb | 86 +++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/spec/cucumber/formatter/progress_spec.rb b/spec/cucumber/formatter/progress_spec.rb index 4d674c0c42..b29e915751 100644 --- a/spec/cucumber/formatter/progress_spec.rb +++ b/spec/cucumber/formatter/progress_spec.rb @@ -12,7 +12,7 @@ module Formatter before(:each) do Cucumber::Term::ANSIColor.coloring = false @out = StringIO.new - @formatter = Progress.new(runtime, @out, {}) + @formatter = Progress.new(runtime, @out, Cucumber::Cli::Options.new) end describe "given a single feature" do @@ -79,6 +79,90 @@ module Formatter end end + + describe "with hooks" do + + describe "all hook passes" do + define_feature <<-FEATURE + Feature: + Scenario: + Given this step passes + FEATURE + + define_steps do + Before do + end + AfterStep do + end + After do + end + Given(/^this step passes$/) {} + end + + it "only steps generate output" do + lines = <<-OUTPUT + . + 1 scenario (1 passed) + 1 step (1 passed) + OUTPUT + lines.split("\n").each do |line| + expect(@out.string).to include line.strip + end + end + end + + describe "with a failing before hook" do + define_feature <<-FEATURE + Feature: + Scenario: + Given this step passes + FEATURE + + define_steps do + Before do + fail "hook failed" + end + Given(/^this step passes$/) {} + end + + it "the failing hook generate output" do + lines = <<-OUTPUT + F- + 1 scenario (1 failed) + 1 step (1 skipped) + OUTPUT + lines.split("\n").each do |line| + expect(@out.string).to include line.strip + end + end + end + + describe "with a failing after hook" do + define_feature <<-FEATURE + Feature: + Scenario: + Given this step passes + FEATURE + + define_steps do + After do + fail "hook failed" + end + Given(/^this step passes$/) {} + end + + it "the failing hook generate output" do + lines = <<-OUTPUT + .F + 1 scenario (1 failed) + 1 step (1 passed) + OUTPUT + lines.split("\n").each do |line| + expect(@out.string).to include line.strip + end + end + end + end end end end From 618179cba48a7017568b97a98bfb8ade82eb1ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Rasmusson?= Date: Sat, 30 May 2015 19:00:18 +0200 Subject: [PATCH 2/2] Rewrite the Progress, Usage, Stepdefs formatters to the new api Also some deficiencies of the Progress formatter are fixed, both that outline steps were printed as skipped, and some cases where the printed progress characters did not match the step count in the summary. --- .../defining_steps/printing_messages.feature | 8 +- .../docs/formatters/usage_formatter.feature | 4 +- features/docs/gherkin/outlines.feature | 3 +- lib/cucumber/formatter/console.rb | 4 +- lib/cucumber/formatter/duration_extractor.rb | 28 +++++++ .../formatter/legacy_api/runtime_facade.rb | 4 + lib/cucumber/formatter/pretty.rb | 3 +- lib/cucumber/formatter/progress.rb | 74 ++++++------------- lib/cucumber/formatter/usage.rb | 38 ++++------ 9 files changed, 81 insertions(+), 85 deletions(-) create mode 100644 lib/cucumber/formatter/duration_extractor.rb diff --git a/features/docs/defining_steps/printing_messages.feature b/features/docs/defining_steps/printing_messages.feature index 3354963347..04d2061463 100644 --- a/features/docs/defining_steps/printing_messages.feature +++ b/features/docs/defining_steps/printing_messages.feature @@ -137,12 +137,12 @@ Feature: Pretty formatter - Printing messages Announce Me - ..-UUUUUU + ..UUU Announce with fail - F-- + F- Line: 1: anno1 - FFF + F Line: 2: anno2 - ... + . """ diff --git a/features/docs/formatters/usage_formatter.feature b/features/docs/formatters/usage_formatter.feature index 76330401af..ed66501b0e 100644 --- a/features/docs/formatters/usage_formatter.feature +++ b/features/docs/formatters/usage_formatter.feature @@ -61,7 +61,7 @@ Feature: Usage formatter When I run `cucumber -x -f usage --dry-run` Then it should pass with exactly: """ - ---------- + ----------- /A/ # features/step_definitions/steps.rb:1 Given A # features/f.feature:3 @@ -87,7 +87,7 @@ Feature: Usage formatter When I run `cucumber -f stepdefs --dry-run` Then it should pass with exactly: """ - -------- + ----------- /A/ # features/step_definitions/steps.rb:1 /B/ # features/step_definitions/steps.rb:2 diff --git a/features/docs/gherkin/outlines.feature b/features/docs/gherkin/outlines.feature index 9b83f570ed..cd78d8e8e9 100644 --- a/features/docs/gherkin/outlines.feature +++ b/features/docs/gherkin/outlines.feature @@ -138,7 +138,7 @@ Feature: Scenario outlines When I run `cucumber -q --format progress features/outline_sample.feature` Then it should fail with exactly: """ - --UU..FF.. + U-..F-.. (::) failed steps (::) @@ -155,4 +155,3 @@ Feature: Scenario outlines 0m0.012s """ - diff --git a/lib/cucumber/formatter/console.rb b/lib/cucumber/formatter/console.rb index f32497b0d8..cfef38d962 100644 --- a/lib/cucumber/formatter/console.rb +++ b/lib/cucumber/formatter/console.rb @@ -76,7 +76,7 @@ def print_elements(elements, status, kind) end end - def print_stats(features, options) + def print_stats(duration, options) failures = collect_failing_scenarios(runtime) if !failures.empty? print_failing_scenarios(failures, options.custom_profiles, options[:source]) @@ -85,7 +85,7 @@ def print_stats(features, options) @io.puts scenario_summary(runtime) {|status_count, status| format_string(status_count, status)} @io.puts step_summary(runtime) {|status_count, status| format_string(status_count, status)} - @io.puts(format_duration(features.duration)) if features && features.duration + @io.puts(format_duration(duration)) if duration if runtime.configuration.randomize? @io.puts diff --git a/lib/cucumber/formatter/duration_extractor.rb b/lib/cucumber/formatter/duration_extractor.rb new file mode 100644 index 0000000000..cbabe132a7 --- /dev/null +++ b/lib/cucumber/formatter/duration_extractor.rb @@ -0,0 +1,28 @@ +module Cucumber + module Formatter + + class DurationExtractor + attr_reader :result_duration + def initialize(result) + @result_duration = 0 + result.describe_to(self) + end + + def passed(*) end + + def failed(*) end + + def undefined(*) end + + def skipped(*) end + + def pending(*) end + + def exception(*) end + + def duration(duration, *) + duration.tap { |duration| @result_duration = duration.nanoseconds / 10**9.0 } + end + end + end +end diff --git a/lib/cucumber/formatter/legacy_api/runtime_facade.rb b/lib/cucumber/formatter/legacy_api/runtime_facade.rb index 9a88e69891..079d0533c2 100644 --- a/lib/cucumber/formatter/legacy_api/runtime_facade.rb +++ b/lib/cucumber/formatter/legacy_api/runtime_facade.rb @@ -23,6 +23,10 @@ def scenarios(status = nil) def steps(status = nil) results.steps(status) end + + def step_match(step_name, name_to_report=nil) + support_code.step_match(step_name, name_to_report) + end end end diff --git a/lib/cucumber/formatter/pretty.rb b/lib/cucumber/formatter/pretty.rb index 510541d7a1..a681f5504b 100644 --- a/lib/cucumber/formatter/pretty.rb +++ b/lib/cucumber/formatter/pretty.rb @@ -240,7 +240,8 @@ def cell_prefix(status) end def print_summary(features) - print_stats(features, @options) + duration = features ? features.duration : nil + print_stats(duration, @options) print_snippets(@options) print_passing_wip(@options) end diff --git a/lib/cucumber/formatter/progress.rb b/lib/cucumber/formatter/progress.rb index 51e1aa7167..0b29fbdc47 100644 --- a/lib/cucumber/formatter/progress.rb +++ b/lib/cucumber/formatter/progress.rb @@ -1,5 +1,6 @@ require 'cucumber/formatter/console' require 'cucumber/formatter/io' +require 'cucumber/formatter/duration_extractor' module Cucumber module Formatter @@ -13,73 +14,42 @@ def initialize(runtime, path_or_io, options) @runtime, @io, @options = runtime, ensure_io(path_or_io, "progress"), options @previous_step_keyword = nil @snippets_input = [] + @total_duration = 0 end - def before_features(features) - print_profile_information - end - - def after_features(features) - @io.puts - @io.puts - print_summary(features) - end - - def before_feature_element(*args) - @exception_raised = false - end - - def after_feature_element(*args) - progress(:failed) if (defined? @exception_raised) and (@exception_raised) - @exception_raised = false - end - - def before_steps(*args) - progress(:failed) if (defined? @exception_raised) and (@exception_raised) - @exception_raised = false - end - - def after_steps(*args) - @exception_raised = false - end - - def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line) - progress(status) - @status = status - end - - def before_outline_table(outline_table) - @outline_table = outline_table + def before_test_case(_test_case) + unless @profile_information_printed + print_profile_information + @profile_information_printed = true + end + @previous_step_keyword = nil end - def after_outline_table(outline_table) - @outline_table = nil + def after_test_step(test_step, result) + progress(result.to_sym) if !hook?(test_step.source.last) || result.failed? + collect_snippet_data(test_step, result) unless hook?(test_step.source.last) end - def table_cell_value(value, status) - return unless @outline_table - status ||= @status - progress(status) unless table_header_cell?(status) + def after_test_case(_test_case, result) + @total_duration += DurationExtractor.new(result).result_duration end - def exception(*args) - @exception_raised = true + def done + @io.puts + @io.puts + print_summary end - def before_test_case(test_case) - @previous_step_keyword = nil - end + private - def after_test_step(test_step, result) - collect_snippet_data(test_step, result) + def hook?(step) + ['Before hook', 'After hook', 'AfterStep hook'].include? step.name end - private - - def print_summary(features) + def print_summary print_steps(:pending) print_steps(:failed) - print_stats(features, @options) + print_stats(@total_duration, @options) print_snippets(@options) print_passing_wip(@options) end diff --git a/lib/cucumber/formatter/usage.rb b/lib/cucumber/formatter/usage.rb index 45324e5853..2158ee7331 100644 --- a/lib/cucumber/formatter/usage.rb +++ b/lib/cucumber/formatter/usage.rb @@ -14,39 +14,33 @@ def initialize(runtime, path_or_io, options) @runtime = runtime @io = ensure_io(path_or_io, "usage") @options = options - @stepdef_to_match = Hash.new{|h,stepdef_key| h[stepdef_key] = []} + @stepdef_to_match = Hash.new { |h, stepdef_key| h[stepdef_key] = [] } + @total_duration = 0 end - def before_features(features) - print_profile_information - end - - def before_step(step) - @step = step - @start_time = Time.now - end + def after_test_step(test_step, result) + return if hook?(test_step.source.last) - def before_step_result(*args) - @duration = Time.now - @start_time - end - - def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line) + step_match = @runtime.step_match(test_step.source.last.name) step_definition = step_match.step_definition - unless step_definition.nil? # nil if it's from a scenario outline - stepdef_key = StepDefKey.new(step_definition.regexp_source, step_definition.file_colon_line) + stepdef_key = StepDefKey.new(step_definition.regexp_source, step_definition.file_colon_line) + unless @stepdef_to_match[stepdef_key].map { |key| key[:file_colon_line] }.include? test_step.location + duration = DurationExtractor.new(result).result_duration @stepdef_to_match[stepdef_key] << { - :keyword => keyword, - :step_match => step_match, - :status => status, - :file_colon_line => @step.file_colon_line, - :duration => @duration + keyword: test_step.source.last.keyword, + step_match: step_match, + status: result.to_sym, + file_colon_line: test_step.location, + duration: duration } end super end - def print_summary(features) + private + + def print_summary add_unused_stepdefs aggregate_info