Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-use failure message in rspec custom matcher

Tags:

ruby

rspec

I have a custom matcher that uses expects in it's match block (the code here is simplified)

RSpec::Matchers.define :have_foo_content do |expected|
  match do |actual|
    expect(actual).to contain_exactly(expected)
    expect(actual.foo).to contain_exactly(expected.foo)
  end
end

Normally the error message would look like this

       expected collection contained:  ["VLPpzkjahD"]
       actual collection contained:    ["yBzPmoRnSK"]
       the missing elements were:      ["VLPpzkjahD"]
       the extra elements were:        ["yBzPmoRnSK"]

But when using a custom matcher, it only prints this, and important debug information gets lost:

expected MyObject to have_foo_content "foobar"

So, is it possible to re-use a error message from the match block as a failure message? I know I can provide custom failure messages with

failure_message do |actual|
  # ...
end

But I don't know how you could access the failure message the error above has raised.

like image 892
23tux Avatar asked Oct 18 '19 09:10

23tux


2 Answers

You can rescue RSpec::Expectations::ExpectationNotMetError in your match to catch the failed expectation message:

  match do |object|
    begin
      expect(object).to be_nil
    rescue RSpec::Expectations::ExpectationNotMetError => e
      @error = e
      raise
    end
  end

  failure_message do
    <<~MESSAGE
      Expected object to meet my custom matcher expectation but failed with error:
      #{@error}
    MESSAGE
  end

Don't forget to re-raise in the rescue, otherwise it won't work

like image 73
Geoffroy Avatar answered Nov 20 '22 12:11

Geoffroy


There is no direct method available to yield original error, I would suggest you to write your own logic to generate similar message.

If you still want to use the existing method, there is a private method which you can call and it will return the default error message. You may need to set some instance variables expected_value, actual_value etc.

RSpec::Matchers::BuiltIn::ContainExactly.new(expected_value).failure_message

reference code

like image 27
Hardik Avatar answered Nov 20 '22 13:11

Hardik