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

Stub request with hash_including #967

Open
leoplct opened this issue Jan 26, 2022 · 4 comments
Open

Stub request with hash_including #967

leoplct opened this issue Jan 26, 2022 · 4 comments

Comments

@leoplct
Copy link

leoplct commented Jan 26, 2022

I am trying to match this url

GET http://example.com/?a=1&b=2&x=1

but it fails. Here a reproducible error.

WebMock.disable_net_connect!
stub_request(:get, "example.com").with(query: hash_including({"x" => 1}))
Net::HTTP.get(URI('http://example.com/?a=1&b=2&x=1'))` 

The error says:

Failure/Error: Net::HTTP.get(URI('http://example.com/?a=1&b=2&x=1'))
     
     WebMock::NetConnectNotAllowedError:
       Real HTTP connections are disabled. Unregistered request: GET http://example.com/?a=1&b=2&x=1 with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Host'=>'example.com', 'User-Agent'=>'Ruby'}

You can stub this request with the following snippet:

     
stub_request(:get, "http://example.com/?a=1&b=2&x=1").
         with(
           headers: {
          'Accept'=>'*/*',
          'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
          'Host'=>'example.com',
          'User-Agent'=>'Ruby'
           }).
         to_return(status: 200, body: "", headers: {})
     
       registered request stubs:
     
       stub_request(:get, "http://example.com/ with query params hash_including({"x"=>1})")
@leoplct
Copy link
Author

leoplct commented Jan 27, 2022

I found the problem is due to "integer" comparison vs "String"

This works.
stub_request(:get, "example.com").with(query: hash_including({"a" => "1"}))
p Net::HTTP.get(URI('http://example.com/?a=1&b=2&x=1'))

@leoplct
Copy link
Author

leoplct commented Jan 28, 2022

I think it makes sense to automatically cast everything to string before doing the Hash diff

@Bodacious
Copy link

I came across this issue yesterday and it took me a while to debug.

After playing around with the Webmock code, I don't think there's a clear solution to fix hash_including directly—since it's defined in RSpec and changing it will undoubtably break other specs that use that method outside of Webmock params.

@bblimke Do you think it would be helpful to add a separate method for this purpose? Something like

def query_hash_including(*args)
  args = args.map { |arg| arg.is_a?(Hash) ? cast_numeric_hash_values_as_strings(arg) : arg }
  hash_including(*args)
end

def cast_numeric_hash_values_as_strings(hash)
  hash.transform_values { |value| value.is_a?(Numeric) ? value.to_s : value }
end

That might allow Webmock users to use integers, floats, or strings in query param expectations, without breaking anything

stub_request(:get, "example.com").with(query: query_hash_including({"a" => "1"}))

@bblimke
Copy link
Owner

bblimke commented Feb 6, 2024

@Bodacious thank you for providing the suggested solution.

I wish HashIncludingMatcher in RSpec provided a public method to get the @expected Hash.
We could then check if the Hash contains any non String values and raise an argument error, explaining the user,
to only match the query against a a hash with string values.

I feel it's more intuitive to use hash_including rather than custom query_hash_including. In addition to that people should learn, what is the difference, when they use query_hash_including.
Perhaps support for hash_including should be deprecated and deprecation message could explain that it needs to be replaced with query_hash_including

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

No branches or pull requests

3 participants