Webmock: hash_including for Headers

Created on 11 Apr 2013  路  19Comments  路  Source: bblimke/webmock

I would really like to use the hash_including matcher on HTTP Headers:

stub_request(:post, 'https://test.host').
      with(
        body: expected_body
        headers: hash_including(expected_headers))

However I am getting this error:

     Failure/Error: stub_request(:post, 'https://test.host').
 NoMethodError:
   undefined method `map' for #<RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher:0x007fc81488e530>

I suppose it is raised on this line

Most helpful comment

Headers are matched by default if request headers include stub headers. It's enough if stub headers are a subset of request headers. There is no need to use hash_including.

All 19 comments

:+1: had the same issue. Ended up with this workaround:

      assert_requested(:get, @url) do |req|
        req.headers["Foo"] == "Bar"
      end

Will look into fixing this in Webmock next, seems a bit tricky.

You could try
stub_request(:post, 'https://test.host').
to_return(
body: expected_body
headers: hash_including(expected_headers))

I'm having the same problem:

      auth = ActionController::HttpAuthentication::Basic.encode_credentials('yah', 'yah')
      headers = { :authorization => auth }
      WebMock.stub_request(:any, /\Ahttp:\/\/localhost:3000\/.*\/newsletter\Z/).with(:headers => hash_including(headers)).to_return(:status => 200, :body => '<html></html>')

Headers are matched by default if request headers include stub headers. It's enough if stub headers are a subset of request headers. There is no need to use hash_including.

as described in README, request is matched if "request headers match stubbed request headers, or stubbed request headers match a subset of request headers, or stubbed request headers are not specified"

Thanks @bblimke That worked for me. I had copied the body example and tried to modify it.

:+1:

Headers are matched by default if request headers include stub headers. It's enough if stub headers are a subset of request headers. There is no need to use hash_including.

Unfortunately this doesn't seem to be the case if you use have_requested.

      expect(WebMock).to have_requested(:get, ...").
        with(:headers => { 'Accept' => 'application/json', 'Foo' => 'Bar' })

doesn't pass if other than Accept and Foo you have other headers.

@weppos It matches if there are more headers in the request than expected. Please have a look here:

https://github.com/bblimke/webmock/blob/master/spec/acceptance/shared/request_expectations.rb#L380-L388

Please provide a failing code sample.

You can see an example here.
https://github.com/aetrion/dnsimple-ruby/blob/102ce131bebfd9be2adb0b5c296893e2b9e94886/spec/dnsimple/user_spec.rb#L43-L45

If I use

    it "builds the correct request" do
      described_class.two_factor_exchange_token(otp_token)

      expect(WebMock).to have_requested(:get, "https://#{CONFIG['username']}:#{CONFIG['password']}@#{CONFIG['host']}/v1/user").
        # workaround for https://github.com/bblimke/webmock/issues/276
        with(headers: hash_including('X-Dnsimple-Otp' => otp_token))
    end

the test fails with

     NoMethodError:
       undefined method `map' for #<RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher:0x007fa6bc15a9e0>
     # /Users/weppos/.rvm/gems/ruby-2.1.5@dnsimple-ruby/gems/webmock-1.20.4/lib/webmock/util/headers.rb:9:in `normalize_headers'
     # /Users/weppos/.rvm/gems/ruby-2.1.5@dnsimple-ruby/gems/webmock-1.20.4/lib/webmock/request_pattern.rb:292:in `initialize'
     # /Users/weppos/.rvm/gems/ruby-2.1.5@dnsimple-ruby/gems/webmock-1.20.4/lib/webmock/request_pattern.rb:55:in `new'
     # /Users/weppos/.rvm/gems/ruby-2.1.5@dnsimple-ruby/gems/webmock-1.20.4/lib/webmock/request_pattern.rb:55:in `assign_options'
     # /Users/weppos/.rvm/gems/ruby-2.1.5@dnsimple-ruby/gems/webmock-1.20.4/lib/webmock/request_pattern.rb:24:in `with'
     # /Users/weppos/.rvm/gems/ruby-2.1.5@dnsimple-ruby/gems/webmock-1.20.4/lib/webmock/rspec/matchers/webmock_matcher.rb:20:in `with'

@weppos There is no need to use hash_including. Headers are matched if expected headers are a subset of received headers.

@bblimke I made the change... and it worked! I swear it didn't work in the old days. :(

@weppos I'm glad it works now :)

weirdly, I am having the same problem as the OP :/
When I omit hash_including Webmocks complains that the headers were not as expected.

Nevermind. It was user error :) ... I had a typo in my headers. Confirming that it works alright without using hash_including

For anyone that landed here: https://stackoverflow.com/a/49360133/2724342

Web mock header and params need to be an exact match. Most mismatched is from symbol/string keys.

I understand that header matching only occurs on the subset of headers passed into the with(headers: ...subset...) method and this matches most of the hash_including functionality. It seems that hash_including can also match on keys being present (without values being specified, ie hash_including(:key1, :key2)). Is there a way to do that in a with(headers: KEYS_THAT_MUST_APPEAR) statement?

And how about hash_excluding? I'd like to test that my headers didn't not include any Authorization key.

I think my use case is the inverse of that - verify that headers include an Authorization key but I don't care what it is specifically (in fact I might not even be able to know a priori).

@jdalt I wasn't really offering a solution to your problem but more adding another use case where it would help to be able to use matchers

Was this page helpful?
0 / 5 - 0 ratings

Related issues

majioa picture majioa  路  4Comments

Watson1978 picture Watson1978  路  4Comments

Integralist picture Integralist  路  5Comments

j-mcnally picture j-mcnally  路  7Comments

lokenmakwana picture lokenmakwana  路  6Comments