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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With