diff --git a/spec/cucumber/core/gherkin/parser_spec.rb b/spec/cucumber/core/gherkin/parser_spec.rb index a9e0d55f..cdf02cf8 100644 --- a/spec/cucumber/core/gherkin/parser_spec.rb +++ b/spec/cucumber/core/gherkin/parser_spec.rb @@ -143,12 +143,12 @@ def parse feature do rule description: 'First rule' do scenario name: 'Do not talk about the fight club' do - step 'text' + step 'step 1' end end rule description: 'Second rule' do example name: 'Do NOT talk about the fight club' do - step 'text' + step 'step 2' end end end diff --git a/spec/cucumber/core/test/location_spec.rb b/spec/cucumber/core/test/location_spec.rb index e3d01d5c..cf58b118 100644 --- a/spec/cucumber/core/test/location_spec.rb +++ b/spec/cucumber/core/test/location_spec.rb @@ -53,8 +53,7 @@ module Test describe '#match?' do let(:matching) { described_class.new(file, line) } let(:same_file_other_line) { described_class.new(file, double) } - let(:not_matching) { described_class.new(other_file, line) } - let(:other_file) { double } + let(:not_matching) { described_class.new(double, line) } context 'with a precise location' do let(:precise) { described_class.new(file, line) } diff --git a/spec/cucumber/core/test/locations_filter_spec.rb b/spec/cucumber/core/test/locations_filter_spec.rb index a3993341..50e37d14 100644 --- a/spec/cucumber/core/test/locations_filter_spec.rb +++ b/spec/cucumber/core/test/locations_filter_spec.rb @@ -10,6 +10,7 @@ include Cucumber::Core::Gherkin::Writer include Cucumber::Core + let(:file) { 'features/path/to/the.feature' } let(:spy_receiver) do Class.new do def test_case(test_case) @@ -28,48 +29,84 @@ def test_cases end end let(:receiver) { spy_receiver.new } + let(:doc) do - gherkin('features/test.feature') do - feature do - scenario 'x' do - step 'step for scenario x' - end + Cucumber::Core::Gherkin::Document.new(file, <<-FEATURE) + Feature: + Background: + Given background + + Scenario: one + Given one a + + # comment + @tags + Scenario: two + Given two a + And two b + + Scenario: three + Given three b + + Scenario: with docstring + Given a docstring + """ + this is a docstring + """ + + Scenario: with a table + Given a table + | a | b | + | 1 | 2 | + | 3 | 4 | + + Rule: A rule with a background + Background: A background rule + Given background - scenario 'y' do - step 'step for scenario y' - end - end - end + Scenario: with a rule and background + Given a rule with a background + + Scenario: another with a rule and background + Given a rule with a background + + Rule: A rule without a background + Scenario: with a rule and no background + Given a rule without a background + + Scenario: another with a rule and no background + Given a rule without a background + FEATURE end def to_location(file, line = nil) Cucumber::Core::Test::Location.new(file, line) end + def test_case_named(name) + test_cases.detect { |tc| tc.name == name } + end + it 'filters by the given locations' do - locations = [to_location('features/test.feature', 6), to_location('features/test.feature', 3)] + locations = [to_location(file, 5), to_location(file, 10), to_location(file, 14)] filter = described_class.new(locations) compile([doc], receiver, [filter]) expect(receiver.test_case_locations).to eq(locations) end it 'returns all locations in a specific file when a specific line is omitted' do - filter = described_class.new([to_location('features/test.feature')]) + filter = described_class.new([to_location(file)]) compile([doc], receiver, [filter]) expect(receiver.test_case_locations).to eq( - [to_location('features/test.feature', 3), to_location('features/test.feature', 6)] + [ + to_location(file, 5), to_location(file, 10), to_location(file, 14), to_location(file, 17), + to_location(file, 23), to_location(file, 33), to_location(file, 36), to_location(file, 40), + to_location(file, 43) + ] ) end - it 'filters out scenarios that do not match' do - locations = [to_location('features/test.feature', 3)] - filter = described_class.new(locations) - compile([doc], receiver, [filter]) - expect(receiver.test_case_locations).to eq(locations) - end - describe 'matching location' do - let(:file) { 'features/path/to/the.feature' } let(:test_cases) do receiver = double.as_null_object result = [] @@ -79,59 +116,6 @@ def to_location(file, line = nil) end context 'with a scenario' do - let(:doc) do - Cucumber::Core::Gherkin::Document.new(file, <<-FEATURE) - Feature: - Background: - Given background - - Scenario: one - Given one a - - # comment - @tags - Scenario: two - Given two a - And two b - - Scenario: three - Given three b - - Scenario: with docstring - Given a docstring - """ - this is a docstring - """ - - Scenario: with a table - Given a table - | a | b | - | 1 | 2 | - | 3 | 4 | - - Rule: A rule with a background - Background: A background rule - Given background - - Scenario: with a rule and background - Given a rule with a background - - Scenario: another with a rule and background - Given a rule with a background - - Rule: A rule without a background - Scenario: with a rule and no background - Given a rule without a background - - Scenario: another with a rule and no background - Given a rule without a background - FEATURE - end - - def test_case_named(name) - test_cases.detect { |tc| tc.name == name } - end - it 'matches the feature keyword location to all scenarios' do locations = [to_location(file, 1)] filter = described_class.new(locations) @@ -247,67 +231,64 @@ def test_case_named(name) compile([doc], receiver, [filter]) expect(receiver.test_case_locations).to eq([]) end + end - context 'with a docstring' do - it 'matches a location at the start the docstring' do - locations = [to_location(file, 17)] - filter = described_class.new(locations) - compile([doc], receiver, [filter]) + context 'with a docstring' do + it 'matches a location at the start the docstring' do + locations = [to_location(file, 17)] + filter = described_class.new(locations) + compile([doc], receiver, [filter]) - expect(receiver.test_case_locations).to eq([test_case_named('with docstring').location]) - end + expect(receiver.test_case_locations).to eq([test_case_named('with docstring').location]) + end - it 'matches a location in the middle of the docstring' do - locations = [to_location(file, 18)] - filter = described_class.new(locations) - compile([doc], receiver, [filter]) + it 'matches a location in the middle of the docstring' do + locations = [to_location(file, 18)] + filter = described_class.new(locations) + compile([doc], receiver, [filter]) - expect(receiver.test_case_locations).to eq([test_case_named('with docstring').location]) - end + expect(receiver.test_case_locations).to eq([test_case_named('with docstring').location]) + end - it 'matches a location at the end of the docstring' do - locations = [to_location(file, 19)] - filter = described_class.new(locations) - compile([doc], receiver, [filter]) + it 'matches a location at the end of the docstring' do + locations = [to_location(file, 19)] + filter = described_class.new(locations) + compile([doc], receiver, [filter]) - expect(receiver.test_case_locations).to eq([test_case_named('with docstring').location]) - end + expect(receiver.test_case_locations).to eq([test_case_named('with docstring').location]) end + end - context 'with a table' do - let(:test_case) { test_cases.detect { |tc| tc.name == 'with a table' } } - let(:starting_location) { to_location(file, 23) } - let(:midpoint_location) { to_location(file, 24) } - let(:ending_location) { to_location(file, 25) } + context 'with a table' do + let(:test_case) { test_cases.detect { |tc| tc.name == 'with a table' } } - it 'matches a location at the start of the table' do - filter = described_class.new([starting_location]) - compile([doc], receiver, [filter]) - expect(receiver.test_case_locations).to eq([test_case_named('with a table').location]) - end + it 'matches a location at the start of the table' do + filter = described_class.new([to_location(file, 23)]) + compile([doc], receiver, [filter]) + expect(receiver.test_case_locations).to eq([test_case_named('with a table').location]) + end - it 'matches a location at the middle of the table' do - filter = described_class.new([midpoint_location]) - compile([doc], receiver, [filter]) - expect(receiver.test_case_locations).to eq([test_case_named('with a table').location]) - end + it 'matches a location at the middle of the table' do + filter = described_class.new([to_location(file, 24)]) + compile([doc], receiver, [filter]) + expect(receiver.test_case_locations).to eq([test_case_named('with a table').location]) + end - it 'matches a location at the end of the table' do - filter = described_class.new([ending_location]) - compile([doc], receiver, [filter]) - expect(receiver.test_case_locations).to eq([test_case_named('with a table').location]) - end + it 'matches a location at the end of the table' do + filter = described_class.new([to_location(file, 25)]) + compile([doc], receiver, [filter]) + expect(receiver.test_case_locations).to eq([test_case_named('with a table').location]) end + end - context 'with duplicate locations in the filter' do - it 'matches each test case only once' do - location_tc_two = test_case_named('two').location - location_tc_one = test_case_named('one').location - location_last_step_tc_two = to_location(file, 12) - filter = described_class.new([location_tc_two, location_tc_one, location_last_step_tc_two]) - compile([doc], receiver, [filter]) - expect(receiver.test_case_locations).to eq([test_case_named('two').location, test_case_named('one').location]) - end + context 'with duplicate locations in the filter' do + it 'matches each test case only once' do + location_tc_two = test_case_named('two').location + location_tc_one = test_case_named('one').location + location_last_step_tc_two = to_location(file, 12) + filter = described_class.new([location_tc_two, location_tc_one, location_last_step_tc_two]) + compile([doc], receiver, [filter]) + expect(receiver.test_case_locations).to eq([test_case_named('two').location, test_case_named('one').location]) end end @@ -346,38 +327,32 @@ def test_case_named(name) let(:test_case) { test_cases.detect { |tc| tc.name == 'two b' } } - let(:feature_location) { to_location(file, 1) } - let(:row_location) { to_location(file, 19) } - let(:start_of_outline_location) { to_location(file, 8) } - let(:middle_of_outline_location) { to_location(file, 10) } - let(:outline_tags_location) { to_location(file, 7) } - it 'matches the feature line to all scenarios' do - filter = described_class.new([feature_location]) + filter = described_class.new([to_location(file, 1)]) compile [doc], receiver, [filter] expect(receiver.test_case_locations).to eq(test_cases.map(&:location)) end it 'matches row location to the test case of the row' do - filter = described_class.new([row_location]) + filter = described_class.new([to_location(file, 19)]) compile([doc], receiver, [filter]) expect(receiver.test_case_locations).to eq([test_case.location]) end it 'matches outline location with the all test cases of all the tables' do - filter = described_class.new([start_of_outline_location]) + filter = described_class.new([to_location(file, 8)]) compile([doc], receiver, [filter]) expect(receiver.test_case_locations.map(&:line)).to eq([19, 23, 24]) end it 'matches a location on a step of the scenario outline with all test cases of all the tables' do - filter = described_class.new([middle_of_outline_location]) + filter = described_class.new([to_location(file, 10)]) compile([doc], receiver, [filter]) expect(receiver.test_case_locations.map(&:line)).to eq([19, 23, 24]) end it "matches a location on the scenario outline's tags with all test cases of all the tables" do - filter = described_class.new([outline_tags_location]) + filter = described_class.new([to_location(file, 7)]) compile([doc], receiver, [filter]) expect(receiver.test_case_locations.map(&:line)).to eq([19, 23, 24]) end diff --git a/spec/cucumber/core/test/result/failed_spec.rb b/spec/cucumber/core/test/result/failed_spec.rb index 38c1d0b2..e3f700af 100644 --- a/spec/cucumber/core/test/result/failed_spec.rb +++ b/spec/cucumber/core/test/result/failed_spec.rb @@ -4,20 +4,16 @@ require 'support/duration_matcher' describe Cucumber::Core::Test::Result::Failed do - subject(:result) { described_class.new(duration, exception) } + subject(:result) { described_class.new(duration, StandardError.new('error message')) } let(:duration) { Cucumber::Core::Test::Result::Duration.new(1 * 1_000 * 1_000) } - let(:exception) { StandardError.new('error message') } let(:visitor) { double } - let(:args) { double } let(:filter_class) { double } let(:filter) { double } let(:filtered_exception) { double } before do - allow(visitor).to receive(:failed) - allow(visitor).to receive(:duration) - allow(visitor).to receive(:exception) + allow(visitor).to receive_messages(failed: nil, duration: nil, exception: nil) end it 'does nothing if step has no backtrace line' do @@ -49,15 +45,15 @@ describe '#describe_to' do it 'is described as a failing test' do - expect(visitor).to receive(:failed).with(args) + expect(visitor).to receive(:failed).with([1, 2, 3]) - result.describe_to(visitor, args) + result.describe_to(visitor, [1, 2, 3]) end it 'contains an exception message' do - expect(visitor).to receive(:exception).with(exception, args) + expect(visitor).to receive(:exception).with(result.exception, %w[foo bar baz]) - result.describe_to(visitor, args) + result.describe_to(visitor, %w[foo bar baz]) end end diff --git a/spec/cucumber/core/test/runner_spec.rb b/spec/cucumber/core/test/runner_spec.rb index 5f676e87..91a35724 100644 --- a/spec/cucumber/core/test/runner_spec.rb +++ b/spec/cucumber/core/test/runner_spec.rb @@ -302,108 +302,108 @@ end test_case.describe_to(runner) end + end - context 'with an undefined step and a subsequent ambiguous step' do - let(:test_steps) { [undefined_step, ambiguous_step] } + context 'with an undefined step and a subsequent ambiguous step' do + let(:test_steps) { [undefined_step, ambiguous_step] } - it 'emits a test_step_finished event when executing an undefined step' do - expect(event_bus).to receive(:test_step_finished).with(undefined_step, anything) do |reported_test_step, _result| - expect(reported_test_step).to be_a(Cucumber::Core::Test::Step) - end - test_case.describe_to(runner) + it 'emits a test_step_finished event when executing an undefined step' do + expect(event_bus).to receive(:test_step_finished).with(undefined_step, anything) do |reported_test_step, _result| + expect(reported_test_step).to be_a(Cucumber::Core::Test::Step) end + test_case.describe_to(runner) + end - it 'emits a test_step_finished event with an undefined result' do - expect(event_bus).to receive(:test_step_finished).with(undefined_step, anything) do |_reported_test_step, result| - expect(result).to be_undefined - end - test_case.describe_to(runner) + it 'emits a test_step_finished event with an undefined result' do + expect(event_bus).to receive(:test_step_finished).with(undefined_step, anything) do |_reported_test_step, result| + expect(result).to be_undefined end + test_case.describe_to(runner) + end - it 'skips, rather than executing the second step' do - expect(passing_step).not_to receive(:execute) + it 'skips, rather than executing the second step' do + expect(passing_step).not_to receive(:execute) - allow(passing_step).to receive(:skip).and_return(Cucumber::Core::Test::Result::Skipped.new) - test_case.describe_to(runner) - end + allow(passing_step).to receive(:skip).and_return(Cucumber::Core::Test::Result::Skipped.new) + test_case.describe_to(runner) + end - it 'emits a test_step_finished event when executing a skipped step' do - expect(event_bus).to receive(:test_step_finished).with(ambiguous_step, anything) do |reported_test_step, _result| - expect(reported_test_step).to be_a(Cucumber::Core::Test::Step) - end - test_case.describe_to(runner) + it 'emits a test_step_finished event when executing a skipped step' do + expect(event_bus).to receive(:test_step_finished).with(ambiguous_step, anything) do |reported_test_step, _result| + expect(reported_test_step).to be_a(Cucumber::Core::Test::Step) end + test_case.describe_to(runner) + end - it 'emits a test_step_finished event with an ambiguous result' do - expect(event_bus).to receive(:test_step_finished).with(ambiguous_step, anything) do |_reported_test_step, result| - expect(result).to be_ambiguous - end - test_case.describe_to(runner) + it 'emits a test_step_finished event with an ambiguous result' do + expect(event_bus).to receive(:test_step_finished).with(ambiguous_step, anything) do |_reported_test_step, result| + expect(result).to be_ambiguous end + test_case.describe_to(runner) + end - it 'emits a test_case_finished event with an ambiguous result' do - expect(event_bus).to receive(:test_case_finished) do |_reported_test_case, result| - expect(result).to be_ambiguous - end - test_case.describe_to(runner) + it 'emits a test_case_finished event with an ambiguous result' do + expect(event_bus).to receive(:test_case_finished) do |_reported_test_case, result| + expect(result).to be_ambiguous end + test_case.describe_to(runner) + end - it 'emits a test_case_finished event with an exception object' do - expect(event_bus).to receive(:test_case_finished) do |_reported_test_case, result| - expect(result.exception).to be_a StandardError - end - test_case.describe_to(runner) + it 'emits a test_case_finished event with an exception object' do + expect(event_bus).to receive(:test_case_finished) do |_reported_test_case, result| + expect(result.exception).to be_a StandardError end + test_case.describe_to(runner) end + end - context 'with a failing after hook' do - let(:test_steps) { [undefined_step, failing_hook] } + context 'with a failing after hook' do + let(:test_steps) { [undefined_step, failing_hook] } - it 'emits a test_step_finished event when executing an undefined step' do - expect(event_bus).to receive(:test_step_finished).with(undefined_step, anything) do |reported_test_step, _result| - expect(reported_test_step).to be_a(Cucumber::Core::Test::Step) - end - test_case.describe_to(runner) + it 'emits a test_step_finished event when executing an undefined step' do + expect(event_bus).to receive(:test_step_finished).with(undefined_step, anything) do |reported_test_step, _result| + expect(reported_test_step).to be_a(Cucumber::Core::Test::Step) end + test_case.describe_to(runner) + end - it 'emits a test_step_finished event with an undefined result' do - expect(event_bus).to receive(:test_step_finished).with(undefined_step, anything) do |_reported_test_step, result| - expect(result).to be_undefined - end - test_case.describe_to(runner) + it 'emits a test_step_finished event with an undefined result' do + expect(event_bus).to receive(:test_step_finished).with(undefined_step, anything) do |_reported_test_step, result| + expect(result).to be_undefined end + test_case.describe_to(runner) + end - it 'emits a test_step_finished event with a failing result' do - expect(event_bus).to receive(:test_step_finished).with(failing_hook, anything) do |_reported_test_step, result| - expect(result).to be_failed - end - test_case.describe_to(runner) + it 'emits a test_step_finished event with a failing result' do + expect(event_bus).to receive(:test_step_finished).with(failing_hook, anything) do |_reported_test_step, result| + expect(result).to be_failed end + test_case.describe_to(runner) + end - it 'emits a test_case_finished event with a failing result' do - expect(event_bus).to receive(:test_case_finished) do |_reported_test_case, result| - expect(result).to be_failed - end - test_case.describe_to(runner) + it 'emits a test_case_finished event with a failing result' do + expect(event_bus).to receive(:test_case_finished) do |_reported_test_case, result| + expect(result).to be_failed end + test_case.describe_to(runner) + end - it 'emits a test_case_finished event with an exception object' do - expect(event_bus).to receive(:test_case_finished) do |_reported_test_case, result| - expect(result.exception).to be_a StandardError - end - test_case.describe_to(runner) + it 'emits a test_case_finished event with an exception object' do + expect(event_bus).to receive(:test_case_finished) do |_reported_test_case, result| + expect(result.exception).to be_a StandardError end + test_case.describe_to(runner) + end - it 'calls skip, rather than execute on test step of the hook' do - expect(failing_hook).not_to receive(:execute) + it 'calls skip, rather than execute on test step of the hook' do + expect(failing_hook).not_to receive(:execute) - allow(failing_hook).to receive(:skip).and_return( - Cucumber::Core::Test::Result::Failed.new( - Cucumber::Core::Test::Result::UnknownDuration.new, instance_double(StandardError, backtrace: [], message: nil) - ) + allow(failing_hook).to receive(:skip).and_return( + Cucumber::Core::Test::Result::Failed.new( + Cucumber::Core::Test::Result::UnknownDuration.new, instance_double(StandardError, backtrace: [], message: nil) ) - test_case.describe_to(runner) - end + ) + test_case.describe_to(runner) end end end @@ -414,10 +414,10 @@ let(:test_cases) { [first_test_case, last_test_case] } it 'reports the results correctly for test cases after a failing test case' do - allow(event_bus).to receive(:test_case_finished) { |reported_test_case, result| + allow(event_bus).to receive(:test_case_finished) do |reported_test_case, result| expect(result).to be_failed if reported_test_case == first_test_case expect(result).to be_passed if reported_test_case == last_test_case - }.twice + end.twice test_cases.each { |test_case| test_case.describe_to(runner) } end