Skip to content

Ruby 3.4 support? #2820

Closed
Closed
@voxik

Description

@voxik

Trying to run rspec-rails test suite against Ruby 3.4, I encounter test failures such as:

   8) be_a_new matcher #with right class and new record with composable matchers one attribute is a composable matcher fails
     Failure/Error:
       expect {
         expect(record).to be_a_new(record.class).with(
           foo: a_string_matching("bar"))
       }.to raise_error("attribute {\"foo\"=>(a string matching \"bar\")} was not set on #{record.inspect}")

       expected Exception with "attribute {\"foo\"=>(a string matching \"bar\")} was not set on #<#<Class:0x00007fe77b608208>:0x00007fe77b756c68 @attributes={foo: \"foo\", bar: \"bar\"}>", got #<RSpec::Expectations::ExpectationNotMetError: attribute {"foo" => (a string matching "bar")} was not set on #<#<Class:0x00007fe77b608208>:0x00007fe77b756c68 @attributes={foo: "foo", bar: "bar"}>> with backtrace:
         # ./spec/rspec/rails/matchers/be_a_new_spec.rb:75:in 'block (7 levels) in <top (required)>'
         # ./spec/rspec/rails/matchers/be_a_new_spec.rb:77:in 'block (6 levels) in <top (required)>'
         # ./spec/spec_helper.rb:83:in 'block (3 levels) in <top (required)>'
         # ./spec/spec_helper.rb:77:in 'block (2 levels) in <top (required)>'
     # ./spec/rspec/rails/matchers/be_a_new_spec.rb:77:in 'block (6 levels) in <top (required)>'
     # ./spec/spec_helper.rb:83:in 'block (3 levels) in <top (required)>'
     # ./spec/spec_helper.rb:77:in 'block (2 levels) in <top (required)>'

The error message seems to be originating from here:

def failure_message
[].tap do |message|
unless actual.is_a?(expected) && actual.new_record?
message << "expected #{actual.inspect} to be a new #{expected.inspect}"
end
unless attributes_match?(actual)
describe_unmatched_attributes = surface_descriptions_in(unmatched_attributes)
if unmatched_attributes.size > 1
message << "attributes #{describe_unmatched_attributes.inspect} were not set on #{actual.inspect}"
else
message << "attribute #{describe_unmatched_attributes.inspect} was not set on #{actual.inspect}"
end
end
end.join(' and ')
end

Specifically the #{describe_unmatched_attributes.inspect}. Here are some details from binding.irb:

rom: /builddir/build/BUILD/rubygem-rspec-rails-7.1.0-build/rspec-rails-7.1.0/usr/share/gems/gems/rspec-rails-7.1.0/lib/rspec/rails/matchers/be_a_new.rb @ line 36 :

    31:             unless actual.is_a?(expected) && actual.new_record?
    32:               message << "expected #{actual.inspect} to be a new #{expected.inspect}"
    33:             end
    34:             unless attributes_match?(actual)
    35:               describe_unmatched_attributes = surface_descriptions_in(unmatched_attributes)
 => 36:               binding.irb
    37:               if unmatched_attributes.size > 1
    38:                 message << "attributes #{describe_unmatched_attributes.inspect} were not set on #{actual.inspect}"
    39:               else
    40:                 message << "attribute #{describe_unmatched_attributes.inspect} was not set on #{actual.inspect}"
    41:               end

irb(#<RSpec::Rails::Matchers::BeA...):001> p unmatched_attributes
{"foo" => #<RSpec::Matchers::BuiltIn::Match:0x00007fa0e04f40b0 @expected="bar", @expected_captures=nil, @matcher_name=:a_string_matching>}
=> {"foo" => #<RSpec::Matchers::BuiltIn::Match:0x00007fa0e04f40b0 @expected="bar", @expected_captures=nil, @matcher_name=:a_string_matching>}
irb(#<RSpec::Rails::Matchers::BeA...):002> p surface_descriptions_in(unmatched_attributes)
{"foo" => (a string matching "bar")}
=> {"foo" => (a string matching "bar")}
irb(#<RSpec::Rails::Matchers::BeA...):003> 

Obviously Ruby 3.4 changes the Hash formatting adding two spaces around hash rocket. The question is how to fix this. Several options:

  1. Only the test cases are adjusted
    • Just add optional spaces
    • Something more elaborated, with Hash#inspect
  2. The backward compatibility of the output is kept, therefore tests stays but the error message is formatted differently

BTW I find the hash like formatting with the brackets a bit unfortunate.

https://github.com/rspec/rspec/blob/60a7a65e195953196fb8d1836257909c56d2da85/rspec-expectations/lib/rspec/matchers/composable.rb#L162

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions