rspec-expectations
rspec-expectations copied to clipboard
Custom object display formatting
This is somewhat related to #495, at least in that my use case is using compound matchers against complex objects. I might not need this if diffs are disabled for composed matchers.
The are already signs in the rspec codebase that inspect isn't always the best way to display an object in rspec output, but to_s is usually worse. Right now:
- Compound matchers use
descriptionvia surface_descriptions_in - The eq matcher has special cases
- Time
- DateTime
I think there's may be other cases, and it may make sense to let users customize the formats rather than have it all in rspec-expectations. Two things that might work are:
RSpec::Formatter.definesimilar toRSpec::Matchers.define- Something like:
object.respond_to? :rspec_format ? object.rspec_format : object.inspect
Here's a bit more context on why I'm interested in this. I'm matching on large objects where the inspect output is often far too detailed for my purposes. In my case, it's objects that represent an HTTP request/response (think Faraday/VCR/WebMock response objects).
WebMock::RequestSignature is a good example of where inspect might not be the best dispaly format. The to_s method accurately captures everything important to the matcher in a more compact and readable form than inspect:
rs = WebMock::RequestSignature.new(:post, 'http://www.google.com')
rs.inspect
#=> "#<WebMock::RequestSignature:0x007fd445acdb88 @method=:post, @uri=#<Addressable::URI:0x3fea22d66c48 URI:http://www.google.com:80/>>"
rs.to_s
#=> "POST http://www.google.com/"
So there's a difference in readability between the two in these tests. It looks better if I monkeypatch WebMock::RequestSignature.inspect:
require 'webmock'
require 'webmock/rspec'
# This monkeypatching improves the test output somewhat
class WebMock::RequestSignature
def inspect
to_s
end
end
describe 'request signatures' do
let(:request_signatures) {
5.times.map do |n| WebMock::RequestSignature.new(:get, "http://www.google.com/#{n}") end
}
it 'only calls google' do
expect(request_signatures).to contain_exactly(5.times.map{a_request :get, 'www.google.com'})
end
end
Here's another interesting scenario. Testing an invariant on an HTTP interaction, in this case testing that a request that expects HTTP 100-continue is not getting a full response:
# The server should not send a response
expect(validations).to_not include(
a_request_with(:any, '', :headers => {'Expect' => '100-continue'}).and a_response_with_a_body
)
If one object fails, then it's going to print out the entire set. That set includes responses, some of which have large base64 encoded bodies. So I might want the flexibility to display a shorthand format (e.g. showing the checksum rather than the contents of the body) or at least have it only show the object that existed and shouldn't, instead of the entire set.
I'd support a PR exposing an API allowing you to customise the output of different types, the Differ would be a better place to house that than Formatters though
I think something like this would make sense, but I'd like to defer this to 3.1.
Has this been implemented? I can't find any documentation on it.
It has not been implemented. You can always define inspect on your object, though. For matchers, their description is used in failure messages automatically so that may help.
Closing due to inactivity during the monorepo migration, but if someone wanted to revisit this they'd be welcome.