Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there a way to do hash_excluding matching? #443

Open
x-yuri opened this issue Jan 1, 2015 · 7 comments
Open

Is there a way to do hash_excluding matching? #443

x-yuri opened this issue Jan 1, 2015 · 7 comments

Comments

@x-yuri
Copy link

x-yuri commented Jan 1, 2015

Like so:

require 'webmock'
include WebMock::API
stub_request(:post, 'http://example.com/path')
  .with(body: hash_excluding({a: '1'}))
  .to_return(body: 'b1')
puts Net::HTTP.post_form(URI('http://example.com/path'), {b: '2'}).body

rspec has this matcher, but it doesn't seem to work for webmock.

@x-yuri
Copy link
Author

x-yuri commented Jan 1, 2015

For now there's this workaround for ruby 2.0+:

module BodyPatternExtensions
  def matches?(body, content_type = "")
    if @pattern.instance_of?(RSpec::Mocks::ArgumentMatchers::HashExcludingMatcher)
      @pattern === body_as_hash(body, content_type)
    else
      super
    end
  end
end

module WebMock
  class BodyPattern
    prepend BodyPatternExtensions
  end
end

@bblimke
Copy link
Owner

bblimke commented Jan 2, 2015

@x-yuri There is no way to do it, unless you use custom matching block.

Nice workaround though.

The proper solution would require adding hash_excluding matcher to WebMock,
to make it independent from RSpec.

Perhaps it's worth adding a change to WebMock and allow it to accept any kind of RSpec::Mocks::ArgumentMatchers::* matcher.

@x-yuri
Copy link
Author

x-yuri commented Jan 2, 2015

There is no way to do it, unless you use custom matching block.

By custom matching block you must be meaning this:

stub_request(:post, 'http://example.com/path')
  .with { |request| hash_excluding(a: '1') === Rack::Utils.parse_nested_query(request.body) }

Which brings the question, if I can call with several times to not end up with only custom matching.

Perhaps it's worth adding a change to WebMock and allow it to accept any kind of RSpec::Mocks::ArgumentMatchers::* matcher.

But there are not only hash matchers there. How will you know what to pass to any one of them?

@ab
Copy link

ab commented Jun 5, 2016

👍

This is a pain for places where you want to ensure that a given header is not present, since webmock will match any superset of the expected values. (i.e. trying to do the opposite case from #276)

@phantomwhale
Copy link

phantomwhale commented Feb 14, 2019

Ran into this issue today - guessing it's still awaiting a PR, as it hit me too, returning a

undefined method map for #<RSpec::Mocks::ArgumentMatchers::HashExcludingMatcher

(mostly leaving this comment to add to the google-ability of this line to get to this issue)

Will try the workaround for now... and sadly it doesn't seem to work - the above issue still gets triggered. Guess the monkey patch above is a few years old now :)

@Kevin-McGonigle
Copy link

In a similar situation where I'm trying to ensure the abscence of a certain header, rather than its presence - not seeing a nice way to go about it.

@lucasarnaud
Copy link
Contributor

I was facing a similar issue
Browsing the code I found it was not working because when the registered stubs are being tested for a match HashExcludingMatcher (that is created by hash_excluding) is not handling the request body as a Hash, which is the behavior for HashIncludingMatcher (that works)

I opened this Pull Request as a suggestion to fix this issue:

elsif (@pattern).is_a?(WebMock::Matchers::HashIncludingMatcher)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants