From a24f2dda2b2de68d97c9f37af019af36ac8a2c48 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 11:03:45 +0100 Subject: [PATCH 01/15] For pretty spec remove all multiple expectation cop failures for snippet based tests --- spec/cucumber/formatter/pretty_spec.rb | 53 ++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/spec/cucumber/formatter/pretty_spec.rb b/spec/cucumber/formatter/pretty_spec.rb index 63279c812..9534973d7 100644 --- a/spec/cucumber/formatter/pretty_spec.rb +++ b/spec/cucumber/formatter/pretty_spec.rb @@ -857,23 +857,53 @@ module Formatter Scenario: many monkeys eat many things Given there are bananas and apples And other monkeys are around + But there was only one chimpanzee When one monkey eats a banana And the other monkeys eat all the apples + But the chimpanzee ate nothing Then bananas remain But there are no apples left + And there was never any marshmallows FEATURE - it "contains snippets with 'And' or 'But' replaced by previous step name" do + it "offers the exact snippet of a 'Given' step name" do expect(@out.string).to include("Given('there are bananas and apples')") + end + + it "replaces snippets containing 'And' to the previous 'Given' step name" do expect(@out.string).to include("Given('other monkeys are around')") + end + + it "replaces snippets containing 'But' to the previous 'Given' step name" do + expect(@out.string).to include("Given('there was only one chimpanzee')") + end + + it "offers the exact snippet of a 'When' step name" do expect(@out.string).to include("When('one monkey eats a banana')") + end + + it "replaces snippets containing 'And' to the previous 'When' step name" do expect(@out.string).to include("When('the other monkeys eat all the apples')") + end + + it "replaces snippets containing 'But' to the previous 'When' step name" do + expect(@out.string).to include("When('the chimpanzee ate nothing')") + end + + it "offers the exact snippet of a 'Then' step name" do expect(@out.string).to include("Then('bananas remain')") + end + + it "replaces snippets containing 'But' to the previous 'Then' step name" do expect(@out.string).to include("Then('there are no apples left')") end + + it "replaces snippets containing 'And' to the previous 'Then' step name" do + expect(@out.string).to include("Then('there was never any marshmallows')") + end end - describe "With a scenario that uses * and 'But'" do + describe "With a scenario that uses *" do define_feature <<-FEATURE Feature: Banana party @@ -885,13 +915,20 @@ module Formatter Then bananas remain * there are no apples left FEATURE + it "replaces the first step with 'Given'" do expect(@out.string).to include("Given('there are bananas and apples')") end - it "uses actual keywords as the 'previous' keyword for future replacements" do + it "uses actual keywords as the previous 'Given' keyword for future replacements" do expect(@out.string).to include("Given('other monkeys are around')") + end + + it "uses actual keywords as the previous 'When' keyword for future replacements" do expect(@out.string).to include("When('the other monkeys eat all the apples')") + end + + it "uses actual keywords as the previous 'Then' keyword for future replacements" do expect(@out.string).to include("Then('there are no apples left')") end end @@ -905,9 +942,11 @@ module Formatter Then this step passes And this step is undefined FEATURE + define_steps do Given('this step passes') {} end + it 'uses actual keyword of the previous passing step for the undefined step' do expect(@out.string).to include("Then('this step is undefined')") end @@ -925,11 +964,16 @@ module Formatter * this step is also undefined Then this step passes FEATURE + define_steps do Given('this step passes') {} end - it "uses 'Given' as actual keyword the step in each scenario" do + + it "uses 'Given' as the actual keyword for the step in the first scenario" do expect(@out.string).to include("Given('this step is undefined')") + end + + it "uses 'Given' as the actual keyword for the step in the last scenario" do expect(@out.string).to include("Given('this step is also undefined')") end end @@ -943,6 +987,7 @@ module Formatter I CAN HAZ IN TEH BEGINNIN CUCUMBRZ AN I EAT CUCUMBRZ FEATURE + it 'uses actual keyword of the previous passing step for the undefined step' do expect(@out.string).to include("ICANHAZ('I EAT CUCUMBRZ')") end From b58c54c0265d6690f0e8844fac1d81d79805021b Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 11:07:42 +0100 Subject: [PATCH 02/15] Linting tidy for pretty spec --- spec/cucumber/formatter/pretty_spec.rb | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/spec/cucumber/formatter/pretty_spec.rb b/spec/cucumber/formatter/pretty_spec.rb index 9534973d7..1b21adc7b 100644 --- a/spec/cucumber/formatter/pretty_spec.rb +++ b/spec/cucumber/formatter/pretty_spec.rb @@ -32,11 +32,11 @@ module Formatter FEATURE it 'outputs the scenario name' do - expect(@out.string).to include 'Scenario: Monkey eats banana' + expect(@out.string).to include('Scenario: Monkey eats banana') end it 'outputs the step' do - expect(@out.string).to include 'Given there are bananas' + expect(@out.string).to include('Given there are bananas') end end @@ -56,11 +56,11 @@ module Formatter end it 'outputs the scenario name' do - expect(@out.string).to include 'Scenario: Monkey eats banana' + expect(@out.string).to include('Scenario: Monkey eats banana') end it 'outputs the step' do - expect(@out.string).to include 'Given there are bananas' + expect(@out.string).to include('Given there are bananas') end end @@ -92,17 +92,18 @@ module Formatter | broccoli | | carrots | OUTPUT + lines.split("\n").each do |line| - expect(@out.string).to include line.strip + expect(@out.string).to include(line.strip) end end it 'has 4 undefined scenarios' do - expect(@out.string).to include '4 scenarios (4 undefined)' + expect(@out.string).to include('4 scenarios (4 undefined)') end it 'has 4 undefined steps' do - expect(@out.string).to include '4 steps (4 undefined)' + expect(@out.string).to include('4 steps (4 undefined)') end context 'when the examples table header is wider than the rows' do @@ -123,6 +124,7 @@ module Formatter | Types of monkey | | Hominidae | OUTPUT + lines.split("\n").each do |line| expect(@out.string).to include line.strip end @@ -156,6 +158,7 @@ module Formatter | things | | apples | OUTPUT + lines.split("\n").each do |line| expect(@out.string).to include line.strip end @@ -555,6 +558,7 @@ module Formatter | broccoli | | carrots | OUTPUT + lines.split("\n").each do |line| expect(@out.string).to include line.strip end @@ -717,6 +721,7 @@ module Formatter Example: | carrots | Given there are carrots OUTPUT + lines.split("\n").each do |line| expect(@out.string).to include line.strip end @@ -755,6 +760,7 @@ module Formatter DEN I HAS 2 CUCUMBERZ IN MAH BELLY AN IN TEH END 1 CUCUMBRZ KTHXBAI OUTPUT + lines.split("\n").each do |line| expect(@out.string).to include line.strip end @@ -809,6 +815,7 @@ module Formatter Example: | carrots | # spec.feature:13 Given there are carrots # spec.feature:13 OUTPUT + lines.split("\n").each do |line| expect(@out.string).to include line.strip end @@ -833,8 +840,9 @@ module Formatter Given there are Hominidae # spec.feature:8 OUTPUT + lines.split("\n").each do |line| - expect(@out.string).to include line.strip + expect(@out.string).to include(line.strip) end end end From ad167c626a24fde587c33f49ccdde4642820e4f4 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 11:10:36 +0100 Subject: [PATCH 03/15] Cleanup of file loading tests to ensure that tests only test one thing --- spec/cucumber/glue/registry_and_more_spec.rb | 26 +++----------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/spec/cucumber/glue/registry_and_more_spec.rb b/spec/cucumber/glue/registry_and_more_spec.rb index 093bb83c6..077cd2932 100644 --- a/spec/cucumber/glue/registry_and_more_spec.rb +++ b/spec/cucumber/glue/registry_and_more_spec.rb @@ -9,9 +9,7 @@ module Glue describe StepDefinition do let(:user_interface) { double('user interface') } let(:registry) { support_code.registry } - let(:support_code) do - Cucumber::Runtime::SupportCode.new(user_interface) - end + let(:support_code) { Cucumber::Runtime::SupportCode.new(user_interface) } let(:dsl) do registry Object.new.extend(Glue::Dsl) @@ -60,9 +58,6 @@ def a_file_called(name) it 'does not re-load the file when called multiple times' do a_file_called('tmp1.rb') { value1 } registry.load_code_file('tmp1.rb') - - expect(Foo.value).to eq(1) - a_file_called('tmp1.rb') { value2 } registry.load_code_file('tmp1.rb') @@ -80,16 +75,11 @@ def a_file_called(name) end context 'when using `use_legacy_autoloader`' do - before(:each) do - allow(Cucumber).to receive(:use_legacy_autoloader).and_return(true) - end + before(:each) { allow(Cucumber).to receive(:use_legacy_autoloader).and_return(true) } it 're-loads the file when called multiple times' do a_file_called('tmp2.rb') { value1 } registry.load_code_file('tmp2.rb') - - expect(Foo.value).to eq(1) - a_file_called('tmp2.rb') { value2 } registry.load_code_file('tmp2.rb') @@ -107,20 +97,12 @@ def a_file_called(name) end context 'when explicitly NOT using `use_legacy_autoloader`' do - before(:each) do - allow(Cucumber).to receive(:use_legacy_autoloader).and_return(false) - end - - after(:each) do - FileUtils.rm_rf('tmp3.rb') - end + before(:each) { allow(Cucumber).to receive(:use_legacy_autoloader).and_return(false) } + after(:each) { FileUtils.rm_rf('tmp3.rb') } it 'does not re-load the file when called multiple times' do a_file_called('tmp3.rb') { value1 } registry.load_code_file('tmp3.rb') - - expect(Foo.value).to eq(1) - a_file_called('tmp3.rb') { value2 } registry.load_code_file('tmp3.rb') From 46f4b0583aff6525b574551868c08423f5c3e746 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 11:15:45 +0100 Subject: [PATCH 04/15] Simplify test for multiple worlds --- spec/cucumber/glue/registry_and_more_spec.rb | 21 ++------------------ 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/spec/cucumber/glue/registry_and_more_spec.rb b/spec/cucumber/glue/registry_and_more_spec.rb index 077cd2932..8703c7fc0 100644 --- a/spec/cucumber/glue/registry_and_more_spec.rb +++ b/spec/cucumber/glue/registry_and_more_spec.rb @@ -124,14 +124,7 @@ def a_file_called(name) it 'raises an error if the world is nil' do dsl.World {} - begin - registry.begin_scenario(nil) - raise 'Should fail' - rescue Glue::NilWorld => e - expect(e.message).to eq 'World procs should never return nil' - expect(e.backtrace.length).to eq(1) - expect(e.backtrace[0]).to match(/spec\/cucumber\/glue\/registry_and_more_spec\.rb:\d+:in `World'/) - end + expect { registry.begin_scenario(nil) }.to raise_error(Glue::NilWorld).with_message('World procs should never return nil') end it 'implicitly extends the world with modules' do @@ -147,19 +140,9 @@ class << registry.current_world end it 'raises error when we try to register more than one World proc' do - expected_error = %(You can only pass a proc to #World once, but it's happening -in 2 places: - -spec/cucumber/glue/registry_and_more_spec.rb:\\d+:in `World' -spec/cucumber/glue/registry_and_more_spec.rb:\\d+:in `World' - -Use Ruby modules instead to extend your worlds. See the Cucumber::Glue::Dsl#World RDoc -or http://wiki.github.com/cucumber/cucumber/a-whole-new-world. - -) dsl.World { {} } - expect { dsl.World { [] } }.to raise_error(Glue::MultipleWorld, /#{expected_error}/) + expect { dsl.World { [] } }.to raise_error(Glue::MultipleWorld, /^You can only pass a proc to #World once/) end end From f9075d54ce48d7c7a4eaebde62a0df7fb10b9880 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 11:45:39 +0100 Subject: [PATCH 05/15] Final tweaks to registry and more spec to resolve all specs only having 1 assertion --- spec/cucumber/glue/registry_and_more_spec.rb | 67 +++++++++----------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/spec/cucumber/glue/registry_and_more_spec.rb b/spec/cucumber/glue/registry_and_more_spec.rb index 8703c7fc0..ab09cf482 100644 --- a/spec/cucumber/glue/registry_and_more_spec.rb +++ b/spec/cucumber/glue/registry_and_more_spec.rb @@ -133,9 +133,14 @@ def a_file_called(name) class << registry.current_world extend RSpec::Matchers - expect(included_modules.inspect).to match(/ModuleOne/) # Workaround for RSpec/Ruby 1.9 issue with namespaces - expect(included_modules.inspect).to match(/ModuleTwo/) + expect(included_modules).to include(FakeObjects::ModuleOne).and include(FakeObjects::ModuleTwo) end + end + + it 'places the current world inside the `Object` superclass' do + dsl.World(FakeObjects::ModuleOne, FakeObjects::ModuleTwo) + registry.begin_scenario(double('scenario').as_null_object) + expect(registry.current_world.class).to eq(Object) end @@ -147,54 +152,47 @@ class << registry.current_world end describe 'Handling namespaced World' do - it 'extends the world with namespaces' do + it 'can still handle top level methods inside the world the world with namespaces' do dsl.World(FakeObjects::ModuleOne, module_two: FakeObjects::ModuleTwo, module_three: FakeObjects::ModuleThree) registry.begin_scenario(double('scenario').as_null_object) - class << registry.current_world - extend RSpec::Matchers - expect(included_modules.inspect).to match(/ModuleOne/) - end - expect(registry.current_world.class).to eq(Object) + expect(registry.current_world).to respond_to(:method_one) + end + + it 'can scope calls to a specific namespaced module' do + dsl.World(FakeObjects::ModuleOne, module_two: FakeObjects::ModuleTwo, module_three: FakeObjects::ModuleThree) + registry.begin_scenario(double('scenario').as_null_object) - expect(registry.current_world.module_two.class).to eq(Object) expect(registry.current_world.module_two).to respond_to(:method_two) + end + + it 'can scope calls to a different specific namespaced module' do + dsl.World(FakeObjects::ModuleOne, module_two: FakeObjects::ModuleTwo, module_three: FakeObjects::ModuleThree) + registry.begin_scenario(double('scenario').as_null_object) - expect(registry.current_world.module_three.class).to eq(Object) expect(registry.current_world.module_three).to respond_to(:method_three) end - it 'allows to inspect the included modules' do + it 'can show all the namespaced included modules' do dsl.World(FakeObjects::ModuleOne, module_two: FakeObjects::ModuleTwo, module_three: FakeObjects::ModuleThree) registry.begin_scenario(double('scenario').as_null_object) - class << registry.current_world - extend RSpec::Matchers - end - expect(registry.current_world.inspect).to match(/ModuleOne/) - expect(registry.current_world.inspect).to include('ModuleTwo (as module_two)') - expect(registry.current_world.inspect).to include('ModuleThree (as module_three)') + + expect(registry.current_world.inspect).to include('ModuleTwo (as module_two)').and include('ModuleThree (as module_three)') end it 'merges methods when assigning different modules to the same namespace' do dsl.World(namespace: FakeObjects::ModuleOne) dsl.World(namespace: FakeObjects::ModuleTwo) registry.begin_scenario(double('scenario').as_null_object) - class << registry.current_world - extend RSpec::Matchers - end - expect(registry.current_world.namespace).to respond_to(:method_one) - expect(registry.current_world.namespace).to respond_to(:method_two) + + expect(registry.current_world.namespace).to respond_to(:method_one).and respond_to(:method_two) end - it 'resolves conflicts when assigning different modules to the same namespace' do + it 'will resolve conflicts and use the latest defined definition when assigning different modules to the same namespace' do dsl.World(namespace: FakeObjects::ModuleOne) dsl.World(namespace: FakeObjects::ModuleMinusOne) registry.begin_scenario(double('scenario').as_null_object) - class << registry.current_world - extend RSpec::Matchers - end - expect(registry.current_world.namespace).to respond_to(:method_one) expect(registry.current_world.namespace.method_one).to eq(-1) end end @@ -206,22 +204,19 @@ class << registry.current_world scenario = double('Scenario') - expect(scenario).to receive(:accept_hook?).with(fish) { true } - expect(scenario).to receive(:accept_hook?).with(meat) { false } + allow(scenario).to receive(:accept_hook?).with(fish) { true } + allow(scenario).to receive(:accept_hook?).with(meat) { false } expect(registry.hooks_for(:before, scenario)).to eq([fish]) end it 'finds around hooks' do - a = dsl.Around do |scenario, block| - end - - b = dsl.Around('@tag') do |scenario, block| - end + a = dsl.Around {} + b = dsl.Around('@tag') {} scenario = double('Scenario') - expect(scenario).to receive(:accept_hook?).with(a) { true } - expect(scenario).to receive(:accept_hook?).with(b) { false } + allow(scenario).to receive(:accept_hook?).with(a) { true } + allow(scenario).to receive(:accept_hook?).with(b) { false } expect(registry.hooks_for(:around, scenario)).to eq([a]) end end From 055c7e6f731580fdf13ee9119f722c1ae9db7db0 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 12:09:27 +0100 Subject: [PATCH 06/15] Remove all duplicate expectations from meta_message_builder --- lib/cucumber/runtime/meta_message_builder.rb | 4 +- .../runtime/meta_message_builder_spec.rb | 55 +++++++++++++++---- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/lib/cucumber/runtime/meta_message_builder.rb b/lib/cucumber/runtime/meta_message_builder.rb index e1322b6b1..a412b018e 100644 --- a/lib/cucumber/runtime/meta_message_builder.rb +++ b/lib/cucumber/runtime/meta_message_builder.rb @@ -5,14 +5,14 @@ module Cucumber class Runtime - # Builder to instanciate a Cucumber::Messages::Meta message filled-in with + # Builder to instantiate a Cucumber::Messages::Meta message filled-in with # the runtime meta-data: # - protocol version: the version of the Cucumber::Messages protocol # - implementation: the name and version of the implementation (e.g. cucumber-ruby 8.0.0) # - runtime: the name and version of the runtime (e.g. ruby 3.0.1) # - os: the name and version of the operating system (e.g. linux 3.13.0-45-generic) # - cpu: the name of the CPU (e.g. x86_64) - # - ci: informtion about the CI environment if any, including: + # - ci: information about the CI environment if any, including: # - name: the name of the CI environment (e.g. Jenkins) # - url: the URL of the CI environment (e.g. https://ci.example.com) # - build_number: the build number of the CI environment (e.g. 123) diff --git a/spec/cucumber/runtime/meta_message_builder_spec.rb b/spec/cucumber/runtime/meta_message_builder_spec.rb index b6ceacdb7..8a18c6d39 100644 --- a/spec/cucumber/runtime/meta_message_builder_spec.rb +++ b/spec/cucumber/runtime/meta_message_builder_spec.rb @@ -4,39 +4,59 @@ require 'cucumber/runtime/meta_message_builder' describe Cucumber::Runtime::MetaMessageBuilder do - describe 'self#build_meta_message' do + describe '.build_meta_message' do subject { described_class.build_meta_message } it { is_expected.to be_a(Cucumber::Messages::Meta) } - it 'fills system info in the meta message' do + it 'has a protocol version' do expect(subject.protocol_version).to eq(Cucumber::Messages::VERSION) + end + + it 'has an implementation name' do expect(subject.implementation.name).to eq('cucumber-ruby') + end + + it 'has an implementation version' do expect(subject.implementation.version).to eq(Cucumber::VERSION) + end + + it 'has a runtime name' do expect(subject.runtime.name).to eq(RUBY_ENGINE) + end + + it 'has a runtime version' do expect(subject.runtime.version).to eq(RUBY_VERSION) + end + + it 'has an os name' do expect(subject.os.name).to eq(RbConfig::CONFIG['target_os']) + end + + it 'has an os version' do expect(subject.os.version).to eq(Sys::Uname.uname.version) + end + + it 'has a cpu name' do expect(subject.cpu.name).to eq(RbConfig::CONFIG['target_cpu']) end - context 'with overriden ENV' do + context 'with an overridden ENV hash' do subject { described_class.build_meta_message(env) } let(:env) { {} } it 'detects CI environment using the given env' do expect(Cucumber::CiEnvironment).to receive(:detect_ci_environment).with(env) + subject end end - describe ':ci' do + describe ':ci hash' do subject { described_class.build_meta_message.ci } - before do - expect(Cucumber::CiEnvironment).to receive(:detect_ci_environment).and_return(ci_data) - end + before { expect(Cucumber::CiEnvironment).to receive(:detect_ci_environment).and_return(ci_data) } context 'when running on a CI system' do let(:ci_data) do @@ -49,9 +69,15 @@ it { is_expected.to be_a(Cucumber::Messages::Ci) } - it 'fills ci data in the :ci field' do + it 'has a populated name from the ci input hash' do expect(subject.name).to eq(ci_data[:name]) + end + + it 'has a populated url from the ci input hash' do expect(subject.url).to eq(ci_data[:url]) + end + + it 'has a populated build number from the ci input hash' do expect(subject.build_number).to eq(ci_data[:buildNumber]) end @@ -72,15 +98,24 @@ it { is_expected.to be_a(Cucumber::Messages::Git) } - it 'fills the git data in the :git field' do + it 'has a populated git remote from the git field of the ci input hash' do expect(subject.remote).to eq(ci_data[:git][:remote]) + end + + it 'has a populated git revision from the git field of the ci input hash' do expect(subject.revision).to eq(ci_data[:git][:revision]) + end + + it 'has a populated git branch from the git field of the ci input hash' do expect(subject.branch).to eq(ci_data[:git][:branch]) + end + + it 'has a populated git tag from the git field of the ci input hash' do expect(subject.tag).to eq(ci_data[:git][:tag]) end end - context 'without git data' do + context 'without any git data' do it { is_expected.to be_nil } end end From 757773144d86d9246d0f182e9a39475836a882b2 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 12:38:25 +0100 Subject: [PATCH 07/15] Remove nearly all duplicate expect situations from options spec --- spec/cucumber/cli/options_spec.rb | 131 ++++++++++++++++-------------- 1 file changed, 71 insertions(+), 60 deletions(-) diff --git a/spec/cucumber/cli/options_spec.rb b/spec/cucumber/cli/options_spec.rb index 65cf43452..9eeab8fda 100644 --- a/spec/cucumber/cli/options_spec.rb +++ b/spec/cucumber/cli/options_spec.rb @@ -67,8 +67,6 @@ def with_env(name, value) end context 'with --i18n-languages' do - include RSpec::WorkInProgress - it 'lists all known languages' do after_parsing '--i18n-languages' do ::Gherkin::DIALECTS.keys.map do |key| @@ -82,27 +80,23 @@ def with_env(name, value) end end - context 'with --i18n-keywords' do - context 'with invalid LANG' do - include RSpec::WorkInProgress - - it 'exits' do - when_parsing '--i18n-keywords foo' do - expect(Kernel).to receive(:exit) - end + context 'with --i18n-keywords but an invalid LANG' do + it 'exits' do + when_parsing '--i18n-keywords foo' do + expect(Kernel).to receive(:exit) end + end - it 'says the language was invalid' do - after_parsing '--i18n-keywords foo' do - expect(@output_stream.string).to include("Invalid language 'foo'. Available languages are:") - end + it 'says the language was invalid' do + after_parsing '--i18n-keywords foo' do + expect(@output_stream.string).to include("Invalid language 'foo'. Available languages are:") end + end - it 'displays the language table' do - after_parsing '--i18n-keywords foo' do - ::Gherkin::DIALECTS.keys.map do |key| - expect(@output_stream.string).to include(key.to_s) - end + it 'displays the language table' do + after_parsing '--i18n-keywords foo' do + ::Gherkin::DIALECTS.keys.map do |key| + expect(@output_stream.string).to include(key.to_s) end end end @@ -145,28 +139,26 @@ def with_env(name, value) end context 'when handling multiple formatters' do + let(:options) { described_class.new(output_stream, error_stream, default_profile: 'default') } + it 'catches multiple command line formatters using the same stream' do expect { options.parse!(prepare_args('-f pretty -f progress')) }.to raise_error('All but one formatter must use --out, only one can print to each stream (or STDOUT)') end it 'catches multiple profile formatters using the same stream' do given_cucumber_yml_defined_as('default' => '-f progress -f pretty') - options = described_class.new(output_stream, error_stream, default_profile: 'default') expect { options.parse!(%w[]) }.to raise_error('All but one formatter must use --out, only one can print to each stream (or STDOUT)') end it 'profiles does not affect the catching of multiple command line formatters using the same stream' do given_cucumber_yml_defined_as('default' => '-q') - options = described_class.new(output_stream, error_stream, default_profile: 'default') expect { options.parse!(%w[-f progress -f pretty]) }.to raise_error('All but one formatter must use --out, only one can print to each stream (or STDOUT)') end it 'merges profile formatters and command line formatters' do given_cucumber_yml_defined_as('default' => '-f junit -o result.xml') - options = described_class.new(output_stream, error_stream, default_profile: 'default') - options.parse!(%w[-f pretty]) expect(options[:formats]).to eq [['pretty', {}, output_stream], ['junit', {}, 'result.xml']] @@ -175,19 +167,27 @@ def with_env(name, value) context 'when using -t TAGS or --tags TAGS' do it 'handles tag expressions as argument' do - after_parsing(['--tags', 'not @foo or @bar']) { expect(options[:tag_expressions]).to eq ['not @foo or @bar'] } + after_parsing(['--tags', 'not @foo or @bar']) do + expect(options[:tag_expressions]).to eq(['not @foo or @bar']) + end end it 'stores tags passed with different --tags separately' do - after_parsing('--tags @foo --tags @bar') { expect(options[:tag_expressions]).to eq ['@foo', '@bar'] } + after_parsing('--tags @foo --tags @bar') do + expect(options[:tag_expressions]).to eq(['@foo', '@bar']) + end end it 'strips tag limits from the tag expressions stored' do - after_parsing(['--tags', 'not @foo:2 or @bar:3']) { expect(options[:tag_expressions]).to eq ['not @foo or @bar'] } + after_parsing(['--tags', 'not @foo:2 or @bar:3']) do + expect(options[:tag_expressions]).to eq(['not @foo or @bar']) + end end it 'stores tag limits separately' do - after_parsing(['--tags', 'not @foo:2 or @bar:3']) { expect(options[:tag_limits]).to eq Hash('@foo' => 2, '@bar' => 3) } + after_parsing(['--tags', 'not @foo:2 or @bar:3']) do + expect(options[:tag_limits]).to eq({'@foo' => 2, '@bar' => 3}) + end end it 'raise exception for inconsistent tag limits' do @@ -197,13 +197,17 @@ def with_env(name, value) context 'when using -n NAME or --name NAME' do it 'stores the provided names as regular expressions' do - after_parsing('-n foo --name bar') { expect(options[:name_regexps]).to eq [/foo/, /bar/] } + after_parsing('-n foo --name bar') do + expect(options[:name_regexps]).to eq([/foo/, /bar/]) + end end end context 'when using -e PATTERN or --exclude PATTERN' do it 'stores the provided exclusions as regular expressions' do - after_parsing('-e foo --exclude bar') { expect(options[:excludes]).to eq [/foo/, /bar/] } + after_parsing('-e foo --exclude bar') do + expect(options[:excludes]).to eq([/foo/, /bar/]) + end end end @@ -211,14 +215,13 @@ def with_env(name, value) it 'adds line numbers to args' do options.parse!(%w[-l24 FILE]) - expect(options.instance_variable_get(:@args)).to eq ['FILE:24'] + expect(options.instance_variable_get(:@args)).to eq(['FILE:24']) end end context 'when using -p PROFILE or --profile PROFILE' do it 'uses the default profile passed in during initialization if none are specified by the user' do given_cucumber_yml_defined_as('default' => '--require some_file') - options = described_class.new(output_stream, error_stream, default_profile: 'default') options.parse!(%w[--format progress]) @@ -233,32 +236,32 @@ def with_env(name, value) expect(options[:verbose]).to be true end - it "gives precendene to the origianl options' paths" do + it "gives precedence to the original options' paths" do given_cucumber_yml_defined_as('foo' => %w[features]) options.parse!(%w[my.feature -p foo]) - expect(options[:paths]).to eq %w[my.feature] + expect(options[:paths]).to eq(%w[my.feature]) end it 'combines the require files of both' do given_cucumber_yml_defined_as('bar' => %w[--require features -r dog.rb]) options.parse!(%w[--require foo.rb -p bar]) - expect(options[:require]).to eq %w[foo.rb features dog.rb] + expect(options[:require]).to eq(%w[foo.rb features dog.rb]) end it 'combines the tag names of both' do given_cucumber_yml_defined_as('baz' => %w[-t @bar]) options.parse!(%w[--tags @foo -p baz]) - expect(options[:tag_expressions]).to eq ['@foo', '@bar'] + expect(options[:tag_expressions]).to eq(['@foo', '@bar']) end it 'combines the tag limits of both' do given_cucumber_yml_defined_as('baz' => %w[-t @bar:2]) options.parse!(%w[--tags @foo:3 -p baz]) - expect(options[:tag_limits]).to eq Hash('@foo' => 3, '@bar' => 2) + expect(options[:tag_limits]).to eq({'@foo' => 3, '@bar' => 2}) end it 'raise exceptions for inconsistent tag limits' do @@ -271,14 +274,14 @@ def with_env(name, value) given_cucumber_yml_defined_as('baz' => %w[features]) options.parse!(%w[my.feature -p baz]) - expect(options[:paths]).to eq ['my.feature'] + expect(options[:paths]).to eq(['my.feature']) end it 'uses the paths from the profile when none are specified originally' do given_cucumber_yml_defined_as('baz' => %w[some.feature]) options.parse!(%w[-p baz]) - expect(options[:paths]).to eq ['some.feature'] + expect(options[:paths]).to eq(['some.feature']) end it 'combines environment variables from the profile but gives precendene to cmd line args' do @@ -292,38 +295,37 @@ def with_env(name, value) given_cucumber_yml_defined_as('foo' => %w[--format pretty]) options.parse!(%w[--format progress --profile foo]) - expect(options[:formats]).to eq [['progress', {}, output_stream]] + expect(options[:formats]).to eq([['progress', {}, output_stream]]) end it 'includes any non-STDOUT formatters from the profile' do given_cucumber_yml_defined_as('json' => %w[--format json -o features.json]) options.parse!(%w[--format progress --profile json]) - expect(options[:formats]).to eq [['progress', {}, output_stream], ['json', {}, 'features.json']] + expect(options[:formats]).to eq([['progress', {}, output_stream], ['json', {}, 'features.json']]) end it 'does not include STDOUT formatters from the profile if there is a STDOUT formatter in command line' do given_cucumber_yml_defined_as('json' => %w[--format json -o features.json --format pretty]) options.parse!(%w[--format progress --profile json]) - expect(options[:formats]).to eq [['progress', {}, output_stream], ['json', {}, 'features.json']] + expect(options[:formats]).to eq([['progress', {}, output_stream], ['json', {}, 'features.json']]) end it 'includes any STDOUT formatters from the profile if no STDOUT formatter was specified in command line' do given_cucumber_yml_defined_as('json' => %w[--format json]) options.parse!(%w[--format rerun -o rerun.txt --profile json]) - expect(options[:formats]).to eq [['json', {}, output_stream], ['rerun', {}, 'rerun.txt']] + expect(options[:formats]).to eq([['json', {}, output_stream], ['rerun', {}, 'rerun.txt']]) end it 'assumes all of the formatters defined in the profile when none are specified on cmd line' do given_cucumber_yml_defined_as('json' => %w[--format progress --format json -o features.json]) options.parse!(%w[--profile json]) - expect(options[:formats]).to eq [['progress', {}, output_stream], ['json', {}, 'features.json']] + expect(options[:formats]).to eq([['progress', {}, output_stream], ['json', {}, 'features.json']]) end - # rubocop:disable Style/GlobalVars it 'only reads cucumber.yml once' do original_parse_count = $cucumber_yml_read_count $cucumber_yml_read_count = 0 @@ -342,16 +344,12 @@ def with_env(name, value) $cucumber_yml_read_count = original_parse_count end end - # rubocop:enable Style/GlobalVars it 'respects --quiet when defined in the profile' do given_cucumber_yml_defined_as('foo' => '-q') options.parse!(%w[-p foo]) expect(options[:publish_quiet]).to be true - expect(options[:snippets]).to be false - expect(options[:source]).to be false - expect(options[:duration]).to be false end it 'uses --no-duration when defined in the profile' do @@ -361,8 +359,8 @@ def with_env(name, value) expect(options[:duration]).to be false end - context 'with --retry ATTEMPTS' do - context 'when --retry option is not defined on the command line' do + context 'with --retry' do + context 'when --retry is not defined on the command line' do it 'uses the --retry option from the profile' do given_cucumber_yml_defined_as('foo' => '--retry 2') options.parse!(%w[-p foo]) @@ -371,7 +369,7 @@ def with_env(name, value) end end - context 'when --retry option is defined on the command line' do + context 'when --retry is defined on the command line' do it 'ignores the --retry option from the profile' do given_cucumber_yml_defined_as('foo' => '--retry 2') options.parse!(%w[--retry 1 -p foo]) @@ -381,8 +379,8 @@ def with_env(name, value) end end - context 'with --retry-total TESTS' do - context 'when --retry option is not defined on the command line' do + context 'with --retry-total' do + context 'when --retry-total is not defined on the command line' do it 'uses the --retry-total option from the profile' do given_cucumber_yml_defined_as('foo' => '--retry-total 2') options.parse!(%w[-p foo]) @@ -391,7 +389,7 @@ def with_env(name, value) end end - context 'when --retry option is defined on the command line' do + context 'when --retry-total is defined on the command line' do it 'ignores the --retry-total option from the profile' do given_cucumber_yml_defined_as('foo' => '--retry-total 2') options.parse!(%w[--retry-total 1 -p foo]) @@ -448,7 +446,7 @@ def with_env(name, value) end end - context 'with --retry ATTEMPTS' do + context 'with --retry' do it 'is 0 by default' do after_parsing('') do expect(options[:retry]).to eq(0) @@ -462,7 +460,7 @@ def with_env(name, value) end end - context 'with --retry-total TESTS' do + context 'with --retry-total' do it 'is INFINITY by default' do after_parsing('') do expect(options[:retry_total]).to eq(Float::INFINITY) @@ -470,7 +468,7 @@ def with_env(name, value) end it 'sets the options[:retry_total] value' do - after_parsing('--retry 3 --retry-total 10') do + after_parsing('--retry-total 10') do expect(options[:retry_total]).to eq(10) end end @@ -503,10 +501,17 @@ def with_env(name, value) end end - it 'enables publishing when CUCUMBER_PUBLISH_ENABLED=true' do + it 'adds message formatter with output to default reports publishing url when CUCUMBER_PUBLISH_ENABLED=true' do with_env('CUCUMBER_PUBLISH_ENABLED', 'true') do after_parsing('') do expect(@options[:formats]).to include(['message', {}, Cucumber::Cli::Options::CUCUMBER_PUBLISH_URL]) + end + end + end + + it 'enables publishing when CUCUMBER_PUBLISH_ENABLED=true' do + with_env('CUCUMBER_PUBLISH_ENABLED', 'true') do + after_parsing('') do expect(@options[:publish_enabled]).to be true end end @@ -515,7 +520,7 @@ def with_env(name, value) it 'does not enable publishing when CUCUMBER_PUBLISH_ENABLED=false' do with_env('CUCUMBER_PUBLISH_ENABLED', 'false') do after_parsing('') do - expect(@options[:publish_enabled]).to be_falsy + expect(@options[:publish_enabled]).to be false end end end @@ -524,6 +529,13 @@ def with_env(name, value) with_env('CUCUMBER_PUBLISH_TOKEN', 'abcd1234') do after_parsing('--publish') do expect(@options[:formats]).to include(['message', {}, %(#{Cucumber::Cli::Options::CUCUMBER_PUBLISH_URL} -H "Authorization: Bearer abcd1234")]) + end + end + end + + it 'enables publishing if CUCUMBER_PUBLISH_TOKEN environment variable is set' do + with_env('CUCUMBER_PUBLISH_TOKEN', 'abcd1234') do + after_parsing('--publish') do expect(@options[:publish_enabled]).to be true end end @@ -533,7 +545,6 @@ def with_env(name, value) with_env('CUCUMBER_PUBLISH_TOKEN', 'abcd1234') do after_parsing('') do expect(@options[:formats]).to include(['message', {}, %(#{Cucumber::Cli::Options::CUCUMBER_PUBLISH_URL} -H "Authorization: Bearer abcd1234")]) - expect(@options[:publish_enabled]).to be true end end end From 6e560c975e046e1c1b6c1418d988852d38284809 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 12:39:36 +0100 Subject: [PATCH 08/15] Stylistic tweaks to activate steps spec --- spec/cucumber/filters/activate_steps_spec.rb | 27 +++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/spec/cucumber/filters/activate_steps_spec.rb b/spec/cucumber/filters/activate_steps_spec.rb index 96ab8473a..481067fb2 100644 --- a/spec/cucumber/filters/activate_steps_spec.rb +++ b/spec/cucumber/filters/activate_steps_spec.rb @@ -30,7 +30,8 @@ expect(step_match).to receive(:activate) do |test_step| expect(test_step.text).to eq 'a passing step' end - compile [doc], receiver, [filter] + + compile([doc], receiver, [filter]) end it 'notifies with a StepActivated event' do @@ -39,7 +40,8 @@ expect(test_step.text).to eq 'a passing step' expect(step_match).to eq step_match end - compile [doc], receiver, [filter] + + compile([doc], receiver, [filter]) end end @@ -63,7 +65,8 @@ expect(step_match).to receive(:activate) do |test_step| expect(test_step.text).to eq 'a passing step' end - compile [doc], receiver, [filter] + + compile([doc], receiver, [filter]) end end @@ -84,12 +87,14 @@ expect(receiver).to receive(:test_case) do |test_case| expect(test_case.test_steps[0].execute).to be_undefined end - compile [doc], receiver, [filter] + + compile([doc], receiver, [filter]) end it 'does not notify' do expect(configuration).not_to receive(:notify) - compile [doc], receiver, [filter] + + compile([doc], receiver, [filter]) end end @@ -110,7 +115,8 @@ expect(receiver).to receive(:test_case) do |test_case| expect(test_case.test_steps[0].execute).to be_skipped end - compile [doc], receiver, [filter] + + compile([doc], receiver, [filter]) end it 'notifies with a StepActivated event' do @@ -119,7 +125,8 @@ expect(test_step.text).to eq 'a passing step' expect(step_match).to eq step_match end - compile [doc], receiver, [filter] + + compile([doc], receiver, [filter]) end end @@ -141,12 +148,14 @@ expect(receiver).to receive(:test_case) do |test_case| expect(test_case.test_steps[0].execute).to be_undefined end - compile [doc], receiver, [filter] + + compile([doc], receiver, [filter]) end it 'does not notify' do expect(configuration).not_to receive(:notify) - compile [doc], receiver, [filter] + + compile([doc], receiver, [filter]) end end end From c5de76576648dc6ccfa7647918fecd41e7e870da Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 12:41:06 +0100 Subject: [PATCH 09/15] Remove double expectation wrappers on essentially allow calls for mocking --- spec/cucumber/filters/activate_steps_spec.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/cucumber/filters/activate_steps_spec.rb b/spec/cucumber/filters/activate_steps_spec.rb index 481067fb2..851e184c3 100644 --- a/spec/cucumber/filters/activate_steps_spec.rb +++ b/spec/cucumber/filters/activate_steps_spec.rb @@ -27,15 +27,15 @@ end it 'activates each step' do - expect(step_match).to receive(:activate) do |test_step| + allow(step_match).to receive(:activate) do |test_step| expect(test_step.text).to eq 'a passing step' end - + compile([doc], receiver, [filter]) end it 'notifies with a StepActivated event' do - expect(configuration).to receive(:notify) do |message, test_step, step_match| + allow(configuration).to receive(:notify) do |message, test_step, step_match| expect(message).to eq :step_activated expect(test_step.text).to eq 'a passing step' expect(step_match).to eq step_match @@ -62,7 +62,7 @@ end it 'activates each step' do - expect(step_match).to receive(:activate) do |test_step| + allow(step_match).to receive(:activate) do |test_step| expect(test_step.text).to eq 'a passing step' end @@ -84,7 +84,7 @@ end it 'does not activate the step' do - expect(receiver).to receive(:test_case) do |test_case| + allow(receiver).to receive(:test_case) do |test_case| expect(test_case.test_steps[0].execute).to be_undefined end @@ -112,7 +112,7 @@ end it 'activates each step with a skipping action' do - expect(receiver).to receive(:test_case) do |test_case| + allow(receiver).to receive(:test_case) do |test_case| expect(test_case.test_steps[0].execute).to be_skipped end @@ -120,7 +120,7 @@ end it 'notifies with a StepActivated event' do - expect(configuration).to receive(:notify) do |message, test_step, step_match| + allow(configuration).to receive(:notify) do |message, test_step, step_match| expect(message).to eq :step_activated expect(test_step.text).to eq 'a passing step' expect(step_match).to eq step_match @@ -145,7 +145,7 @@ end it 'does not activate the step' do - expect(receiver).to receive(:test_case) do |test_case| + allow(receiver).to receive(:test_case) do |test_case| expect(test_case.test_steps[0].execute).to be_undefined end From 80faf5e8d9eb2504475230e422788ba0a251c115 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 14:55:32 +0100 Subject: [PATCH 10/15] Remove all duplicate expectations from activate_steps spec --- spec/cucumber/filters/activate_steps_spec.rb | 32 ++++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/spec/cucumber/filters/activate_steps_spec.rb b/spec/cucumber/filters/activate_steps_spec.rb index 851e184c3..3f5d2797e 100644 --- a/spec/cucumber/filters/activate_steps_spec.rb +++ b/spec/cucumber/filters/activate_steps_spec.rb @@ -28,17 +28,23 @@ it 'activates each step' do allow(step_match).to receive(:activate) do |test_step| - expect(test_step.text).to eq 'a passing step' + expect(test_step.text).to eq('a passing step') end compile([doc], receiver, [filter]) end it 'notifies with a StepActivated event' do - allow(configuration).to receive(:notify) do |message, test_step, step_match| - expect(message).to eq :step_activated - expect(test_step.text).to eq 'a passing step' - expect(step_match).to eq step_match + allow(configuration).to receive(:notify) do |message, _test_step, _step_match| + expect(message).to eq(:step_activated) + end + + compile([doc], receiver, [filter]) + end + + it 'notifies with the correct step' do + allow(configuration).to receive(:notify) do |_message, test_step, _step_match| + expect(test_step.text).to eq('a passing step') end compile([doc], receiver, [filter]) @@ -63,7 +69,7 @@ it 'activates each step' do allow(step_match).to receive(:activate) do |test_step| - expect(test_step.text).to eq 'a passing step' + expect(test_step.text).to eq('a passing step') end compile([doc], receiver, [filter]) @@ -120,10 +126,16 @@ end it 'notifies with a StepActivated event' do - allow(configuration).to receive(:notify) do |message, test_step, step_match| - expect(message).to eq :step_activated - expect(test_step.text).to eq 'a passing step' - expect(step_match).to eq step_match + allow(configuration).to receive(:notify) do |message, _test_step, _step_match| + expect(message).to eq(:step_activated) + end + + compile([doc], receiver, [filter]) + end + + it 'notifies with the correct step' do + allow(configuration).to receive(:notify) do |_message, test_step, _step_match| + expect(test_step.text).to eq('a passing step') end compile([doc], receiver, [filter]) From e2ef6e6164238e4ee6afd403c40c04c1b5962eda Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 14:57:34 +0100 Subject: [PATCH 11/15] Remove around 30% of multiple expectation offenses --- .rubocop_todo.yml | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 90fe067dd..fcc02e0f3 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2023-10-02 14:25:13 UTC using RuboCop version 1.56.4. +# on 2023-10-03 13:56:41 UTC using RuboCop version 1.56.4. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -69,6 +69,15 @@ Layout/IndentationWidth: Exclude: - 'spec/cucumber/formatter/fail_fast_spec.rb' +# Offense count: 4 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. +# SupportedStyles: space, no_space, compact +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideHashLiteralBraces: + Exclude: + - 'spec/cucumber/cli/options_spec.rb' + # Offense count: 3 # This cop supports safe autocorrection (--autocorrect). Lint/AmbiguousOperator: @@ -185,7 +194,7 @@ RSpec/EmptyLineAfterFinalLet: - 'spec/cucumber/configuration_spec.rb' - 'spec/cucumber/hooks_spec.rb' -# Offense count: 100 +# Offense count: 83 # Configuration parameters: CountAsOne. RSpec/ExampleLength: Max: 58 @@ -245,9 +254,9 @@ RSpec/MissingExampleGroupArgument: - 'spec/cucumber/formatter/fail_fast_spec.rb' - 'spec/cucumber/formatter/rerun_spec.rb' -# Offense count: 87 +# Offense count: 59 RSpec/MultipleExpectations: - Max: 8 + Max: 3 # Offense count: 38 # Configuration parameters: AllowSubject. @@ -325,15 +334,14 @@ RSpec/ScatteredLet: Exclude: - 'spec/cucumber/runtime/support_code_spec.rb' -# Offense count: 9 +# Offense count: 5 RSpec/StubbedMock: Exclude: - 'spec/cucumber/cli/configuration_spec.rb' - 'spec/cucumber/formatter/interceptor_spec.rb' - - 'spec/cucumber/glue/registry_and_more_spec.rb' - 'spec/cucumber/runtime/meta_message_builder_spec.rb' -# Offense count: 54 +# Offense count: 57 # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: Exclude: @@ -371,6 +379,12 @@ Style/ClassVars: Exclude: - 'spec/cucumber/glue/step_definition_spec.rb' +# Offense count: 4 +# Configuration parameters: AllowedVariables. +Style/GlobalVars: + Exclude: + - 'spec/cucumber/cli/options_spec.rb' + # Offense count: 6 # This cop supports safe autocorrection (--autocorrect). Style/StderrPuts: @@ -382,10 +396,11 @@ Style/StderrPuts: - 'lib/cucumber/rake/task.rb' - 'spec/cucumber/formatter/interceptor_spec.rb' -# Offense count: 1 +# Offense count: 2 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. # SupportedStyles: single_quotes, double_quotes Style/StringLiterals: Exclude: - 'spec/cucumber/cli/options_spec.rb' + - 'spec/cucumber/formatter/pretty_spec.rb' From 3b6d99db57585436ee043e25808cfabc6c2ff729 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 15:10:19 +0100 Subject: [PATCH 12/15] Partial fix for maximum lets --- spec/cucumber/filters/retry_spec.rb | 60 ++++++++++------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/spec/cucumber/filters/retry_spec.rb b/spec/cucumber/filters/retry_spec.rb index 6dfb16028..cfa05c979 100644 --- a/spec/cucumber/filters/retry_spec.rb +++ b/spec/cucumber/filters/retry_spec.rb @@ -15,16 +15,12 @@ let(:configuration) { Cucumber::Configuration.new(retry: 2, retry_total: retry_total) } let(:retry_total) { Float::INFINITY } - let(:id) { double } - let(:name) { double } - let(:location) { double } - let(:tags) { double } - let(:language) { double } - let(:test_case) { Cucumber::Core::Test::Case.new(id, name, [double('test steps')], location, tags, language) } + let(:test_case) { Cucumber::Core::Test::Case.new(double, double, [double('test steps')], double, [], double) } let(:receiver) { double('receiver').as_null_object } let(:filter) { described_class.new(configuration, receiver) } let(:fail) { Cucumber::Events::AfterTestCase.new(test_case, double('result', failed?: true, ok?: false)) } let(:pass) { Cucumber::Events::AfterTestCase.new(test_case, double('result', failed?: false, ok?: true)) } + let(:fail_result) { Cucumber::Core::Test::Result::Failed.new(0, StandardError.new) } it { is_expected.to respond_to(:test_case) } it { is_expected.to respond_to(:with_receiver) } @@ -35,32 +31,30 @@ it 'describes the test case once' do expect(receiver).to receive(:test_case).with(test_case).once + test_case.describe_to filter - configuration.notify :test_case_finished, test_case, result + configuration.notify(:test_case_finished, test_case, result) end end context 'when performing retry' do - let(:result) { Cucumber::Core::Test::Result::Failed.new(0, StandardError.new) } - it 'describes the same test case object each time' do - allow(receiver).to receive(:test_case) { |tc| + allow(receiver).to receive(:test_case) do |tc| expect(tc).to equal(test_case) - configuration.notify :test_case_finished, tc.with_steps(tc.test_steps), result - } + + configuration.notify(:test_case_finished, tc.with_steps(tc.test_steps), fail_result) + end filter.test_case(test_case) end end context 'with a consistently failing test case' do - let(:result) { Cucumber::Core::Test::Result::Failed.new(0, StandardError.new) } - - shared_examples 'retries the test case the specified number of times' do |expected_nr_of_times| + shared_examples 'retries the test case the specified number of times' do |expected_number_of_times| it 'describes the test case the specified number of times' do expect(receiver).to receive(:test_case) { |test_case| - configuration.notify :test_case_finished, test_case, result - }.exactly(expected_nr_of_times).times + configuration.notify(:test_case_finished, test_case, fail_result) + }.exactly(expected_number_of_times).times filter.test_case(test_case) end @@ -86,34 +80,23 @@ end context 'with slighty flaky test cases' do - let(:results) do - [ - Cucumber::Core::Test::Result::Failed.new(0, StandardError.new), - Cucumber::Core::Test::Result::Passed.new(0) - ] - end + let(:results) { [fail_result, Cucumber::Core::Test::Result::Passed.new(0)] } it 'describes the test case twice' do expect(receiver).to receive(:test_case) { |test_case| - configuration.notify :test_case_finished, test_case, results.shift - }.exactly(2).times + configuration.notify(:test_case_finished, test_case, results.shift) + }.twice filter.test_case(test_case) end end context 'with really flaky test cases' do - let(:results) do - [ - Cucumber::Core::Test::Result::Failed.new(0, StandardError.new), - Cucumber::Core::Test::Result::Failed.new(0, StandardError.new), - Cucumber::Core::Test::Result::Passed.new(0) - ] - end + let(:results) { [fail_result, fail_result, Cucumber::Core::Test::Result::Passed.new(0)] } it 'describes the test case 3 times' do expect(receiver).to receive(:test_case) { |test_case| - configuration.notify :test_case_finished, test_case, results.shift + configuration.notify(:test_case_finished, test_case, results.shift) }.exactly(3).times filter.test_case(test_case) @@ -123,21 +106,20 @@ context 'with too many failing tests' do let(:retry_total) { 1 } let(:always_failing_test_case1) do - Cucumber::Core::Test::Case.new(id, name, [double('test steps')], 'test.rb:1', tags, language) + Cucumber::Core::Test::Case.new(double, double, [double('test steps')], 'test.rb:1', [], double) end let(:always_failing_test_case2) do - Cucumber::Core::Test::Case.new(id, name, [double('test steps')], 'test.rb:9', tags, language) + Cucumber::Core::Test::Case.new(double, double, [double('test steps')], 'test.rb:9', [], double) end - let(:fail_result) { Cucumber::Core::Test::Result::Failed.new(0, StandardError.new) } it 'stops retrying tests' do expect(receiver).to receive(:test_case).with(always_failing_test_case1) { |test_case| - configuration.notify :test_case_finished, test_case, fail_result + configuration.notify(:test_case_finished, test_case, fail_result) }.ordered.exactly(3).times expect(receiver).to receive(:test_case).with(always_failing_test_case2) { |test_case| - configuration.notify :test_case_finished, test_case, fail_result - }.ordered.exactly(1).times + configuration.notify(:test_case_finished, test_case, fail_result) + }.ordered.once filter.test_case(always_failing_test_case1) filter.test_case(always_failing_test_case2) From fcfd0e64adf416dda0fe94c2d9247e465b82e384 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 15:21:25 +0100 Subject: [PATCH 13/15] Fix up all RSpec/NestedGroups offenses --- .../runtime/meta_message_builder_spec.rb | 126 +++++++++--------- spec/cucumber/term/banner_spec.rb | 21 ++- 2 files changed, 71 insertions(+), 76 deletions(-) diff --git a/spec/cucumber/runtime/meta_message_builder_spec.rb b/spec/cucumber/runtime/meta_message_builder_spec.rb index 8a18c6d39..9f4341427 100644 --- a/spec/cucumber/runtime/meta_message_builder_spec.rb +++ b/spec/cucumber/runtime/meta_message_builder_spec.rb @@ -53,79 +53,77 @@ end end - describe ':ci hash' do + context 'when running on a CI system without git data' do subject { described_class.build_meta_message.ci } before { expect(Cucumber::CiEnvironment).to receive(:detect_ci_environment).and_return(ci_data) } - context 'when running on a CI system' do - let(:ci_data) do - { - name: 'Jenkins', - url: 'http://localhost:8080', - buildNumber: '123' + let(:ci_data) do + { + name: 'Jenkins', + url: 'http://localhost:8080', + buildNumber: '123' + } + end + + it { is_expected.to be_a(Cucumber::Messages::Ci) } + + it 'has a populated CI name from the ci input hash' do + expect(subject.name).to eq(ci_data[:name]) + end + + it 'has a populated CI url from the ci input hash' do + expect(subject.url).to eq(ci_data[:url]) + end + + it 'has a populated CI build number from the ci input hash' do + expect(subject.build_number).to eq(ci_data[:buildNumber]) + end + end + + context 'when running on a CI system with git data' do + subject { described_class.build_meta_message.ci.git } + + before { expect(Cucumber::CiEnvironment).to receive(:detect_ci_environment).and_return(ci_data) } + + let(:ci_data) do + { + git: { + remote: 'origin', + revision: '1234567890', + branch: 'main', + tag: 'v1.0.0' } - end - - it { is_expected.to be_a(Cucumber::Messages::Ci) } - - it 'has a populated name from the ci input hash' do - expect(subject.name).to eq(ci_data[:name]) - end - - it 'has a populated url from the ci input hash' do - expect(subject.url).to eq(ci_data[:url]) - end - - it 'has a populated build number from the ci input hash' do - expect(subject.build_number).to eq(ci_data[:buildNumber]) - end - - describe ':git field' do - subject { described_class.build_meta_message.ci.git } - - context 'with some git data' do - let(:ci_data) do - { - git: { - remote: 'origin', - revision: '1234567890', - branch: 'main', - tag: 'v1.0.0' - } - } - end - - it { is_expected.to be_a(Cucumber::Messages::Git) } - - it 'has a populated git remote from the git field of the ci input hash' do - expect(subject.remote).to eq(ci_data[:git][:remote]) - end - - it 'has a populated git revision from the git field of the ci input hash' do - expect(subject.revision).to eq(ci_data[:git][:revision]) - end - - it 'has a populated git branch from the git field of the ci input hash' do - expect(subject.branch).to eq(ci_data[:git][:branch]) - end - - it 'has a populated git tag from the git field of the ci input hash' do - expect(subject.tag).to eq(ci_data[:git][:tag]) - end - end - - context 'without any git data' do - it { is_expected.to be_nil } - end - end + } end - context 'when not running on a CI system' do - let(:ci_data) { nil } + it { is_expected.to be_a(Cucumber::Messages::Git) } - it { is_expected.to be_nil } + it 'has a populated git remote from the git field of the ci input hash' do + expect(subject.remote).to eq(ci_data[:git][:remote]) end + + it 'has a populated git revision from the git field of the ci input hash' do + expect(subject.revision).to eq(ci_data[:git][:revision]) + end + + it 'has a populated git branch from the git field of the ci input hash' do + expect(subject.branch).to eq(ci_data[:git][:branch]) + end + + it 'has a populated git tag from the git field of the ci input hash' do + expect(subject.tag).to eq(ci_data[:git][:tag]) + end + end + + context 'when not running on a CI system' do + subject { described_class.build_meta_message.ci } + + before { expect(Cucumber::CiEnvironment).to receive(:detect_ci_environment).and_return(ci_data) } + + let(:ci_data) { nil } + + it { is_expected.to be_nil } end end end diff --git a/spec/cucumber/term/banner_spec.rb b/spec/cucumber/term/banner_spec.rb index 8333ac5be..6bcdcaf5d 100644 --- a/spec/cucumber/term/banner_spec.rb +++ b/spec/cucumber/term/banner_spec.rb @@ -44,18 +44,15 @@ BANNER end - context 'when specifying spans' do - it 'can render special characters inside the lines' do - display_banner(['Oh, this is a banner', ['It has ', ['two', :bold, :blue], ' lines']], io, []) - - io.rewind - expect(io.read).to eq(<<~BANNER) - ┌──────────────────────┐ - │ Oh, this is a banner │ - │ It has \e[34m\e[1mtwo\e[0m\e[0m lines │ - └──────────────────────┘ - BANNER - end + it 'can render special characters inside the lines' do + display_banner(['Oh, this is a banner', ['It has ', ['two', :bold, :blue], ' lines']], io, []) + io.rewind + expect(io.read).to eq(<<~BANNER) + ┌──────────────────────┐ + │ Oh, this is a banner │ + │ It has \e[34m\e[1mtwo\e[0m\e[0m lines │ + └──────────────────────┘ + BANNER end end From d5a6137f640059e6089aa1403e5213e0219a433a Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 15:23:29 +0100 Subject: [PATCH 14/15] Fix up incorrect rubocop fix --- spec/cucumber/cli/options_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/cucumber/cli/options_spec.rb b/spec/cucumber/cli/options_spec.rb index 9eeab8fda..9cf55d584 100644 --- a/spec/cucumber/cli/options_spec.rb +++ b/spec/cucumber/cli/options_spec.rb @@ -520,7 +520,7 @@ def with_env(name, value) it 'does not enable publishing when CUCUMBER_PUBLISH_ENABLED=false' do with_env('CUCUMBER_PUBLISH_ENABLED', 'false') do after_parsing('') do - expect(@options[:publish_enabled]).to be false + expect(@options[:publish_enabled]).to be nil end end end From 4a0998cbe455a51942e1c1b2a5cb22e5eb19ef89 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Tue, 3 Oct 2023 15:40:01 +0100 Subject: [PATCH 15/15] Add in additional note about rubocop fixes --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71d8d473c..c3e1d8ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo ## [Unreleased] ### Changed - First couple of passes of tidying up approximately 40% of the manual fix cops - ([#1739](https://github.com/cucumber/cucumber-ruby/pull/1739) [#1740](https://github.com/cucumber/cucumber-ruby/pull/1740) [#1741](https://github.com/cucumber/cucumber-ruby/pull/1741) [luke-hill](https://github.com/luke-hill)) + ([#1739](https://github.com/cucumber/cucumber-ruby/pull/1739) [#1740](https://github.com/cucumber/cucumber-ruby/pull/1740) [#1741](https://github.com/cucumber/cucumber-ruby/pull/1741) [#1742](https://github.com/cucumber/cucumber-ruby/pull/1742) [luke-hill](https://github.com/luke-hill)) - Removed a bunch of example files / sample projects from ancient projects no longer viable [#1740](https://github.com/cucumber/cucumber-ruby/pull/1740) [luke-hill](https://github.com/luke-hill))