From 15184babe354142a249f56d23a35a20d16d781cc Mon Sep 17 00:00:00 2001 From: Matt Wynne Date: Fri, 8 Jul 2016 21:55:24 +0100 Subject: [PATCH 1/4] First pass at spec formatter This formatter provides a high-level summary of the scenarios that were run. It's also A LOT simpler than the pretty formatter, and so more reliable for testing with. I'm thinking we can use this to build out alternative re-usable pieces (like the summary) that need to be re-written anyway. Work still to do: - unit tests - acceptance test for scenario outlines - finish the summary - colours? - some animation as steps run? --- .../docs/formatters/spec_formatter.feature | 29 +++++++++++ lib/cucumber/cli/options.rb | 3 +- lib/cucumber/formatter/spec.rb | 52 +++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 features/docs/formatters/spec_formatter.feature create mode 100644 lib/cucumber/formatter/spec.rb diff --git a/features/docs/formatters/spec_formatter.feature b/features/docs/formatters/spec_formatter.feature new file mode 100644 index 0000000000..4b4f648010 --- /dev/null +++ b/features/docs/formatters/spec_formatter.feature @@ -0,0 +1,29 @@ +Feature: Spec formatter + + This formatter mimic the output from tools like RSpec or Mocha, giving an + overview of each feature and scenario, omitting the steps. + + Background: + Given the standard step definitions + + Scenario: A couple of scenarios + Given a file named "features/test.feature" with: + """ + Feature: Test + Scenario: Passing + Given this step passes + + Scenario: Failing + Given this step fails + """ + When I run `cucumber --format spec` + Then it should fail with exactly: + """ + Test + Passing ✓ + Failing ✗ + + 2 scenarios (1 passed, 1 failed) + 2 steps (1 passed, 1 failed) + """ + diff --git a/lib/cucumber/cli/options.rb b/lib/cucumber/cli/options.rb index a41c615163..263a07e54f 100644 --- a/lib/cucumber/cli/options.rb +++ b/lib/cucumber/cli/options.rb @@ -23,7 +23,8 @@ class Options 'junit' => ['Cucumber::Formatter::Junit', 'Generates a report similar to Ant+JUnit.'], 'json' => ['Cucumber::Formatter::Json', 'Prints the feature as JSON'], 'json_pretty' => ['Cucumber::Formatter::JsonPretty', 'Prints the feature as prettified JSON'], - 'debug' => ['Cucumber::Formatter::Debug', 'For developing formatters - prints the calls made to the listeners.'] + 'debug' => ['Cucumber::Formatter::Debug', 'For developing formatters - prints the calls made to the listeners.'], + 'spec' => ['Cucumber::Formatter::Spec', 'Summary output of feature and scenarios'] } max = BUILTIN_FORMATS.keys.map{|s| s.length}.max FORMAT_HELP_MSG = ["Use --format rerun --out rerun.txt to write out failing", diff --git a/lib/cucumber/formatter/spec.rb b/lib/cucumber/formatter/spec.rb new file mode 100644 index 0000000000..968feff0c1 --- /dev/null +++ b/lib/cucumber/formatter/spec.rb @@ -0,0 +1,52 @@ +require 'cucumber/formatter/io' +require 'cucumber/core/test/result' + +module Cucumber + module Formatter + class Spec + include Io + + def initialize(config) + @config, @io = config, ensure_io(config.out_stream) + @test_case_summary = Core::Test::Result::Summary.new + + @config.on_event :test_case_starting do |event| + print_feature event.test_case + print_test_case event.test_case + end + + @config.on_event :test_case_finished do |event| + print_result event.result + event.result.describe_to @test_case_summary + end + + @config.on_event :test_run_finished do |event| + print_scenario_summary + end + end + + private + + def print_feature(test_case) + feature = test_case.feature + return if @current_feature == feature + @io.puts feature + @current_feature = feature + end + + def print_test_case(test_case) + @io.print " #{test_case.name} " + end + + def print_result(result) + @io.puts result + end + + def print_scenario_summary + @io.puts + @io.puts "#{@test_case_summary.total} scenarios" + end + end + end +end + From 7223737f332005e6ed4321fbb4572ea437e7d529 Mon Sep 17 00:00:00 2001 From: Matt Wynne Date: Wed, 20 Jul 2016 21:38:34 +0100 Subject: [PATCH 2/4] Add summary output and make the scenario pass Still to do: - unit tests - useful output when tests fail --- .../docs/formatters/spec_formatter.feature | 5 ++- lib/cucumber/formatter/spec.rb | 38 ++++++++++++++++++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/features/docs/formatters/spec_formatter.feature b/features/docs/formatters/spec_formatter.feature index 4b4f648010..d2e3ca5bcc 100644 --- a/features/docs/formatters/spec_formatter.feature +++ b/features/docs/formatters/spec_formatter.feature @@ -1,7 +1,7 @@ Feature: Spec formatter - This formatter mimic the output from tools like RSpec or Mocha, giving an - overview of each feature and scenario, omitting the steps. + This formatter mimics the output from tools like RSpec or Mocha, giving an + overview of each feature and scenario but omitting the steps. Background: Given the standard step definitions @@ -25,5 +25,6 @@ Feature: Spec formatter 2 scenarios (1 passed, 1 failed) 2 steps (1 passed, 1 failed) + """ diff --git a/lib/cucumber/formatter/spec.rb b/lib/cucumber/formatter/spec.rb index 968feff0c1..d40c4ee747 100644 --- a/lib/cucumber/formatter/spec.rb +++ b/lib/cucumber/formatter/spec.rb @@ -5,10 +5,12 @@ module Cucumber module Formatter class Spec include Io + include Console def initialize(config) @config, @io = config, ensure_io(config.out_stream) @test_case_summary = Core::Test::Result::Summary.new + @test_step_summary = Core::Test::Result::Summary.new @config.on_event :test_case_starting do |event| print_feature event.test_case @@ -20,6 +22,10 @@ def initialize(config) event.result.describe_to @test_case_summary end + @config.on_event :test_step_finished do |event| + event.result.describe_to @test_step_summary if from_gherkin?(event.test_step) + end + @config.on_event :test_run_finished do |event| print_scenario_summary end @@ -27,9 +33,14 @@ def initialize(config) private + def from_gherkin?(test_step) + test_step.source.last.location.file.match(/\.feature$/) + end + def print_feature(test_case) feature = test_case.feature return if @current_feature == feature + @io.puts unless @current_feature.nil? @io.puts feature @current_feature = feature end @@ -39,12 +50,35 @@ def print_test_case(test_case) end def print_result(result) - @io.puts result + @io.puts format_string(result, result.to_sym) end def print_scenario_summary @io.puts - @io.puts "#{@test_case_summary.total} scenarios" + @io.puts [scenario_count, status_counts(@test_case_summary)].join(" ") + @io.puts [step_count, status_counts(@test_step_summary)].join(" ") + end + + def scenario_count + count = @test_case_summary.total + "#{count} scenario" + (count == 1 ? "" : "s") + end + + def step_count + count = @test_step_summary.total + "#{count} step" + (count == 1 ? "" : "s") + end + + def status_counts(summary) + counts = [:passed, :failed, :undefined, :pending].map { |status| + count = summary.total(status) + [status, count] + }.select { |status, count| + count > 0 + }.map { |status, count| + format_string("#{count} #{status}", status) + } + "(#{counts.join(", ")})" if counts.any? end end end From 44622930b47afd307e99fb85ec2f0bf26e8a0313 Mon Sep 17 00:00:00 2001 From: Matt Wynne Date: Wed, 20 Jul 2016 22:23:37 +0100 Subject: [PATCH 3/4] Extract a Formatter::ConsoleCounts and use it everywhere --- ...tter.feature => summary_formatter.feature} | 6 +- lib/cucumber/cli/options.rb | 2 +- lib/cucumber/formatter/console.rb | 12 +-- lib/cucumber/formatter/console_counts.rb | 57 ++++++++++++ lib/cucumber/formatter/pretty.rb | 8 +- lib/cucumber/formatter/progress.rb | 6 +- lib/cucumber/formatter/spec.rb | 86 ------------------- lib/cucumber/formatter/summary.rb | 69 ++++++++------- lib/cucumber/multiline_argument/data_table.rb | 3 +- .../cucumber/formatter/console_counts_spec.rb | 14 +++ 10 files changed, 126 insertions(+), 137 deletions(-) rename features/docs/formatters/{spec_formatter.feature => summary_formatter.feature} (83%) create mode 100644 lib/cucumber/formatter/console_counts.rb delete mode 100644 lib/cucumber/formatter/spec.rb create mode 100644 spec/cucumber/formatter/console_counts_spec.rb diff --git a/features/docs/formatters/spec_formatter.feature b/features/docs/formatters/summary_formatter.feature similarity index 83% rename from features/docs/formatters/spec_formatter.feature rename to features/docs/formatters/summary_formatter.feature index d2e3ca5bcc..63a73faefb 100644 --- a/features/docs/formatters/spec_formatter.feature +++ b/features/docs/formatters/summary_formatter.feature @@ -16,15 +16,15 @@ Feature: Spec formatter Scenario: Failing Given this step fails """ - When I run `cucumber --format spec` + When I run `cucumber --format summary` Then it should fail with exactly: """ Test Passing ✓ Failing ✗ - 2 scenarios (1 passed, 1 failed) - 2 steps (1 passed, 1 failed) + 2 scenarios (1 failed, 1 passed) + 2 steps (1 failed, 1 passed) """ diff --git a/lib/cucumber/cli/options.rb b/lib/cucumber/cli/options.rb index 263a07e54f..f1968de99f 100644 --- a/lib/cucumber/cli/options.rb +++ b/lib/cucumber/cli/options.rb @@ -24,7 +24,7 @@ class Options 'json' => ['Cucumber::Formatter::Json', 'Prints the feature as JSON'], 'json_pretty' => ['Cucumber::Formatter::JsonPretty', 'Prints the feature as prettified JSON'], 'debug' => ['Cucumber::Formatter::Debug', 'For developing formatters - prints the calls made to the listeners.'], - 'spec' => ['Cucumber::Formatter::Spec', 'Summary output of feature and scenarios'] + 'summary' => ['Cucumber::Formatter::Summary', 'Summary output of feature and scenarios'] } max = BUILTIN_FORMATS.keys.map{|s| s.length}.max FORMAT_HELP_MSG = ["Use --format rerun --out rerun.txt to write out failing", diff --git a/lib/cucumber/formatter/console.rb b/lib/cucumber/formatter/console.rb index 240722808d..68d3e2c355 100644 --- a/lib/cucumber/formatter/console.rb +++ b/lib/cucumber/formatter/console.rb @@ -1,6 +1,5 @@ require 'cucumber/formatter/ansicolor' require 'cucumber/formatter/duration' -require 'cucumber/formatter/summary' require 'cucumber/gherkin/i18n' module Cucumber @@ -29,7 +28,6 @@ module Formatter module Console extend ANSIColor include Duration - include Summary def format_step(keyword, step_match, status, source_indent) comment = if source_indent @@ -80,19 +78,13 @@ def print_element_messages(element_messages, status, kind) end end - def print_stats(features, options) - duration = features ? features.duration : nil - print_statistics(duration, options) - end - - def print_statistics(duration, options) + def print_statistics(duration, options, counts) failures = collect_failing_scenarios(runtime) if !failures.empty? print_failing_scenarios(failures, options.custom_profiles, options[:source]) end - @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 counts.to_s @io.puts(format_duration(duration)) if duration && options[:duration] if runtime.configuration.randomize? diff --git a/lib/cucumber/formatter/console_counts.rb b/lib/cucumber/formatter/console_counts.rb new file mode 100644 index 0000000000..cd96da69dd --- /dev/null +++ b/lib/cucumber/formatter/console_counts.rb @@ -0,0 +1,57 @@ +require 'cucumber/formatter/console' + +module Cucumber + module Formatter + class ConsoleCounts + include Console + + def initialize(config) + @test_case_summary = Core::Test::Result::Summary.new + @test_step_summary = Core::Test::Result::Summary.new + + config.on_event :test_case_finished do |event| + event.result.describe_to @test_case_summary + end + + config.on_event :test_step_finished do |event| + event.result.describe_to @test_step_summary if from_gherkin?(event.test_step) + end + end + + def to_s + [ + [scenario_count, status_counts(@test_case_summary)].compact.join(" "), + [step_count, status_counts(@test_step_summary)].compact.join(" ") + ].join("\n") + end + + private + + def from_gherkin?(test_step) + test_step.source.last.location.file.match(/\.feature$/) + end + + def scenario_count + count = @test_case_summary.total + "#{count} scenario" + (count == 1 ? "" : "s") + end + + def step_count + count = @test_step_summary.total + "#{count} step" + (count == 1 ? "" : "s") + end + + def status_counts(summary) + counts = [:failed, :skipped, :undefined, :pending, :passed].map { |status| + count = summary.total(status) + [status, count] + }.select { |status, count| + count > 0 + }.map { |status, count| + format_string("#{count} #{status}", status) + } + "(#{counts.join(", ")})" if counts.any? + end + end + end +end diff --git a/lib/cucumber/formatter/pretty.rb b/lib/cucumber/formatter/pretty.rb index af40ebed9b..62810c8b82 100644 --- a/lib/cucumber/formatter/pretty.rb +++ b/lib/cucumber/formatter/pretty.rb @@ -2,6 +2,7 @@ require 'cucumber/formatter/console' require 'cucumber/formatter/io' require 'cucumber/gherkin/formatter/escaping' +require 'cucumber/formatter/console_counts' module Cucumber module Formatter @@ -28,6 +29,7 @@ def initialize(runtime, path_or_io, options) @delayed_messages = [] @previous_step_keyword = nil @snippets_input = [] + @counts = ConsoleCounts.new(runtime.configuration) end def before_features(features) @@ -35,7 +37,7 @@ def before_features(features) end def after_features(features) - print_summary(features) + print_summary(features, @counts) end def before_feature(feature) @@ -237,8 +239,8 @@ def cell_prefix(status) @prefixes[status] end - def print_summary(features) - print_stats(features, @options) + def print_summary(features, counts) + print_statistics(features.duration, @options, counts) print_snippets(@options) print_passing_wip(@options) end diff --git a/lib/cucumber/formatter/progress.rb b/lib/cucumber/formatter/progress.rb index ac0763bf61..eb88c93e2b 100644 --- a/lib/cucumber/formatter/progress.rb +++ b/lib/cucumber/formatter/progress.rb @@ -1,6 +1,7 @@ require 'cucumber/core/report/summary' require 'cucumber/formatter/backtrace_filter' require 'cucumber/formatter/console' +require 'cucumber/formatter/console_counts' require 'cucumber/formatter/io' require 'cucumber/formatter/duration_extractor' require 'cucumber/formatter/hook_query_visitor' @@ -25,6 +26,7 @@ def initialize(config) @failed_results = [] @failed_test_cases = [] @passed_test_cases = [] + @counts = ConsoleCounts.new(config) config.on_event :step_match, &method(:on_step_match) config.on_event :test_case_starting, &method(:on_test_case_starting) config.on_event :test_step_finished, &method(:on_test_step_finished) @@ -96,9 +98,7 @@ def print_statistics_local(duration) end scenarios_proc = lambda{|status| summary.test_cases.total(status)} - @io.puts dump_summary_counts(summary.test_cases.total, scenarios_proc, "scenario") {|status_count, status| format_string(status_count, status)} - steps_proc = lambda{|status| summary.test_steps.total(status)} - @io.puts dump_summary_counts(summary.test_steps.total, steps_proc, "step") {|status_count, status| format_string(status_count, status)} + @io.puts @counts.to_s @io.puts(format_duration(duration)) if duration && config.duration? if config.randomize? diff --git a/lib/cucumber/formatter/spec.rb b/lib/cucumber/formatter/spec.rb deleted file mode 100644 index d40c4ee747..0000000000 --- a/lib/cucumber/formatter/spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -require 'cucumber/formatter/io' -require 'cucumber/core/test/result' - -module Cucumber - module Formatter - class Spec - include Io - include Console - - def initialize(config) - @config, @io = config, ensure_io(config.out_stream) - @test_case_summary = Core::Test::Result::Summary.new - @test_step_summary = Core::Test::Result::Summary.new - - @config.on_event :test_case_starting do |event| - print_feature event.test_case - print_test_case event.test_case - end - - @config.on_event :test_case_finished do |event| - print_result event.result - event.result.describe_to @test_case_summary - end - - @config.on_event :test_step_finished do |event| - event.result.describe_to @test_step_summary if from_gherkin?(event.test_step) - end - - @config.on_event :test_run_finished do |event| - print_scenario_summary - end - end - - private - - def from_gherkin?(test_step) - test_step.source.last.location.file.match(/\.feature$/) - end - - def print_feature(test_case) - feature = test_case.feature - return if @current_feature == feature - @io.puts unless @current_feature.nil? - @io.puts feature - @current_feature = feature - end - - def print_test_case(test_case) - @io.print " #{test_case.name} " - end - - def print_result(result) - @io.puts format_string(result, result.to_sym) - end - - def print_scenario_summary - @io.puts - @io.puts [scenario_count, status_counts(@test_case_summary)].join(" ") - @io.puts [step_count, status_counts(@test_step_summary)].join(" ") - end - - def scenario_count - count = @test_case_summary.total - "#{count} scenario" + (count == 1 ? "" : "s") - end - - def step_count - count = @test_step_summary.total - "#{count} step" + (count == 1 ? "" : "s") - end - - def status_counts(summary) - counts = [:passed, :failed, :undefined, :pending].map { |status| - count = summary.total(status) - [status, count] - }.select { |status, count| - count > 0 - }.map { |status, count| - format_string("#{count} #{status}", status) - } - "(#{counts.join(", ")})" if counts.any? - end - end - end -end - diff --git a/lib/cucumber/formatter/summary.rb b/lib/cucumber/formatter/summary.rb index 33d633d78b..b0a65a46ca 100644 --- a/lib/cucumber/formatter/summary.rb +++ b/lib/cucumber/formatter/summary.rb @@ -1,48 +1,57 @@ +require 'cucumber/formatter/io' +require 'cucumber/formatter/console' +require 'cucumber/formatter/console_counts' +require 'cucumber/core/test/result' + module Cucumber module Formatter - module Summary - def scenario_summary(runtime, &block) - scenarios_proc = lambda{|status| elements = runtime.scenarios(status)} - scenario_count_proc = element_count_proc(scenarios_proc) - dump_summary_counts(runtime.scenarios.length, scenario_count_proc, "scenario", &block) - end + # Summary formatter, outputting only feature / scenario titles + class Summary + include Io + include Console - def step_summary(runtime, &block) - steps_proc = lambda{|status| runtime.steps(status)} - step_count_proc = element_count_proc(steps_proc) - dump_summary_counts(runtime.steps.length, step_count_proc, "step", &block) - end + def initialize(config) + @config, @io = config, ensure_io(config.out_stream) + @counts = ConsoleCounts.new(@config) - def dump_summary_counts(total_count, status_proc, what, &block) - dump_count(total_count, what) + dump_status_counts(status_proc, &block) + @config.on_event :test_case_starting do |event| + print_feature event.test_case + print_test_case event.test_case + end + + @config.on_event :test_case_finished do |event| + print_result event.result + end + + @config.on_event :test_run_finished do |event| + print_counts + end end private - def element_count_proc(find_elements_proc) - lambda { |status| - elements = find_elements_proc.call(status) - elements.any? ? elements.length : 0 - } + def print_feature(test_case) + feature = test_case.feature + return if @current_feature == feature + @io.puts unless @current_feature.nil? + @io.puts feature + @current_feature = feature end - def dump_status_counts(element_count_proc) - counts = [:failed, :skipped, :undefined, :pending, :passed].map do |status| - count = element_count_proc.call(status) - count != 0 ? yield("#{count} #{status.to_s}", status) : nil - end.compact - if counts.any? - " (#{counts.join(', ')})" - else - "" - end + def print_test_case(test_case) + @io.print " #{test_case.name} " end - def dump_count(count, what, state=nil) - [count, state, "#{what}#{count == 1 ? '' : 's'}"].compact.join(" ") + def print_result(result) + @io.puts format_string(result, result.to_sym) end + def print_counts + @io.puts + @io.puts @counts.to_s + end end end end + diff --git a/lib/cucumber/multiline_argument/data_table.rb b/lib/cucumber/multiline_argument/data_table.rb index 27bb48b5ef..c4dca903b2 100644 --- a/lib/cucumber/multiline_argument/data_table.rb +++ b/lib/cucumber/multiline_argument/data_table.rb @@ -469,7 +469,8 @@ def to_s(options = {}) #:nodoc: c = Cucumber::Term::ANSIColor.coloring? Cucumber::Term::ANSIColor.coloring = options[:color] - formatter = Formatter::Pretty.new(nil, io, options) + runtime = Struct.new(:configuration).new(Configuration.new) + formatter = Formatter::Pretty.new(runtime, io, options) formatter.instance_variable_set('@indent', options[:indent]) Formatter::LegacyApi::Ast::MultilineArg.for(self).accept(Formatter::Fanout.new([formatter])) Cucumber::Term::ANSIColor.coloring = c diff --git a/spec/cucumber/formatter/console_counts_spec.rb b/spec/cucumber/formatter/console_counts_spec.rb new file mode 100644 index 0000000000..01029be277 --- /dev/null +++ b/spec/cucumber/formatter/console_counts_spec.rb @@ -0,0 +1,14 @@ +require 'cucumber/configuration' +require 'cucumber/formatter/console_counts' + +module Cucumber + module Formatter + describe ConsoleCounts do + it "works for zero" do + config = Configuration.new + counts = ConsoleCounts.new(config) + expect(counts.to_s).to eq "0 scenarios\n0 steps" + end + end + end +end From c3962f55a3a6ce1e95868f7e7fb8f1198c110a1b Mon Sep 17 00:00:00 2001 From: Matt Wynne Date: Wed, 20 Jul 2016 23:31:37 +0100 Subject: [PATCH 4/4] Use shared code for summary --- .../docs/formatters/summary_formatter.feature | 4 ++ lib/cucumber/formatter/console.rb | 36 ++++-------------- lib/cucumber/formatter/console_issues.rb | 37 +++++++++++++++++++ lib/cucumber/formatter/pretty.rb | 9 +++-- lib/cucumber/formatter/progress.rb | 24 ++---------- lib/cucumber/formatter/summary.rb | 12 +++--- 6 files changed, 63 insertions(+), 59 deletions(-) create mode 100644 lib/cucumber/formatter/console_issues.rb diff --git a/features/docs/formatters/summary_formatter.feature b/features/docs/formatters/summary_formatter.feature index 63a73faefb..f6ac1138ab 100644 --- a/features/docs/formatters/summary_formatter.feature +++ b/features/docs/formatters/summary_formatter.feature @@ -23,8 +23,12 @@ Feature: Spec formatter Passing ✓ Failing ✗ + Failing Scenarios: + cucumber features/test.feature:5 # Scenario: Failing + 2 scenarios (1 failed, 1 passed) 2 steps (1 failed, 1 passed) + 0m0.012s """ diff --git a/lib/cucumber/formatter/console.rb b/lib/cucumber/formatter/console.rb index 68d3e2c355..8d9c628e9b 100644 --- a/lib/cucumber/formatter/console.rb +++ b/lib/cucumber/formatter/console.rb @@ -78,45 +78,23 @@ def print_element_messages(element_messages, status, kind) end end - def print_statistics(duration, options, counts) - failures = collect_failing_scenarios(runtime) - if !failures.empty? - print_failing_scenarios(failures, options.custom_profiles, options[:source]) + def print_statistics(duration, config, counts, issues) + if issues.any? + @io.puts issues.to_s + @io.puts end @io.puts counts.to_s - @io.puts(format_duration(duration)) if duration && options[:duration] + @io.puts(format_duration(duration)) if duration && config.duration? - if runtime.configuration.randomize? + if config.randomize? @io.puts - @io.puts "Randomized with seed #{runtime.configuration.seed}" + @io.puts "Randomized with seed #{config.seed}" end @io.flush end - def collect_failing_scenarios(runtime) - # TODO: brittle - stop coupling to types - scenario_class = LegacyApi::Ast::Scenario - example_table_class = Core::Ast::ExamplesTable - - runtime.scenarios(:failed).select do |s| - [scenario_class, example_table_class].include?(s.class) - end.map do |s| - s.is_a?(example_table_class)? s.scenario_outline : s - end - end - - def print_failing_scenarios(failures, custom_profiles, given_source) - @io.puts format_string("Failing Scenarios:", :failed) - failures.each do |failure| - profiles_string = custom_profiles.empty? ? '' : (custom_profiles.map{|profile| "-p #{profile}" }).join(' ') + ' ' - source = given_source ? format_string(" # " + failure.name, :comment) : '' - @io.puts format_string("cucumber #{profiles_string}" + failure.location, :failed) + source - end - @io.puts - end - def print_exception(e, status, indent) string = exception_message_string(e, indent) @io.puts(format_string(string, status)) diff --git a/lib/cucumber/formatter/console_issues.rb b/lib/cucumber/formatter/console_issues.rb new file mode 100644 index 0000000000..be8ef7ba2f --- /dev/null +++ b/lib/cucumber/formatter/console_issues.rb @@ -0,0 +1,37 @@ +require 'cucumber/formatter/console' + +module Cucumber + module Formatter + class ConsoleIssues + include Console + + def initialize(config) + @failures = [] + @config = config + @config.on_event(:test_case_finished) do |event| + @failures << event.test_case if event.result.failed? + end + end + + def to_s + return if @failures.empty? + result = [ format_string("Failing Scenarios:", :failed) ] + @failures.map { |failure| + source = @config.source? ? format_string(" # #{failure.keyword}: #{failure.name}", :comment) : '' + format_string("cucumber #{profiles_string}" + failure.location, :failed) + source + } + result.join("\n") + end + + def any? + @failures.any? + end + + private + + def profiles_string + return if @config.custom_profiles.empty? + @config.custom_profiles.map { |profile| "-p #{profile}" }.join(' ') + ' ' + end + end + end +end diff --git a/lib/cucumber/formatter/pretty.rb b/lib/cucumber/formatter/pretty.rb index 62810c8b82..1cfe1a81cd 100644 --- a/lib/cucumber/formatter/pretty.rb +++ b/lib/cucumber/formatter/pretty.rb @@ -3,6 +3,7 @@ require 'cucumber/formatter/io' require 'cucumber/gherkin/formatter/escaping' require 'cucumber/formatter/console_counts' +require 'cucumber/formatter/console_issues' module Cucumber module Formatter @@ -23,6 +24,7 @@ class Pretty def initialize(runtime, path_or_io, options) @runtime, @io, @options = runtime, ensure_io(path_or_io), options + @config = runtime.configuration @exceptions = [] @indent = 0 @prefixes = options[:prefixes] || {} @@ -30,6 +32,7 @@ def initialize(runtime, path_or_io, options) @previous_step_keyword = nil @snippets_input = [] @counts = ConsoleCounts.new(runtime.configuration) + @issues = ConsoleIssues.new(runtime.configuration) end def before_features(features) @@ -37,7 +40,7 @@ def before_features(features) end def after_features(features) - print_summary(features, @counts) + print_summary(features) end def before_feature(feature) @@ -239,8 +242,8 @@ def cell_prefix(status) @prefixes[status] end - def print_summary(features, counts) - print_statistics(features.duration, @options, counts) + def print_summary(features) + print_statistics(features.duration, @config, @counts, @issues) print_snippets(@options) print_passing_wip(@options) end diff --git a/lib/cucumber/formatter/progress.rb b/lib/cucumber/formatter/progress.rb index eb88c93e2b..a8c75f768d 100644 --- a/lib/cucumber/formatter/progress.rb +++ b/lib/cucumber/formatter/progress.rb @@ -2,6 +2,7 @@ require 'cucumber/formatter/backtrace_filter' require 'cucumber/formatter/console' require 'cucumber/formatter/console_counts' +require 'cucumber/formatter/console_issues' require 'cucumber/formatter/io' require 'cucumber/formatter/duration_extractor' require 'cucumber/formatter/hook_query_visitor' @@ -27,6 +28,7 @@ def initialize(config) @failed_test_cases = [] @passed_test_cases = [] @counts = ConsoleCounts.new(config) + @issues = ConsoleIssues.new(config) config.on_event :step_match, &method(:on_step_match) config.on_event :test_case_starting, &method(:on_test_case_starting) config.on_event :test_step_finished, &method(:on_test_step_finished) @@ -76,7 +78,7 @@ def on_test_run_finished(_event) def print_summary print_elements(@pending_step_matches, :pending, 'steps') print_elements(@failed_results, :failed, 'steps') - print_statistics_local(@total_duration) + print_statistics(@total_duration, @config, @counts, @issues) snippet_text_proc = lambda { |step_keyword, step_name, multiline_arg| snippet_text(step_keyword, step_name, multiline_arg) } @@ -89,26 +91,6 @@ def print_summary end end - def print_statistics_local(duration) - if @failed_test_cases.any? - failed_test_cases_data = @failed_test_cases.map do |test_case| - TestCaseData.new(name="#{test_case.keyword}: #{test_case.name}", location=test_case.location) - end - print_failing_scenarios(failed_test_cases_data, config.custom_profiles, config.source?) - end - - scenarios_proc = lambda{|status| summary.test_cases.total(status)} - @io.puts @counts.to_s - @io.puts(format_duration(duration)) if duration && config.duration? - - if config.randomize? - @io.puts - @io.puts "Randomized with seed #{config.seed}" - end - - @io.flush - end - CHARS = { :passed => '.', :failed => 'F', diff --git a/lib/cucumber/formatter/summary.rb b/lib/cucumber/formatter/summary.rb index b0a65a46ca..4b531cc11f 100644 --- a/lib/cucumber/formatter/summary.rb +++ b/lib/cucumber/formatter/summary.rb @@ -1,6 +1,7 @@ require 'cucumber/formatter/io' require 'cucumber/formatter/console' require 'cucumber/formatter/console_counts' +require 'cucumber/formatter/console_issues' require 'cucumber/core/test/result' module Cucumber @@ -14,6 +15,8 @@ class Summary def initialize(config) @config, @io = config, ensure_io(config.out_stream) @counts = ConsoleCounts.new(@config) + @issues = ConsoleIssues.new(@config) + @start_time = Time.now @config.on_event :test_case_starting do |event| print_feature event.test_case @@ -25,7 +28,9 @@ def initialize(config) end @config.on_event :test_run_finished do |event| - print_counts + duration = Time.now - @start_time + @io.puts + print_statistics(duration, @config, @counts, @issues) end end @@ -46,11 +51,6 @@ def print_test_case(test_case) def print_result(result) @io.puts format_string(result, result.to_sym) end - - def print_counts - @io.puts - @io.puts @counts.to_s - end end end end