rspec-expectations icon indicating copy to clipboard operation
rspec-expectations copied to clipboard

Custom object display formatting

Open maxlinc opened this issue 11 years ago • 5 comments

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:

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.define similar to RSpec::Matchers.define
  • Something like: object.respond_to? :rspec_format ? object.rspec_format : object.inspect

maxlinc avatar Mar 11 '14 18:03 maxlinc

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.

maxlinc avatar Mar 11 '14 18:03 maxlinc

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

JonRowe avatar Mar 11 '14 20:03 JonRowe

I think something like this would make sense, but I'd like to defer this to 3.1.

myronmarston avatar Mar 11 '14 21:03 myronmarston

Has this been implemented? I can't find any documentation on it.

ghostsquad avatar Jun 09 '17 21:06 ghostsquad

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.

myronmarston avatar Jun 09 '17 21:06 myronmarston

Closing due to inactivity during the monorepo migration, but if someone wanted to revisit this they'd be welcome.

JonRowe avatar Nov 27 '24 21:11 JonRowe