diff --git a/.rspec b/.rspec index 5c96d62826..3687797e56 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1,2 @@ +--require spec_helper --color ---tag "~cck" diff --git a/CHANGELOG.md b/CHANGELOG.md index c3e1d8ae1e..1e745bcdce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,27 @@ This document is formatted according to the principles of [Keep A CHANGELOG](htt Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CONTRIBUTING.md) for more info on how to contribute to Cucumber. ## [Unreleased] +### Added +- `ParameterType` message now contains a new (sourceReference), property + (This contains a uri string and a `Location` message -> for where the ParameterType `transformer` is located) ([#1738](https://github.com/cucumber/cucumber-ruby/pull/1738) [luke-hill](https://github.com/luke-hill)) + ### 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) [#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)) + ([#1740](https://github.com/cucumber/cucumber-ruby/pull/1740) [luke-hill](https://github.com/luke-hill)) +- When a `testStepResult` is of type `FAILED` we now pass in a new (Exception), message property + ([#1738](https://github.com/cucumber/cucumber-ruby/pull/1738) [luke-hill](https://github.com/luke-hill)) +- `#attach` now can take an optional filename parameter which will rename attachments like PDF's + ([#1738](https://github.com/cucumber/cucumber-ruby/pull/1738) [luke-hill](https://github.com/luke-hill)) + +### Fixed +- Clear up a couple of tiny "nuances" that hide lots of issues when running local vs remote (Primarily CCK tests should always be runnable) + ([#1738](https://github.com/cucumber/cucumber-ruby/pull/1738) [luke-hill](https://github.com/luke-hill)) + +### Removed +- Removed a variety of overrides / hacks for travis CI (No longer in use) ([#1738](https://github.com/cucumber/cucumber-ruby/pull/1738) [luke-hill](https://github.com/luke-hill)) +- Removed some legacy rspec pending flags present since cucumber 1.x ([#1738](https://github.com/cucumber/cucumber-ruby/pull/1738) [luke-hill](https://github.com/luke-hill)) ## [9.0.2] - 2023-09-11 ### Changed diff --git a/Rakefile b/Rakefile index 6c41a6c506..8d83d778ac 100644 --- a/Rakefile +++ b/Rakefile @@ -19,6 +19,3 @@ default_tasks = %i[spec cucumber cck] default_tasks << :examples if ENV['CI'] task default: default_tasks - -require 'rake/clean' -CLEAN.include %w[**/*.{log,pyc,rbc,tgz} doc] diff --git a/cucumber.gemspec b/cucumber.gemspec index 0e6787c04f..199b6d8df3 100644 --- a/cucumber.gemspec +++ b/cucumber.gemspec @@ -20,12 +20,13 @@ Gem::Specification.new do |s| } s.required_ruby_version = '>= 2.7' + s.required_rubygems_version = '>= 3.0.1' s.add_dependency 'builder', '~> 3.2', '>= 3.2.4' s.add_dependency 'cucumber-ci-environment', '~> 9.2', '>= 9.2.0' - s.add_dependency 'cucumber-core', '~> 11.1', '>= 11.1.0' - s.add_dependency 'cucumber-cucumber-expressions', '~> 16.1', '>= 16.1.2' - s.add_dependency 'cucumber-gherkin', '>= 24', '< 26.2.1' + s.add_dependency 'cucumber-core', '~> 12.0' + s.add_dependency 'cucumber-cucumber-expressions', '~> 17.0' + s.add_dependency 'cucumber-gherkin', '>= 24', '< 27' s.add_dependency 'cucumber-html-formatter', '~> 20.4', '>= 20.4.0' s.add_dependency 'cucumber-messages', '>= 19', '< 23' s.add_dependency 'diff-lcs', '~> 1.5', '>= 1.5.0' @@ -33,10 +34,9 @@ Gem::Specification.new do |s| s.add_dependency 'multi_test', '~> 1.1', '>= 1.1.0' s.add_dependency 'sys-uname', '~> 1.2', '>= 1.2.3' - s.add_development_dependency 'cucumber-compatibility-kit', '~> 10.0' + s.add_development_dependency 'cucumber-compatibility-kit', '~> 14.0' # Only needed whilst we are testing the formatters. Can be removed once we remove tests for those s.add_development_dependency 'nokogiri', '~> 1.13', '>= 1.13.6' - s.add_development_dependency 'pry', '~> 0.14', '>= 0.14.1' s.add_development_dependency 'rake', '~> 13.0', '>= 13.0.6' s.add_development_dependency 'rspec', '~> 3.12', '>= 3.12.0' s.add_development_dependency 'rubocop', '~> 1.56.4' @@ -54,7 +54,6 @@ Gem::Specification.new do |s| s.add_development_dependency 'rack-test', '~> 2.1', '>= 2.1.0' s.add_development_dependency 'sinatra', '~> 3.1', '>= 3.1.0' - s.required_rubygems_version = '>= 3.0.1' s.files = Dir[ 'README.md', 'LICENSE', diff --git a/features/docs/writing_support_code/hooks/hook_order.feature b/features/docs/writing_support_code/hooks/hook_order.feature index 40fa86e8fa..edbc195a07 100644 --- a/features/docs/writing_support_code/hooks/hook_order.feature +++ b/features/docs/writing_support_code/hooks/hook_order.feature @@ -1,26 +1,25 @@ - Feature: Hooks execute in defined order - +Feature: Hooks execute in defined order Background: Given a file named "features/step_definitions/steps.rb" with: """ - Given /^background step$/ do; log(:background_step) end - Given /^scenario step$/ do; log(:scenario_step) end + Given('background step') { log(:background_step) } + Given('scenario step') { log(:scenario_step) } """ And a file named "features/support/hooks.rb" with: """ $EventOrder = [] Around('@around') do |scenario,block| - log :around_begin + log(:around_begin) block.call - log :around_end + log(:around_end) end Before('@before') do - log :before + log(:before) end After('@after') do |scenario| - log :after + log(:after) end """ And a file named "features/around_hook_covers_background.feature" with: @@ -46,7 +45,7 @@ And log only formatter is declared Scenario: Around hooks cover background steps - When I run `cucumber features/around_hook_covers_background.feature --format LogOnlyFormatter` + When I run `cucumber features/around_hook_covers_background.feature --format LogOnlyFormatter --publish-quiet` Then the output should contain: """ around_begin @@ -54,9 +53,10 @@ scenario_step around_end """ + And the exit status should be 0 Scenario: All hooks execute in expected order - When I run `cucumber features/all_hook_order.feature --format LogOnlyFormatter` + When I run `cucumber features/all_hook_order.feature --format LogOnlyFormatter --publish-quiet` Then the output should contain: """ around_begin @@ -66,3 +66,4 @@ after around_end """ + And the exit status should be 0 diff --git a/features/lib/step_definitions/cucumber_steps.rb b/features/lib/step_definitions/cucumber_steps.rb index 32eb82a7d7..dc7c830d33 100644 --- a/features/lib/step_definitions/cucumber_steps.rb +++ b/features/lib/step_definitions/cucumber_steps.rb @@ -15,8 +15,8 @@ ' @io = config.out_stream', ' end', '', - ' def attach(src, media_type)', - ' @io.puts src', + ' def attach(src, media_type, _filename)', + ' @io.puts(src)', ' end', 'end' ].join("\n")) diff --git a/gem_tasks/examples.rake b/gem_tasks/examples.rake index 1b1792b213..0b8225a4ab 100644 --- a/gem_tasks/examples.rake +++ b/gem_tasks/examples.rake @@ -3,7 +3,7 @@ desc 'Run all examples' task :examples do Dir['examples/*'].each do |example_dir| - next if !File.directory?(example_dir) || %w[examples/tcl].index(example_dir) + next unless File.directory?(example_dir) puts "Running #{example_dir}" Dir.chdir(example_dir) do diff --git a/gem_tasks/rspec.rake b/gem_tasks/rspec.rake index e9f5accbbf..3aa0e1b0ea 100644 --- a/gem_tasks/rspec.rake +++ b/gem_tasks/rspec.rake @@ -5,4 +5,5 @@ require 'rspec/core/rake_task' desc 'Run RSpec' RSpec::Core::RakeTask.new do |t| t.verbose = true + t.rspec_opts = '--tag ~cck' end diff --git a/lib/cucumber/formatter/console.rb b/lib/cucumber/formatter/console.rb index 6500ae1759..a27bf94a0f 100644 --- a/lib/cucumber/formatter/console.rb +++ b/lib/cucumber/formatter/console.rb @@ -169,12 +169,17 @@ def do_print_passing_wip(passed_messages) end end - def attach(src, media_type) + def attach(src, media_type, filename) return unless media_type == 'text/x.cucumber.log+plain' return unless @io @io.puts - @io.puts(format_string(src, :tag)) + if filename + @io.puts("#{filename}: #{format_string(src, :tag)}") + else + @io.puts(format_string(src, :tag)) + end + @io.flush end diff --git a/lib/cucumber/formatter/json.rb b/lib/cucumber/formatter/json.rb index 6b1e0f9f41..6e7b7aedee 100644 --- a/lib/cucumber/formatter/json.rb +++ b/lib/cucumber/formatter/json.rb @@ -85,7 +85,7 @@ def on_test_run_finished(_event) @io.write(JSON.pretty_generate(@feature_hashes)) end - def attach(src, mime_type) + def attach(src, mime_type, _filename) if mime_type == 'text/x.cucumber.log+plain' test_step_output << src return diff --git a/lib/cucumber/formatter/message_builder.rb b/lib/cucumber/formatter/message_builder.rb index 3e52d69252..e834b46b6a 100644 --- a/lib/cucumber/formatter/message_builder.rb +++ b/lib/cucumber/formatter/message_builder.rb @@ -42,11 +42,12 @@ def output_message raise 'To be implemented' end - def attach(src, media_type) + def attach(src, media_type, filename) attachment_data = { test_step_id: @current_test_step_id, test_case_started_id: @current_test_case_started_id, - media_type: media_type + media_type: media_type, + file_name: filename } if media_type.start_with?('text/') @@ -192,10 +193,13 @@ def on_test_step_finished(event) result_message = result.to_message if result.failed? || result.pending? + message_element = result.failed? ? result.exception : result + result_message = Cucumber::Messages::TestStepResult.new( status: result_message.status, duration: result_message.duration, - message: create_error_message(result) + message: create_error_message(message_element), + exception: create_exception_object(result, message_element) ) end @@ -211,12 +215,17 @@ def on_test_step_finished(event) output_envelope(message) end - def create_error_message(result) - message_element = result.failed? ? result.exception : result + def create_error_message(message_element) message = "#{message_element.message} (#{message_element.class})" ([message] + message_element.backtrace).join("\n") end + def create_exception_object(result, message_element) + return unless result.failed? + + Cucumber::Messages::Exception.from_h({ type: message_element.class, message: message_element.message }) + end + def on_test_case_finished(event) message = Cucumber::Messages::Envelope.new( test_case_finished: Cucumber::Messages::TestCaseFinished.new( diff --git a/lib/cucumber/formatter/pretty.rb b/lib/cucumber/formatter/pretty.rb index c4b0848910..49ebf89724 100644 --- a/lib/cucumber/formatter/pretty.rb +++ b/lib/cucumber/formatter/pretty.rb @@ -140,10 +140,14 @@ def on_test_run_finished(_event) print_summary end - def attach(src, media_type) + def attach(src, media_type, filename) return unless media_type == 'text/x.cucumber.log+plain' - @test_step_output.push src + if filename + @test_step_output.push("#{filename}: #{src}") + else + @test_step_output.push(src) + end end private diff --git a/lib/cucumber/glue/proto_world.rb b/lib/cucumber/glue/proto_world.rb index a898628b44..e5718cc17d 100644 --- a/lib/cucumber/glue/proto_world.rb +++ b/lib/cucumber/glue/proto_world.rb @@ -7,7 +7,7 @@ module Cucumber module Glue - # Defines the basic API methods availlable in all Cucumber step definitions. + # Defines the basic API methods available in all Cucumber step definitions. # # You can, and probably should, extend this API with your own methods that # make sense in your domain. For more on that, see {Cucumber::Glue::Dsl#World} @@ -86,14 +86,17 @@ def log(*messages) # @param file [string|io] the file to attach. # It can be a string containing the file content itself, the file path, or an IO ready to be read. # @param media_type [string] the media type. - # If file is a valid path, media_type can be omitted, it will then be inferred from the file name. - def attach(file, media_type = nil) + # If file is a valid path, media_type can be omitted, it will then be inferred from the file name. + # @param filename [string] the name of the file you wish to specify. + # This is only needed in situations where you want to rename a PDF download e.t.c. - In most situations + # you should not need to pass a filename + def attach(file, media_type = nil, filename = nil) return super unless File.file?(file) content = File.read(file, mode: 'rb') media_type = MiniMime.lookup_by_filename(file)&.content_type if media_type.nil? - super(content, media_type.to_s) + super(content, media_type.to_s, filename) rescue StandardError super end @@ -152,8 +155,8 @@ def add_modules!(world_modules, namespaced_world_modules) runtime.ask(question, timeout_seconds) end - define_method(:attach) do |file, media_type| - runtime.attach(file, media_type) + define_method(:attach) do |file, media_type, filename| + runtime.attach(file, media_type, filename) end # Prints the list of modules that are included in the World diff --git a/lib/cucumber/glue/registry_and_more.rb b/lib/cucumber/glue/registry_and_more.rb index 653bebeebb..b404ce4b30 100644 --- a/lib/cucumber/glue/registry_and_more.rb +++ b/lib/cucumber/glue/registry_and_more.rb @@ -198,16 +198,19 @@ def self.cli_snippet_type_options private def parameter_type_envelope(parameter_type) - # TODO: should me moved to Cucumber::Expression::ParameterType#to_envelope ? + # TODO: should this be moved to Cucumber::Expression::ParameterType#to_envelope ?? # Note: that would mean that cucumber-expression would depend on cucumber-messages - Cucumber::Messages::Envelope.new( parameter_type: Cucumber::Messages::ParameterType.new( id: @configuration.id_generator.new_id, name: parameter_type.name, regular_expressions: parameter_type.regexps.map(&:to_s), - prefer_for_regular_expression_match: parameter_type.prefer_for_regexp_match?, - use_for_snippets: parameter_type.use_for_snippets? + prefer_for_regular_expression_match: parameter_type.prefer_for_regexp_match, + use_for_snippets: parameter_type.use_for_snippets, + source_reference: Cucumber::Messages::SourceReference.new( + uri: parameter_type.transformer.source_location[0], + location: Cucumber::Messages::Location.new(line: parameter_type.transformer.source_location[1]) + ) ) ) end diff --git a/lib/cucumber/runtime/user_interface.rb b/lib/cucumber/runtime/user_interface.rb index ab78e0d24d..433ef8273f 100644 --- a/lib/cucumber/runtime/user_interface.rb +++ b/lib/cucumber/runtime/user_interface.rb @@ -41,8 +41,8 @@ def ask(question, timeout_seconds) # be a path to a file, or if it's an image it may also be a Base64 encoded image. # The embedded data may or may not be ignored, depending on what kind of formatter(s) are active. # - def attach(src, media_type) - @visitor.attach(src, media_type) + def attach(src, media_type, filename) + @visitor.attach(src, media_type, filename) end private diff --git a/spec/cucumber/cli/configuration_spec.rb b/spec/cucumber/cli/configuration_spec.rb index 641dca35c5..e623949fe8 100644 --- a/spec/cucumber/cli/configuration_spec.rb +++ b/spec/cucumber/cli/configuration_spec.rb @@ -45,8 +45,6 @@ def reset_config end context 'when using the --profile flag' do - include RSpec::WorkInProgress - it 'expands args from profiles in the cucumber.yml file' do given_cucumber_yml_defined_as('bongo' => '--require from/yml') config.parse!(%w[--format progress --profile bongo]) diff --git a/spec/cucumber/cli/profile_loader_spec.rb b/spec/cucumber/cli/profile_loader_spec.rb index 75827193ed..825324c68d 100644 --- a/spec/cucumber/cli/profile_loader_spec.rb +++ b/spec/cucumber/cli/profile_loader_spec.rb @@ -16,7 +16,7 @@ def given_cucumber_yml_defined_as(hash_or_string) end context 'when on a Windows OS' do - before { skip('Only run these tests on non-Windows') unless Cucumber::WINDOWS } + before { skip('These tests are only to be ran on Windows') unless Cucumber::WINDOWS } it 'treats backslashes as literals in rerun.txt when on Windows (JRuby or MRI)' do given_cucumber_yml_defined_as('default' => '--format "pretty" features\sync_imap_mailbox.feature:16:22') @@ -54,7 +54,7 @@ def given_cucumber_yml_defined_as(hash_or_string) end context 'when on non-Windows OS' do - before { skip('Only run these tests on non-Windows') if Cucumber::WINDOWS } + before { skip('These tests are only to be ran on a "Non-Windows" OS') if Cucumber::WINDOWS } it 'treats backslashes as literals in rerun.txt when on Windows (JRuby or MRI)' do given_cucumber_yml_defined_as('default' => '--format "pretty" features\sync_imap_mailbox.feature:16:22') diff --git a/spec/cucumber/glue/step_definition_spec.rb b/spec/cucumber/glue/step_definition_spec.rb index efab3f6154..03c7782072 100644 --- a/spec/cucumber/glue/step_definition_spec.rb +++ b/spec/cucumber/glue/step_definition_spec.rb @@ -198,7 +198,7 @@ def step_match(text) context 'allows log' do it 'calls "attach" with the correct media type' do - expect(user_interface).to receive(:attach).with('wasup', 'text/x.cucumber.log+plain') + expect(user_interface).to receive(:attach).with('wasup', 'text/x.cucumber.log+plain', nil) dsl.Given(/Loud/) do log 'wasup' end @@ -206,7 +206,7 @@ def step_match(text) end it 'calls `to_s` if the message is not a String' do - expect(user_interface).to receive(:attach).with('["Not", 1, "string"]', 'text/x.cucumber.log+plain') + expect(user_interface).to receive(:attach).with('["Not", 1, "string"]', 'text/x.cucumber.log+plain', nil) dsl.Given(/Loud/) do log ['Not', 1, 'string'] end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7cbdd135af..18c0c0c6e4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,29 +3,9 @@ ENV['CUCUMBER_COLORS'] = nil $LOAD_PATH.unshift(File.dirname(__FILE__)) -# For Travis.... -require 'cucumber/encoding' - require 'simplecov_setup' - -require 'pry' - require 'cucumber' RSpec.configure do |c| - c.before do - ::Cucumber::Term::ANSIColor.coloring = true - end -end - -module RSpec - module WorkInProgress - def pending_under(platforms, reason, &block) - if [platforms].flatten.map(&:to_s).include? RUBY_PLATFORM - pending "pending under #{platforms.inspect} because: #{reason}", &block - else - yield - end - end - end + c.before { Cucumber::Term::ANSIColor.coloring = true } end