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

Tests with the combination of strict_mode and FlatParamsEncoder may fail #1411

Closed
yykamei opened this issue Apr 13, 2022 · 6 comments
Closed
Labels

Comments

@yykamei
Copy link
Contributor

yykamei commented Apr 13, 2022

With strict_mode, the Testing adapter tries to check the equality of parameters here.

return Set.new(params) == Set.new(request_params)

This check sometimes return false with FlatParamsEncoder because an array value may contain elements by different order. For example,

stubs = Faraday::Adapter::Test::Stubs.new do |stub|
  stub.get("/foo?key=123&key=234&key=abc") do |_env|
    [200, { content_type: "application/json" }, JSON.dump(status: "OK")]
  end
end
conn = Faraday.new { |b| b.adapter(:test, stubs) }
conn.get("/foo", { key: [123, 234, "abc"] })
stubs.verify_stubbed_calls # => Error with this comparison: `Set.new(key: [123, 234, "abc]) == Set.new(key: ["abc", 123, 234])`

In general, the order of query is not important, so I want to check keys without order.

What do you think?

Related PRs: #1298 #1316

@iMacTia
Copy link
Member

iMacTia commented Apr 18, 2022

This makes sense, but I can see someone coming in future and asking how to write a test that also checks the specific order of things...
Ideally, it would be great to support both scenarios and let the developer choose which one they want to apply in any given case. I'd also feel reluctant in changing the current behaviour as this would cause existing tests relying on the adapter to fail.

A possible solution to all these points could be the following:

  • We keep the current behaviour as-is
  • We extend the test adapter capabilities so that query parameters in the stub can be passed as a separate argument, rather than as part of the URI (e.g. stub.get('/foo', query: { key: [123, 234, "abc"] }))
  • We allow to pass RSpec matchers as values for query, similarly to how Webmock allows you to do

I like this because it would be flexible enough to support all cases, while also keeping the existing behaviour, but I'm not sure about the complexity of such a change, so I'm open to alternative suggestions as far as they respect the points I highlighted above!

@yykamei
Copy link
Contributor Author

yykamei commented Apr 18, 2022

Oh, I understood FlatParamsEncoder has a feature to sort parameters.

params.sort! if @sort_params

As you said, it would be necessary for someone who wants to check the specific order of parameter values.

Introducing query looks great 👍 Of course, the Test adapter must consider parameters included in path as well as query, but it would be useful to construct parameters with the Hash value. So, I think it's worth implementing 😄

By the way, is query good for the argument name? Faraday's methods seem to use params for the URL query parameters. For example, Connection#get has params for its method argument.

# @param params [Hash] Hash of URI query unencoded key/value pairs.

@iMacTia
Copy link
Member

iMacTia commented Apr 19, 2022

The idea behind using query and body instead of just params is that you'll be able to distinguish them on HTTP methods that support both (e.g. POST).

Of course, the Test adapter must consider parameters included in path as well as query

Good point, I think I see where this is coming from.
Could you show an example of this just to be sure we're on the same page?

@yykamei
Copy link
Contributor Author

yykamei commented Apr 20, 2022

OK, using query makes sense 👍

I think changing here might be the first step:

path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path

Stub seems to have query as a string, but we will have to merge this query with the new parameter query, which comes from the argument of #new_stub. So, I'm considering changing Stub#query from string to Hash.

The example code in #new_stub here.

path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path
query = convert_to_hash(query) # NOTE: convert_to_hash is something like URI.decode_www_form
query.merge!(query_from_args)

stub = Stub.new(host, path, query, headers, body, @strict_mode, block)

@iMacTia
Copy link
Member

iMacTia commented Apr 26, 2022

That makes sense to me, Stub can use any internal representation for query as far as it works in the same way 😄!
Sorry I was sure I got back to you already on this 🙈

@yykamei
Copy link
Contributor Author

yykamei commented Apr 29, 2022

Oh, I misunderstood the implementation of FlatParamesEncoder. I reconsidered this issue and keeping as-is might be the best way. Thanks for thinking about this issue.

By the way, adding query for testing adapters might be a nice to have. This is out of this issue 😄

@yykamei yykamei closed this as completed Apr 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants