diff --git a/.rubocop.yml b/.rubocop.yml index 7d48cd73c6..4591707204 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -15,8 +15,6 @@ AllCops: Exclude: - 'tmp/**/*' - 'vendor/**/*' - - 'lib/cucumber/formatter/legacy_api/*' - - 'spec/cucumber/formatter/legacy_api/*' # Reviewed: please see PR-1022 for details on why this cop is disabled: # https://github.com/cucumber/cucumber-ruby/pull/1022 diff --git a/features/docs/api/listen_for_events.feature b/features/docs/api/listen_for_events.feature index d5a084a35e..afe2f0397f 100644 --- a/features/docs/api/listen_for_events.feature +++ b/features/docs/api/listen_for_events.feature @@ -39,7 +39,7 @@ Feature: Listen for events """ Feature: Scenario: - Given passing + Given this step passes """ And the standard step definitions And a file named "features/support/my_listener.rb" with: diff --git a/features/docs/extending_cucumber/custom_formatter.feature b/features/docs/extending_cucumber/custom_formatter.feature index c5f9eaf819..6698fa8658 100644 --- a/features/docs/extending_cucumber/custom_formatter.feature +++ b/features/docs/extending_cucumber/custom_formatter.feature @@ -60,35 +60,3 @@ Feature: Custom Formatter """ {"foo"=>"bar", "one"=>"two"} """ - - Scenario: Use the legacy API - This is deprecated and should no longer be used. - - Given a file named "features/support/custom_legacy_formatter.rb" with: - """ - module MyCustom - class LegacyFormatter - def initialize(runtime, io, options) - @io = io - end - - def before_feature(feature) - @io.puts feature.short_name.upcase - end - - def scenario_name(keyword, name, file_colon_line, source_indent) - @io.puts " #{name.upcase}" - end - end - end - """ - When I run `cucumber features/f.feature --format MyCustom::LegacyFormatter` - Then it should pass with exactly: - """ - WARNING: The formatter MyCustom::LegacyFormatter is using the deprecated formatter API which will be removed in v4.0 of Cucumber. - - I'LL USE MY OWN - JUST PRINT ME - - """ - diff --git a/features/docs/formatters/api_methods.feature b/features/docs/formatters/api_methods.feature index 95d3b24b1b..28dcc2f382 100644 --- a/features/docs/formatters/api_methods.feature +++ b/features/docs/formatters/api_methods.feature @@ -26,7 +26,7 @@ Feature: Formatter API methods module Formatter class Test include Io - def initialize(runtime, path_or_io, options) + def initialize(config) ensure_file("my/special/output.file", "custom formatter") end end diff --git a/lib/cucumber/configuration.rb b/lib/cucumber/configuration.rb index 76945754e6..4d34d85208 100644 --- a/lib/cucumber/configuration.rb +++ b/lib/cucumber/configuration.rb @@ -196,8 +196,7 @@ def formatter_factories factory = formatter_class(format) yield factory, formatter_options, - path_or_io, - Cli::Options.new(STDOUT, STDERR, @options) + path_or_io rescue Exception => e raise e, "#{e.message}\nError creating formatter: #{format}", e.backtrace end diff --git a/lib/cucumber/filters/prepare_world.rb b/lib/cucumber/filters/prepare_world.rb index fbb824b5b3..79020c0119 100644 --- a/lib/cucumber/filters/prepare_world.rb +++ b/lib/cucumber/filters/prepare_world.rb @@ -24,12 +24,7 @@ def test_case end around_hooks = [init_scenario] + @original_test_case.around_hooks - empty_hook = proc {} # no op - legacy format adapter expects a before hooks - empty_hook_location = Cucumber::Core::Ast::Location.from_source_location(*empty_hook.source_location) - default_hook = Cucumber::Hooks.before_hook(@original_test_case.source, empty_hook_location, &empty_hook) - steps = [default_hook] + @original_test_case.test_steps - - @original_test_case.with_around_hooks(around_hooks).with_steps(steps) + @original_test_case.with_around_hooks(around_hooks).with_steps(@original_test_case.test_steps) end private diff --git a/lib/cucumber/formatter/legacy_api/adapter.rb b/lib/cucumber/formatter/legacy_api/adapter.rb deleted file mode 100644 index 5c3460b23c..0000000000 --- a/lib/cucumber/formatter/legacy_api/adapter.rb +++ /dev/null @@ -1,1028 +0,0 @@ -# frozen_string_literal: true -require 'forwardable' -require 'delegate' -require 'cucumber/errors' -require 'cucumber/multiline_argument' -require 'cucumber/formatter/backtrace_filter' -require 'cucumber/formatter/legacy_api/ast' - -module Cucumber - module Formatter - module LegacyApi - - Adapter = Struct.new(:formatter, :results, :config) do - extend Forwardable - - def initialize(*) - super - emit_deprecation_warning - - @matches = collect_matches - config.on_event(:test_case_started) do |event| - formatter.before_test_case(event.test_case) - printer.before_test_case(event.test_case) - end - config.on_event(:test_step_started) do |event| - formatter.before_test_step(event.test_step) - printer.before_test_step(event.test_step) - end - config.on_event(:test_step_finished) do |event| - test_step, result = *event.attributes - printer.after_test_step(test_step, result) - formatter.after_test_step(test_step, result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)) - end - config.on_event(:test_case_finished) do |event| - test_case, result = *event.attributes - record_test_case_result(test_case, result) - printer.after_test_case(test_case, result) - formatter.after_test_case(test_case, result.with_filtered_backtrace(Cucumber::Formatter::BacktraceFilter)) - end - config.on_event(:test_run_finished) do - printer.after - formatter.done - end - end - - def_delegators :formatter, :ask - def_delegators :printer, :embed - - def puts(*messages) - printer.puts(messages) - end - - private - - def emit_deprecation_warning - parent_name = formatter_class_name =~ /::[^:]+\Z/ ? $`.freeze : nil - return if parent_name == 'Cucumber::Formatter' - return if !config.out_stream # some unit tests don't set it - config.out_stream.puts "WARNING: The formatter #{formatter.class.name} is using the deprecated formatter API which will be removed in v4.0 of Cucumber." - config.out_stream.puts - end - - def formatter_class_name - formatter.class.name - rescue NoMethodError # when we use the Fanout, things get gnarly - formatter.class[0].class.name - end - - def printer - @printer ||= FeaturesPrinter.new(formatter, results, config, @matches).before - end - - def record_test_case_result(test_case, result) - scenario = LegacyResultBuilder.new(result).scenario("#{test_case.keyword}: #{test_case.name}", test_case.location) - results.scenario_visited(scenario) - end - - def collect_matches - result = {} - config.on_event(:step_activated) do |event| - test_step, step_match = *event.attributes - result[test_step.source.last] = step_match - end - result - end - - require 'cucumber/core/test/timer' - FeaturesPrinter = Struct.new(:formatter, :results, :config, :matches) do - extend Forwardable - - def before - timer.start - formatter.before_features(nil) - self - end - - def before_test_case(test_case) - test_case.describe_source_to(self) - @child.before_test_case(test_case) - end - - def before_test_step(*args) - @child.before_test_step(*args) - end - - def after_test_step(test_step, result) - @child.after_test_step(test_step, result) - end - - def after_test_case(*args) - @child.after_test_case(*args) - end - - def feature(node, *) - if node != @current_feature - @child.after if @child - @child = FeaturePrinter.new(formatter, results, matches, config, node).before - @current_feature = node - end - end - - def scenario(node, *) - end - - def scenario_outline(node, *) - end - - def examples_table(node, *) - end - - def examples_table_row(node, *) - end - - def after - @child.after if @child - formatter.after_features Ast::Features.new(timer.sec) - self - end - - def puts(messages) - @child.puts(messages) - end - - def embed(src, mime_type, label) - @child.embed(src, mime_type, label) - end - - private - - def timer - @timer ||= Cucumber::Core::Test::Timer.new - end - - end - - module TestCaseSource - def self.for(test_case, result) - collector = Collector.new - test_case.describe_source_to collector, result - collector.result.freeze - end - - class Collector - attr_reader :result - - def initialize - @result = CaseSource.new - end - - def method_missing(name, node, _test_case_result, *_args) - result.send "#{name}=", node - end - end - - require 'ostruct' - class CaseSource < OpenStruct - end - end - - module TestStepSource - def self.for(test_step, result) - collector = Collector.new - test_step.describe_source_to collector, result - collector.result.freeze - end - - class Collector - attr_reader :result - - def initialize - @result = StepSource.new - end - - def method_missing(name, node, step_result, *_args) - result.send "#{name}=", node - result.send "#{name}_result=", LegacyResultBuilder.new(step_result) - end - end - - require 'ostruct' - class StepSource < OpenStruct - def build_step_invocation(indent, matches, config, messages, embeddings) - step_result.step_invocation( - matches.fetch(step) { NoStepMatch.new(step, step.text) }, - step, - indent, - background, - config, - messages, - embeddings - ) - end - end - - end - - Embedding = Struct.new(:src, :mime_type, :label) do - - def send_to_formatter(formatter) - formatter.embed(src, mime_type, label) - end - end - - FeaturePrinter = Struct.new(:formatter, :results, :matches, :config, :node) do - - def before - formatter.before_feature(node) - language_comment = node.language.iso_code != 'en' ? ["# language: #{node.language.iso_code}"] : [] - Ast::Comments.new(language_comment + node.comments).accept(formatter) - Ast::Tags.new(node.tags).accept(formatter) - formatter.feature_name node.keyword, node.legacy_conflated_name_and_description - @delayed_messages = [] - @delayed_embeddings = [] - self - end - - attr_reader :current_test_step_source - - def before_test_case(_test_case) - @before_hook_results = Ast::HookResultCollection.new - @test_step_results = [] - end - - def before_test_step(test_step) - end - - def after_test_step(test_step, result) - @current_test_step_source = TestStepSource.for(test_step, result) - # TODO: stop calling self, and describe source to another object - test_step.describe_source_to(self, result) - print_step - @test_step_results << result - end - - def after_test_case(test_case, test_case_result) - if current_test_step_source && current_test_step_source.step_result.nil? - switch_step_container - end - - if test_case_result.failed? && !any_test_steps_failed? - # around hook must have failed. Print the error. - switch_step_container(TestCaseSource.for(test_case, test_case_result)) - LegacyResultBuilder.new(test_case_result).describe_exception_to formatter - end - - # messages and embedding should already have been handled, but just in case... - @delayed_messages.each { |message| formatter.puts(message) } - @delayed_embeddings.each { |embedding| embedding.send_to_formatter(formatter) } - @delayed_messages = [] - @delayed_embeddings = [] - - @child.after_test_case(test_case, test_case_result) if @child - @previous_test_case_background = @current_test_case_background - @previous_test_case_scenario_outline = current_test_step_source && current_test_step_source.scenario_outline - end - - def before_hook(_location, result) - @before_hook_results << Ast::HookResult.new(LegacyResultBuilder.new(result), @delayed_messages, @delayed_embeddings) - @delayed_messages = [] - @delayed_embeddings = [] - end - - def after_hook(_location, 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 Ast::HookResult.new(LegacyResultBuilder.new(result), @delayed_messages, @delayed_embeddings) - @delayed_messages = [] - @delayed_embeddings = [] - end - - def after_step_hook(_hook, result) - p current_test_step_source if current_test_step_source.step.nil? - line = current_test_step_source.step.backtrace_line - @child.after_step_hook Ast::HookResult.new(LegacyResultBuilder.new(result). - append_to_exception_backtrace(line), @delayed_messages, @delayed_embeddings) - @delayed_messages = [] - @delayed_embeddings = [] - end - - def background(node, *) - @current_test_case_background = node - end - - def puts(messages) - @delayed_messages.push *messages - end - - def embed(src, mime_type, label) - @delayed_embeddings.push Embedding.new(src, mime_type, label) - end - - def step(*);end - def scenario(*);end - def scenario_outline(*);end - def examples_table(*);end - def examples_table_row(*);end - def feature(*);end - - def after - @child.after if @child - formatter.after_feature(node) - self - end - - private - - attr_reader :before_hook_results - private :before_hook_results - - def any_test_steps_failed? - @test_step_results.any? &:failed? - end - - def switch_step_container(source = current_test_step_source) - switch_to_child select_step_container(source), source - end - - def select_step_container(source) - if source.background - if same_background_as_previous_test_case?(source) - HiddenBackgroundPrinter.new(formatter, source.background) - else - BackgroundPrinter.new(formatter, node, source.background, before_hook_results) - end - elsif source.scenario - ScenarioPrinter.new(formatter, source.scenario, before_hook_results) - elsif source.scenario_outline - if same_scenario_outline_as_previous_test_case?(source) && @previous_outline_child - @previous_outline_child - else - ScenarioOutlinePrinter.new(formatter, config, source.scenario_outline) - end - else - raise 'unknown step container' - end - end - - def same_background_as_previous_test_case?(source) - source.background == @previous_test_case_background - end - - def same_scenario_outline_as_previous_test_case?(source) - source.scenario_outline == @previous_test_case_scenario_outline - end - - def print_step - return unless current_test_step_source.step_result - switch_step_container - - if current_test_step_source.scenario_outline - @child.examples_table(current_test_step_source.examples_table) - @child.examples_table_row(current_test_step_source.examples_table_row, before_hook_results) - end - - if @failed_hidden_background_step - indent = Indent.new(@child.node) - step_invocation = @failed_hidden_background_step.build_step_invocation(indent, matches, config, [], []) - @child.step_invocation(step_invocation, @failed_hidden_background_step) - @failed_hidden_background_step = nil - end - - unless @last_step == current_test_step_source.step - indent ||= Indent.new(@child.node) - step_invocation = current_test_step_source.build_step_invocation(indent, matches, config, @delayed_messages, @delayed_embeddings) - results.step_visited step_invocation - @child.step_invocation(step_invocation, current_test_step_source) - @last_step = current_test_step_source.step - end - @delayed_messages = [] - @delayed_embeddings = [] - end - - def switch_to_child(child, source) - return if @child == child - if @child - if from_first_background(@child) - @first_background_failed = @child.failed? - elsif from_hidden_background(@child) - if not @first_background_failed - @failed_hidden_background_step = @child.get_failed_step_source - end - if @previous_outline_child - @previous_outline_child.after unless same_scenario_outline_as_previous_test_case?(source) - end - end - if from_scenario_outline_to_hidden_background(@child, child) - @previous_outline_child = @child - else - @child.after - @previous_outline_child = nil - end - end - child.before unless to_scenario_outline(child) && same_scenario_outline_as_previous_test_case?(source) - @child = child - end - - def from_scenario_outline_to_hidden_background(from, to) - from.class.name == ScenarioOutlinePrinter.name && - to.class.name == HiddenBackgroundPrinter.name - end - - def from_first_background(from) - from.class.name == BackgroundPrinter.name - end - - def from_hidden_background(from) - from.class.name == HiddenBackgroundPrinter.name - end - - def to_scenario_outline(to) - to.class.name == ScenarioOutlinePrinter.name - end - - end - - module PrintsAfterHooks - def after_hook_results - @after_hook_results ||= Ast::HookResultCollection.new - end - - def after_hook(result) - after_hook_results << result - end - end - - # Basic printer used by default - class AfterHookPrinter - attr_reader :formatter - - def initialize(formatter) - @formatter = formatter - end - - include PrintsAfterHooks - - def after - after_hook_results.accept(formatter) - end - end - - BackgroundPrinter = Struct.new(:formatter, :feature, :node, :before_hook_results) do - - def after_test_case(*) - end - - def after_hook(*) - end - - def before - formatter.before_background Ast::Background.new(feature, node) - Ast::Comments.new(node.comments).accept(formatter) - formatter.background_name node.keyword, node.legacy_conflated_name_and_description, node.location.to_s, indent.of(node) - before_hook_results.accept(formatter) - self - end - - def after_step_hook(result) - result.accept formatter - end - - def step_invocation(step_invocation, source) - @child ||= StepsPrinter.new(formatter).before - @child.step_invocation step_invocation - if source.step_result.status == :failed - @failed = true - end - end - - def after - @child.after if @child - formatter.after_background(Ast::Background.new(feature, node)) - self - end - - def failed? - @failed - end - - private - - def indent - @indent ||= Indent.new(node) - end - end - - # Printer to handle background steps for anything but the first scenario in a - # feature. These steps should not be printed. - class HiddenBackgroundPrinter < Struct.new(:formatter, :node) - def get_failed_step_source - return @source_of_failed_step - end - - def step_invocation(_step_invocation, source) - if source.step_result.status == :failed - @source_of_failed_step = source - end - end - - def before;self;end - def after;self;end - def before_hook(*);end - def after_hook(*);end - def after_step_hook(*);end - def examples_table(*);end - def after_test_case(*);end - end - - ScenarioPrinter = Struct.new(:formatter, :node, :before_hook_results) do - include PrintsAfterHooks - - def before - formatter.before_feature_element(node) - Ast::Comments.new(node.comments).accept(formatter) - Ast::Tags.new(node.tags).accept(formatter) - formatter.scenario_name node.keyword, node.legacy_conflated_name_and_description, node.location.to_s, indent.of(node) - before_hook_results.accept(formatter) - self - end - - def step_invocation(step_invocation, _source) - @child ||= StepsPrinter.new(formatter).before - @child.step_invocation step_invocation - end - - def after_step_hook(result) - result.accept formatter - end - - def after_test_case(_test_case, result) - @test_case_result = result - after - end - - def after - return if @done - @child.after if @child - scenario = LegacyResultBuilder.new(@test_case_result).scenario(node.name, node.location) - after_hook_results.accept(formatter) - formatter.after_feature_element(scenario) - @done = true - self - end - - private - - def indent - @indent ||= Indent.new(node) - end - end - - StepsPrinter = Struct.new(:formatter) do - def before - formatter.before_steps(nil) - self - end - - def step_invocation(step_invocation) - steps << step_invocation - step_invocation.accept(formatter) - self - end - - def after - formatter.after_steps(steps) - self - end - - private - - def steps - @steps ||= Ast::StepInvocations.new - end - - end - - ScenarioOutlinePrinter = Struct.new(:formatter, :configuration, :node) do - extend Forwardable - def_delegators :@child, :after_hook, :after_step_hook - - def before - formatter.before_feature_element(node) - Ast::Comments.new(node.comments).accept(formatter) - Ast::Tags.new(node.tags).accept(formatter) - formatter.scenario_name node.keyword, node.legacy_conflated_name_and_description, node.location.to_s, indent.of(node) - OutlineStepsPrinter.new(formatter, configuration, indent).print(node) - self - end - - def step_invocation(step_invocation, source) - _node, result = source.step, source.step_result - @last_step_result = result - @child.step_invocation(step_invocation, source) - end - - def examples_table(examples_table) - @child ||= ExamplesArrayPrinter.new(formatter, configuration).before - @child.examples_table(examples_table) - end - - def examples_table_row(node, before_hook_results) - @child.examples_table_row(node, before_hook_results) - end - - def after_test_case(test_case, result) - @child.after_test_case(test_case, result) - end - - def after - @child.after if @child - # TODO: the last step result might not accurately reflect the - # overall scenario result. - scenario_outline = last_step_result.scenario_outline(node.name, node.location) - formatter.after_feature_element(scenario_outline) - self - end - - private - - def last_step_result - @last_step_result || Core::Test::Result::Unknown.new - end - - def indent - @indent ||= Indent.new(node) - end - end - - OutlineStepsPrinter = Struct.new(:formatter, :configuration, :indent, :outline) do - def print(node) - node.describe_to self - steps_printer.after - end - - def scenario_outline(_node, &descend) - descend.call(self) - end - - def outline_step(step) - step_match = NoStepMatch.new(step, step.text) - step_invocation = LegacyResultBuilder.new(Core::Test::Result::Skipped.new). - step_invocation(step_match, step, indent, nil, configuration, [], []) - steps_printer.step_invocation step_invocation - end - - def examples_table(*);end - - private - - def steps_printer - @steps_printer ||= StepsPrinter.new(formatter).before - end - end - - ExamplesArrayPrinter = Struct.new(:formatter, :configuration) do - extend Forwardable - def_delegators :@child, :step_invocation, :after_hook, :after_step_hook, :after_test_case, :examples_table_row - - def before - formatter.before_examples_array(:examples_array) - self - end - - def examples_table(examples_table) - return if examples_table == @current - @child.after if @child - @child = ExamplesTablePrinter.new(formatter, configuration, examples_table).before - @current = examples_table - end - - def after - @child.after if @child - formatter.after_examples_array - self - end - end - - ExamplesTablePrinter = Struct.new(:formatter, :configuration, :node) do - extend Forwardable - def_delegators :@child, :step_invocation, :after_hook, :after_step_hook, :after_test_case - - def before - formatter.before_examples(node) - Ast::Comments.new(node.comments).accept(formatter) - Ast::Tags.new(node.tags).accept(formatter) - formatter.examples_name(node.keyword, node.legacy_conflated_name_and_description) - formatter.before_outline_table(legacy_table) - if !configuration.expand? - HeaderTableRowPrinter.new(formatter, ExampleTableRow.new(node.header), Ast::Node.new).before.after - end - self - end - - def examples_table_row(examples_table_row, before_hook_results) - return if examples_table_row == @current - @child.after if @child - row = ExampleTableRow.new(examples_table_row) - @child = if !configuration.expand? - TableRowPrinter.new(formatter, row, before_hook_results).before - else - ExpandTableRowPrinter.new(formatter, row, before_hook_results).before - end - @current = examples_table_row - end - - def after_test_case(*args) - @child.after_test_case(*args) - end - - def after - @child.after if @child - formatter.after_outline_table(node) - formatter.after_examples(node) - self - end - - private - - def legacy_table - LegacyTable.new(node) - end - - class ExampleTableRow < SimpleDelegator - def dom_id - file_colon_line.gsub(/[\/\.:]/, '_') - end - end - - LegacyTable = Struct.new(:node) do - def col_width(index) - max_width = FindMaxWidth.new(index) - node.describe_to max_width - max_width.result - end - - require 'cucumber/gherkin/formatter/escaping' - FindMaxWidth = Struct.new(:index) do - include ::Cucumber::Gherkin::Formatter::Escaping - - def examples_table(table, &descend) - @result = char_length_of(table.header.values[index]) - descend.call(self) - end - - def examples_table_row(row, &_descend) - width = char_length_of(row.values[index]) - @result = width if width > result - end - - def result - @result ||= 0 - end - - private - def char_length_of(cell) - escape_cell(cell).unpack('U*').length - end - end - end - end - - class TableRowPrinterBase < Struct.new(:formatter, :node, :before_hook_results) - include PrintsAfterHooks - - def after_step_hook(result) - @after_step_hook_result ||= Ast::HookResultCollection.new - @after_step_hook_result << result - end - - def after_test_case(*_args) - after - end - - private - - def indent - :not_needed - end - - def legacy_table_row - Ast::ExampleTableRow.new(exception, @status, node.values, node.location, node.language) - end - - def exception - return nil unless @failed_step - @failed_step.exception - end - end - - class HeaderTableRowPrinter < TableRowPrinterBase - def legacy_table_row - Ast::ExampleTableRow.new(exception, @status, node.values, node.location, Ast::NullLanguage.new) - end - - def before - Ast::Comments.new(node.comments).accept(formatter) - formatter.before_table_row(node) - self - end - - def after - node.values.each do |value| - formatter.before_table_cell(value) - formatter.table_cell_value(value, :skipped_param) - formatter.after_table_cell(value) - end - formatter.after_table_row(legacy_table_row) - self - end - end - - - class TableRowPrinter < TableRowPrinterBase - def before - before_hook_results.accept(formatter) - Ast::Comments.new(node.comments).accept(formatter) - formatter.before_table_row(node) - self - end - - def step_invocation(step_invocation, source) - result = source.step_result - step_invocation.messages.each { |message| formatter.puts(message) } - step_invocation.embeddings.each { |embedding| embedding.send_to_formatter(formatter) } - @failed_step = step_invocation if result.status == :failed - @status = step_invocation.status unless already_failed? - end - - def after - return if @done - @child.after if @child - node.values.each do |value| - formatter.before_table_cell(value) - 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.describe_exception_to(formatter) if @after_step_hook_result - after_hook_results.describe_exception_to(formatter) - @done = true - self - end - - private - - def already_failed? - @status == :failed || @status == :undefined || @status == :pending - end - end - - class ExpandTableRowPrinter < TableRowPrinterBase - def before - before_hook_results.accept(formatter) - self - end - - def step_invocation(step_invocation, source) - result = source.step_result - @table_row ||= legacy_table_row - step_invocation.indent.record_width_of(@table_row) - if !@scenario_name_printed - print_scenario_name(step_invocation, @table_row) - @scenario_name_printed = true - end - step_invocation.accept(formatter) - @failed_step = step_invocation if result.status == :failed - @status = step_invocation.status unless @status == :failed - end - - def after - return if @done - @child.after if @child - @after_step_hook_result.accept(formatter) if @after_step_hook_result - after_hook_results.accept(formatter) - @done = true - self - end - - private - - def print_scenario_name(step_invocation, table_row) - formatter.scenario_name table_row.keyword, table_row.name, node.location.to_s, step_invocation.indent.of(table_row) - end - end - - class Indent - def initialize(node) - @widths = [] - node.describe_to(self) - end - - [:background, :scenario, :scenario_outline].each do |node_name| - define_method(node_name) do |node, &descend| - record_width_of node - descend.call(self) - end - end - - [:step, :outline_step].each do |node_name| - define_method(node_name) do |node| - record_width_of node - end - end - - def examples_table(*); end - def examples_table_row(*); end - - def of(node) - # The length of the instantiated steps in --expand mode are currently - # not included in the calculation of max => make sure to return >= 1 - [1, max - node.to_s.length - node.keyword.length].max - end - - def record_width_of(node) - @widths << node.keyword.length + node.to_s.length + 1 - end - - private - - def max - @widths.max - end - end - - class LegacyResultBuilder - attr_reader :status - def initialize(result) - @result = result - @result.describe_to(self) - end - - def passed - @status = :passed - end - - def failed - @status = :failed - end - - def undefined - @status = :undefined - end - - def skipped - @status = :skipped - end - - def pending(exception, *) - @exception = exception - @status = :pending - end - - def exception(exception, *) - @exception = exception - end - - def append_to_exception_backtrace(line) - @exception.set_backtrace(@exception.backtrace + [line.to_s]) if @exception - return self - end - - def duration(duration, *) - @duration = duration - end - - def step_invocation(step_match, step, indent, background, configuration, messages, embeddings) - Ast::StepInvocation.new(step_match, @status, @duration, step_exception(step, configuration), indent, background, step, messages, embeddings) - end - - def scenario(name, location) - Ast::Scenario.new(@status, name, location) - end - - def scenario_outline(name, location) - Ast::ScenarioOutline.new(@status, name, location) - end - - def describe_exception_to(formatter) - formatter.exception(filtered_exception, @status) if @exception - end - - private - - def step_exception(step, configuration) - return filtered_step_exception(step) if @exception - return nil unless @status == :undefined && configuration.strict.strict?(:undefined) - @exception = Cucumber::Undefined.from(@result, step.text) - @exception.backtrace << step.backtrace_line - filtered_step_exception(step) - end - - def filtered_exception - Cucumber::Formatter::BacktraceFilter.new(@exception.dup).exception - end - - def filtered_step_exception(_step) - exception = filtered_exception - return Cucumber::Formatter::BacktraceFilter.new(exception).exception - end - end - - end - - end - end -end diff --git a/lib/cucumber/formatter/legacy_api/ast.rb b/lib/cucumber/formatter/legacy_api/ast.rb deleted file mode 100644 index bd11effe7e..0000000000 --- a/lib/cucumber/formatter/legacy_api/ast.rb +++ /dev/null @@ -1,394 +0,0 @@ -# frozen_string_literal: true -module Cucumber - module Formatter - module LegacyApi - # Adapters to pass to the legacy API formatters that provide the interface - # of the old AST classes - module Ast - - # Acts as a null object, or a base class - class Node - def initialize(node = nil) - @node = node - end - - def accept(formatter) - end - - attr_reader :node - private :node - end - - # Null object for HeaderRow language. - # ExampleTableRow#keyword is never called on them, - # but this will pass silently if it happens anyway - class NullLanguage - def method_missing(*_args, &_block) - self - end - - def to_ary - [''] - end - end - - class HookResultCollection - def initialize - @children = [] - end - - 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 - end - - Comments = Struct.new(:comments) do - def accept(formatter) - return if comments.empty? - formatter.before_comment comments - comments.each do |comment| - formatter.comment_line comment.to_s.strip - end - formatter.after_comment comments - end - end - - class HookResult - def initialize(result, messages, embeddings) - @result, @messages, @embeddings = result, messages, embeddings - @already_accepted = false - end - - def accept(formatter) - unless @already_accepted - send_output_to(formatter) - describe_exception_to(formatter) - end - self - end - - def send_output_to(formatter) - return if @already_accepted - @messages.each { |message| formatter.puts(message) } - @embeddings.each { |embedding| embedding.send_to_formatter(formatter) } - end - - def describe_exception_to(formatter) - return if @already_accepted - @result.describe_exception_to(formatter) - @already_accepted = true - end - end - - StepInvocation = Struct.new(:step_match, - :status, - :duration, - :exception, - :indent, - :background, - :step, - :messages, - :embeddings) do - extend Forwardable - - def_delegators :step, :keyword, :text, :multiline_arg, :location - - def accept(formatter) - formatter.before_step(self) - Ast::Comments.new(step.comments).accept(formatter) - messages.each { |message| formatter.puts(message) } - embeddings.each { |embedding| embedding.send_to_formatter(formatter) } - formatter.before_step_result(*step_result_attributes) - print_step_name(formatter) - Ast::MultilineArg.for(multiline_arg).accept(formatter) - print_exception(formatter) - formatter.after_step_result(*step_result_attributes) - formatter.after_step(self) - end - - def step_result_attributes - legacy_multiline_arg = if multiline_arg.is_a?(Core::Ast::EmptyMultilineArgument) - nil - else - step.multiline_arg - end - [keyword, step_match, legacy_multiline_arg, status, exception, source_indent, background, file_colon_line] - end - - def failed? - status != :passed - end - - def passed? - status == :passed - end - - def dom_id - - end - - def actual_keyword(previous_step_keyword = nil) - step.actual_keyword(previous_step_keyword) - end - - def file_colon_line - location.to_s - end - - def backtrace_line - step_match.backtrace_line - end - - def step_invocation - self - end - - def to_s - text - end - - private - - def source_indent - indent.of(self) - end - - def print_step_name(formatter) - formatter.step_name( - keyword, - step_match, - status, - source_indent, - background, - location.to_s) - end - - def print_exception(formatter) - return unless exception - raise exception if ENV['FAIL_FAST'] - formatter.exception(exception, status) - end - end - - class StepInvocations < Array - def failed? - any?(&:failed?) - end - - def passed? - all?(&:passed?) - end - - def status - return :passed if passed? - failed_step.status - end - - def exception - failed_step.exception if failed_step - end - - private - - def failed_step - detect(&:failed?) - end - end - - class DataTableRow - def initialize(row, line) - @values = row - @line = line - end - - def dom_id - "row_#{line}" - end - - def accept(formatter) - formatter.before_table_row(self) - values.each do |value| - formatter.before_table_cell(value) - formatter.table_cell_value(value, status) - formatter.after_table_cell(value) - end - formatter.after_table_row(self) - end - - def status - :skipped - end - - def exception - nil - end - - attr_reader :values, :line - private :values, :line - end - - ExampleTableRow = Struct.new(:exception, :status, :cells, :location, :language) do - def name - '| ' + cells.join(' | ') + ' |' - end - - def to_s - name - end - - def failed? - status == :failed - end - - def line - location.line - end - - def keyword - # This method is only called when used for the scenario name line with - # the expand option, and on that line the keyword is "Scenario" - language.scenario_keywords[0] - end - end - - class LegacyTableRow < DataTableRow - def accept(formatter) - formatter.before_table_row(self) - values.each do |value| - formatter.before_table_cell(value.value) - formatter.table_cell_value(value.value, value.status) - formatter.after_table_cell(value.value) - end - formatter.after_table_row(self) - end - end - - Tags = Struct.new(:tags) do - def accept(formatter) - formatter.before_tags tags - tags.each do |tag| - formatter.tag_name tag.name - end - formatter.after_tags tags - end - end - - Scenario = Struct.new(:status, :name, :location) do - def backtrace_line(step_name = name.to_s, line = self.location.line) - "#{location.on_line(line)}:in `#{step_name}'" - end - - def failed? - :failed == status - end - - def line - location.line - end - end - - ScenarioOutline = Struct.new(:status, :name, :location) do - def backtrace_line(step_name = name.to_s, line = self.location.line) - "#{location.on_line(line)}:in `#{step_name}'" - end - - def failed? - :failed == status - end - - def line - location.line - end - end - - module MultilineArg - class << self - def for(node) - Builder.new(node).result - end - end - - class Builder - def initialize(node) - node.describe_to(self) - end - - def doc_string(node) - @result = DocString.new(node) - end - - def data_table(node) - @result = DataTable.new(node) - end - - def legacy_table(node) - @result = LegacyTable.new(node) - end - - def result - @result || Node.new(nil) - end - end - - class DocString < Node - def accept(formatter) - formatter.before_multiline_arg node - formatter.doc_string(node) - formatter.after_multiline_arg node - end - end - - class DataTable < Cucumber::MultilineArgument::DataTable - def node - @ast_table - end - - def accept(formatter) - formatter.before_multiline_arg self - node.raw.each_with_index do |row, index| - line = node.location.line + index - DataTableRow.new(row, line).accept(formatter) - end - formatter.after_multiline_arg self - end - end - end - - class LegacyTable < SimpleDelegator - def accept(formatter) - formatter.before_multiline_arg self - cells_rows.each_with_index do |row, index| - line = location.line + index - LegacyTableRow.new(row, line).accept(formatter) - end - formatter.after_multiline_arg self - end - end - - Features = Struct.new(:duration) - - class Background < SimpleDelegator - def initialize(feature, node) - super node - @feature = feature - end - - attr_reader :feature - end - - end - end - end -end diff --git a/lib/cucumber/formatter/legacy_api/results.rb b/lib/cucumber/formatter/legacy_api/results.rb deleted file mode 100644 index 50cd119b6f..0000000000 --- a/lib/cucumber/formatter/legacy_api/results.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true -module Cucumber - module Formatter - module LegacyApi - - class Results - def initialize - # Optimization - quicker lookup. - @inserted_steps = {} - @inserted_scenarios = {} - end - - def step_visited(step) #:nodoc: - step_id = step.object_id - - return if @inserted_steps.key?(step_id) - @inserted_steps[step_id] = step - steps.push(step) - end - - def scenario_visited(scenario) #:nodoc: - scenario_id = scenario.object_id - - return if @inserted_scenarios.key?(scenario_id) - @inserted_scenarios[scenario_id] = scenario - scenarios.push(scenario) - end - - def steps(status = nil) #:nodoc: - @steps ||= [] - if(status) - @steps.select{|step| step.status == status} - else - @steps - end - end - - def scenarios(status = nil) #:nodoc: - @scenarios ||= [] - if(status) - @scenarios.select{|scenario| scenario.status == status} - else - @scenarios - end - end - end - - end - end -end diff --git a/lib/cucumber/formatter/legacy_api/runtime_facade.rb b/lib/cucumber/formatter/legacy_api/runtime_facade.rb deleted file mode 100644 index 2194d2bcc7..0000000000 --- a/lib/cucumber/formatter/legacy_api/runtime_facade.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true -require 'cucumber/gherkin/i18n' - -module Cucumber - module Formatter - module LegacyApi - - # This is what's passed to the constructor of the formatters - class RuntimeFacade < Struct.new(:results, :support_code, :configuration) - def unmatched_step_definitions - support_code.unmatched_step_definitions - end - - def snippet_text(step_keyword, step_name, multiline_arg) #:nodoc: - keyword = Cucumber::Gherkin::I18n.code_keyword_for(step_keyword).strip - configuration.snippet_generators.map { |generator| - generator.call(keyword, step_name, multiline_arg, configuration.snippet_type) - }.join("\n") - end - - def scenarios(status = nil) - results.scenarios(status) - end - - def steps(status = nil) - results.steps(status) - end - end - - end - end -end diff --git a/lib/cucumber/runtime.rb b/lib/cucumber/runtime.rb index 74acf5d37e..26b3d2b1c7 100644 --- a/lib/cucumber/runtime.rb +++ b/lib/cucumber/runtime.rb @@ -54,7 +54,6 @@ class Runtime def initialize(configuration = Configuration.default) @configuration = Configuration.new(configuration) @support_code = SupportCode.new(self, @configuration) - @results = Formatter::LegacyApi::Results.new end # Allows you to take an existing runtime and change its configuration @@ -84,14 +83,6 @@ def dry_run? @configuration.dry_run? end - def scenarios(status = nil) - @results.scenarios(status) - end - - def steps(status = nil) - @results.steps(status) - end - def unmatched_step_definitions @support_code.unmatched_step_definitions end @@ -171,9 +162,6 @@ def set_encoding end end - require 'cucumber/formatter/legacy_api/adapter' - require 'cucumber/formatter/legacy_api/runtime_facade' - require 'cucumber/formatter/legacy_api/results' require 'cucumber/formatter/ignore_missing_messages' require 'cucumber/formatter/fail_fast' require 'cucumber/core/report/summary' @@ -194,39 +182,26 @@ def fail_fast_report def formatters @formatters ||= - @configuration.formatter_factories do |factory, formatter_options, path_or_io, options| - create_formatter(factory, formatter_options, path_or_io, options) + @configuration.formatter_factories do |factory, formatter_options, path_or_io| + create_formatter(factory, formatter_options, path_or_io) end end - def create_formatter(factory, formatter_options, path_or_io, cli_options) - if !legacy_formatter?(factory) - if accept_options?(factory) - return factory.new(@configuration, formatter_options) if path_or_io.nil? - return factory.new(@configuration.with_options(out_stream: path_or_io), - formatter_options) - else - return factory.new(@configuration) if path_or_io.nil? - return factory.new(@configuration.with_options(out_stream: path_or_io)) - end + def create_formatter(factory, formatter_options, path_or_io) + if accept_options?(factory) + return factory.new(@configuration, formatter_options) if path_or_io.nil? + factory.new(@configuration.with_options(out_stream: path_or_io), + formatter_options) + else + return factory.new(@configuration) if path_or_io.nil? + factory.new(@configuration.with_options(out_stream: path_or_io)) end - results = Formatter::LegacyApi::Results.new - runtime_facade = Formatter::LegacyApi::RuntimeFacade.new(results, @support_code, @configuration) - formatter = factory.new(runtime_facade, path_or_io, cli_options) - Formatter::LegacyApi::Adapter.new( - Formatter::IgnoreMissingMessages.new(formatter), - results, @configuration - ) end def accept_options?(factory) factory.instance_method(:initialize).arity > 1 end - def legacy_formatter?(factory) - factory.instance_method(:initialize).arity > 2 - end - def failure? if @configuration.wip? summary_report.test_cases.total_passed > 0 diff --git a/spec/cucumber/formatter/legacy_api/adapter_spec.rb b/spec/cucumber/formatter/legacy_api/adapter_spec.rb deleted file mode 100644 index e635d22d24..0000000000 --- a/spec/cucumber/formatter/legacy_api/adapter_spec.rb +++ /dev/null @@ -1,2175 +0,0 @@ -# frozen_string_literal: true -require 'cucumber/formatter/legacy_api/adapter' -require 'cucumber/core' -require 'cucumber/core/gherkin/writer' -require 'cucumber/runtime/step_hooks' -require 'cucumber/runtime/before_hooks' -require 'cucumber/runtime/after_hooks' -require 'cucumber/filters' -require 'spec_helper' - -module Cucumber - module Formatter::LegacyApi - describe Adapter do - include Core::Gherkin::Writer - include Core - - let!(:report) { Adapter.new(formatter, runtime.results, runtime.configuration) } - let(:formatter) { double('formatter').as_null_object } - let(:runtime) { Runtime.new } - let(:events) { runtime.configuration.event_bus } - let(:step_match_search) { SimpleStepDefinitionSearch.new } - - Failure = Class.new(StandardError) - - class SimpleStepMatch - def initialize(&block) - @block = block - end - - def activate(test_step) - test_step.with_action &@block - end - end - - class SimpleStepDefinitionSearch - def call(name) - if name =~ /pass/ - return [SimpleStepMatch.new {}] - end - - if name =~ /fail/ - return [SimpleStepMatch.new { raise Failure }] - end - - [] - end - end - - class HookWrapper - def initialize(proc) - @proc = proc - end - - def source_location - @proc.source_location - end - - def location - source_location - end - - def invoke(_pseudo_method, _arguments, &_block) - @proc.call - end - end - - class AddBeforeAndAfterHooks < Core::Filter.new - def test_case(test_case) - steps = before_hooks(test_case.source) + - test_case.test_steps + - after_hooks(test_case.source) - test_case.with_steps(steps).describe_to receiver - end - - private - - def before_hooks(source) - # The adapter is built on the assumption that each test case will have at least one step. This is annoying - # for tests, but a safe assumption for production use as we always add one hook to initialize the world. - hook = proc {} - [ Hooks.before_hook(source, hook.source_location, &hook) ] - end - - def after_hooks(source) - # We add an after hook to make sure the adapter can cope with it - hook = proc {} - [ Hooks.after_hook(source, hook.source_location, &hook) ] - end - end - - context 'message order' do - let(:formatter) { MessageSpy.new } - - it 'two features' do - gherkin_docs = [ - gherkin do - feature do - scenario do - step 'passing' - end - end - end, - gherkin do - feature do - scenario do - step 'passing' - end - end - end - ] - runner = Core::Test::Runner.new(events) - compile gherkin_docs, runner, default_filters - events.test_run_finished - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :after_feature_element, - :after_feature, - :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, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a scenario with one step' do - execute_gherkin do - feature do - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a scenario with two steps, one of them failing' do - execute_gherkin do - feature do - scenario do - step 'passing' - step 'failing' - end - end - end - expect( formatter.legacy_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, - :before_step, - :before_step_result, - :step_name, - :exception, - :after_step_result, - :after_step, - :after_steps, - :after_feature_element, - :after_feature, - :after_features - ] - end - - it 'a feature with two scenarios' do - execute_gherkin do - feature do - scenario do - step 'passing' - end - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :after_feature_element, - :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, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a background and an empty scenario' do - execute_gherkin do - feature do - background do - step 'passing' - end - scenario - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :before_feature_element, - :before_tags, - :after_tags, - :scenario_name, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a background and two scenarios' do - execute_gherkin do - feature do - background do - step 'passing' - end - scenario do - step 'passing' - end - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :after_feature_element, - :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, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a background and one scenario and one scenario outline' do - execute_gherkin do - feature do - background do - step 'passing' - end - scenario do - step 'passing' - end - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :after_feature_element, - :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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a background and one scenario outline and one scenario' do - execute_gherkin do - feature do - background do - step 'passing' - end - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - end - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :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, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a background and two scenario outlines' do - execute_gherkin do - feature do - background do - step 'passing' - end - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - end - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a background and one scenario outline with two rows' do - execute_gherkin do - feature do - background do - step 'passing' - end - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a background and one scenario outline with two examples tables' do - execute_gherkin do - feature do - background do - step 'passing' - end - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - examples do - row 'result' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a background with two steps' do - execute_gherkin do - feature do - background do - step 'passing' - step 'passing' - end - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a background' do - execute_gherkin do - feature do - background do - step 'passing' - end - scenario do - step 'passing' - end - end - end - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :after_feature_element, - :after_feature, - :after_features - ] - end - - it 'scenario outline' do - execute_gherkin do - feature do - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'scenario outline after scenario' do - execute_gherkin do - feature do - scenario do - step 'passing' - end - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :after_feature_element, - :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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'scenario outline before scenario' do - execute_gherkin do - feature do - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - end - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :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, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'scenario outline two rows' do - execute_gherkin do - feature do - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'scenario outline two examples tables' do - execute_gherkin do - feature do - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - examples do - row 'result' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'two scenario outline' do - execute_gherkin do - feature do - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - end - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'failing scenario outline' do - execute_gherkin do - feature do - scenario_outline do - step 'ing' - examples do - row 'result' - row 'fail' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - it 'a feature with a failing background and two scenarios' do - execute_gherkin do - feature do - background do - step 'failing' - end - scenario do - step 'passing' - end - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq [ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :exception, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :after_feature_element, - :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, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - - context 'in expand mode' do - let(:runtime) { Runtime.new expand: true } - let(:formatter) { MessageSpy.new } - - it 'scenario outline two rows' do - execute_gherkin do - feature do - scenario_outline do - step 'ing' - examples do - row 'result' - row 'pass' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :scenario_name, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :scenario_name, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ] - # rubocop:enable AlignArray - end - end - - context 'with exception in after step hook' do - - class FailingAfterStepHook - def find_after_step_hooks(_test_case) - failing_hook = HookWrapper.new(proc { raise Failure }) - Runtime::StepHooks.new [failing_hook] - end - end - - it 'prints the exception within the step' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyAfterStepHooks.new(FailingAfterStepHook.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :exception, - :after_steps, - :after_feature_element, - :after_feature, - :after_features - ]) - # rubocop:enable AlignArray - end - end - - context 'with exception in a single before hook' do - class FailingBeforeHook - def apply_before_hooks(test_case) - failing_hook = HookWrapper.new(proc { raise Failure }) - Runtime::BeforeHooks.new([failing_hook], RunningTestCase.new(test_case)).apply_to(test_case) - end - end - - it 'prints the exception after the scenario name' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyBeforeHooks.new(FailingBeforeHook.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq([ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_feature_element, - :before_tags, - :after_tags, - :scenario_name, - :exception, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_feature_element, - :after_feature, - :after_features - ]) - # rubocop:enable AlignArray - end - - it 'prints the exception after the background name' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyBeforeHooks.new(FailingBeforeHook.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - background do - step 'passing' - end - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq([ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_background, - :background_name, - :exception, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_background, - :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, - :after_feature_element, - :after_feature, - :after_features - ]) - # rubocop:enable AlignArray - end - - - it 'prints the exception before the examples table row' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyBeforeHooks.new(FailingBeforeHook.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - scenario_outline do - step 'ing' - examples do - row 'status' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :exception, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ]) - # rubocop:enable AlignArray - end - end - - context 'with exception in the first of several before hooks' do - # This proves that the second before hook's result doesn't overwrite - # the result of the first one. - class FailingAndPassingBeforeHooks - def apply_before_hooks(test_case) - failing_hook = HookWrapper.new(proc { raise Failure }) - passing_hook = HookWrapper.new(proc {}) - Runtime::BeforeHooks.new([failing_hook, passing_hook], RunningTestCase.new(test_case)).apply_to(test_case) - end - end - - it 'prints the exception after the scenario name' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyBeforeHooks.new(FailingAndPassingBeforeHooks.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_messages ).to eq([ - :before_features, - :before_feature, - :before_tags, - :after_tags, - :feature_name, - :before_feature_element, - :before_tags, - :after_tags, - :scenario_name, - :exception, - :before_steps, - :before_step, - :before_step_result, - :step_name, - :after_step_result, - :after_step, - :after_steps, - :after_feature_element, - :after_feature, - :after_features - ]) - # rubocop:enable AlignArray - end - end - - context 'with exception in after hooks' do - - class FailingAfterHook - def apply_after_hooks(test_case) - failing_hook = HookWrapper.new(proc { raise Failure }) - Runtime::AfterHooks.new([failing_hook], RunningTestCase.new(test_case)).apply_to(test_case) - end - end - - it 'prints the exception after the steps' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyAfterHooks.new(FailingAfterHook.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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 - ]) - # rubocop:enable AlignArray - end - - it 'prints the exception after the examples table row' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyAfterHooks.new(FailingAfterHook.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - scenario_outline do - step 'ing' - examples do - row 'status' - row 'pass' - end - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :before_examples_array, - :before_examples, - :before_tags, - :after_tags, - :examples_name, - :before_outline_table, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :before_table_row, - :before_table_cell, - :table_cell_value, - :after_table_cell, - :after_table_row, - :exception, - :after_outline_table, - :after_examples, - :after_examples_array, - :after_feature_element, - :after_feature, - :after_features - ]) - # rubocop:enable AlignArray - end - end - - context 'with exception in the first of several after hooks' do - class FailingThenPassingAfterHooks - def apply_after_hooks(test_case) - failing_hook = HookWrapper.new(proc { raise Failure }) - passing_hook = HookWrapper.new(proc {}) - Runtime::AfterHooks.new([failing_hook, passing_hook], RunningTestCase.new(test_case)).apply_to(test_case) - end - end - - it 'prints the exception after the steps' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyAfterHooks.new(FailingThenPassingAfterHooks.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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 - ]) - # rubocop:enable AlignArray - end - end - - context 'with an exception in an around hook before the test case is run' do - class FailingAroundHookBeforeRunningTestCase - def find_around_hooks(test_case) - [ - Hooks.around_hook(test_case.source) { raise Failure } - ] - end - end - - it 'prints the exception after the scenario name' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyAroundHooks.new(FailingAroundHookBeforeRunningTestCase.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - scenario do - step 'passing' - end - end - end - - # rubocop:disable AlignArray - expect( formatter.legacy_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 - ]) - # rubocop:enable AlignArray - end - end - - context 'with an exception in an around hook after the test case is run' do - class FailingAroundHookAfterRunningTestCase - def find_around_hooks(test_case) - [ - Hooks.around_hook(test_case.source) { |run_test_case| run_test_case.call; raise Failure } - ] - end - end - - it 'prints the exception after the scenario name' do - filters = [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - Filters::ApplyAroundHooks.new(FailingAroundHookAfterRunningTestCase.new), - AddBeforeAndAfterHooks.new - ] - execute_gherkin(filters) do - feature do - scenario do - step - end - end - end - # rubocop:disable AlignArray - expect( formatter.legacy_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, - :exception, - :after_steps, - :after_feature_element, - :after_feature, - :after_features - ]) - # rubocop:enable AlignArray - end - end - end - - describe 'before_step_result message' do - context 'when the step matches' do - it 'sends the step match to the formatter' do - expect(formatter).to receive(:before_step_result) do |_, step_match, *| - expect(step_match).to be_a SimpleStepMatch - end - execute_gherkin do - feature do - scenario do - step 'passing' - end - end - end - end - end - - context "when the step doesn't match" do - it 'sends a null object to the formatter' do - end - end - end - - it 'passes nil as the multiline arg when there is none' do - expect(formatter).to receive(:after_step_result) do |keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line| - expect(multiline_arg).to be_nil - end - execute_gherkin do - feature do - scenario do - step 'passing' - end - end - end - end - - context 'after_feature_element callback' do - it 'passes an object reflecting the status of the scenario' do - expect( formatter ).to receive(:after_feature_element).once do |scenario| - expect( scenario ).to be_failed - end - execute_gherkin do - feature do - scenario do - step 'failing' - step 'this will be skipped' - end - end - end - end - end - - context 'in strict mode' do - let(:runtime) { Runtime.new strict: Cucumber::Core::Test::Result::StrictConfiguration.new([:undefined]) } - - it 'passes an exception to the formatter for undefined steps' do - expect( formatter ).to receive(:exception) do |exception| - expect( exception.message ).to eq %{Undefined step: "this step is undefined"} - end - execute_gherkin do - feature do - scenario do - step 'this step is undefined' - end - end - end - end - end - - class MessageSpy - attr_reader :messages - - def initialize - @messages = [] - end - - def legacy_messages - @messages - [ - :before_test_step, - :before_test_case, - :after_test_step, - :after_test_case, - :done - ] - end - - def method_missing(message, *_args) - @messages << message - end - - def respond_to_missing?(_name, _include_private = false) - true - end - end - - def execute_gherkin(filters = default_filters, &gherkin) - runner = Core::Test::Runner.new(events) - compile [gherkin(&gherkin)], runner, filters - events.test_run_finished - self - end - - def default_filters - [ - Filters::ActivateSteps.new(step_match_search, runtime.configuration), - AddBeforeAndAfterHooks.new - ] - end - - end - end -end diff --git a/spec/cucumber/formatter/spec_helper.rb b/spec/cucumber/formatter/spec_helper.rb index f3f47fa26d..3d2f9a7a0e 100644 --- a/spec/cucumber/formatter/spec_helper.rb +++ b/spec/cucumber/formatter/spec_helper.rb @@ -21,7 +21,7 @@ module SpecHelper def run_defined_feature define_steps - actual_runtime.visitor = report + actual_runtime.visitor = Fanout.new([@formatter]) receiver = Test::Runner.new(event_bus) filters = [ @@ -39,15 +39,6 @@ def run_defined_feature event_bus.test_run_finished end - require 'cucumber/formatter/legacy_api/adapter' - def report - @report ||= LegacyApi::Adapter.new( - Fanout.new([@formatter]), - actual_runtime.results, - actual_runtime.configuration - ) - end - require 'cucumber/core/gherkin/document' def gherkin_doc Core::Gherkin::Document.new(self.class.feature_filename, gherkin) @@ -57,10 +48,6 @@ def gherkin self.class.feature_content || raise('No feature content defined!') end - def runtime - @runtime_facade ||= LegacyApi::RuntimeFacade.new(actual_runtime.results, actual_runtime.support_code, actual_runtime.configuration) - end - def actual_runtime @runtime ||= Runtime.new(options) end