Skip to content

Commit 0af120a

Browse files
authored
fix: match request body json otp26 (#213)
* handle request body differently if it is json * Revert "handle request body differently if it is json" This reverts commit 02cf526. * only add the code without formatting * revert formatting change * remove jason * add a test with a map
1 parent 8c942fe commit 0af120a

File tree

3 files changed

+133
-15
lines changed

3 files changed

+133
-15
lines changed
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[
2+
{
3+
"request": {
4+
"body": "{\"address\":{\"city\":\"Los Angeles\",\"state\":\"CA\",\"street\":\"123 Main St\",\"zip\":\"90001\"},\"age\":30,\"city\":\"New York\",\"country\":\"USA\",\"favoriteColor\":\"blue\",\"hobbies\":[\"reading\",\"traveling\",\"swimming\"],\"isMarried\":true,\"name\":\"John\",\"phoneNumbers\":[{\"number\":\"555-555-1234\",\"type\":\"home\"},{\"number\":\"555-555-5678\",\"type\":\"work\"}]}",
5+
"headers": [],
6+
"method": "post",
7+
"options": [],
8+
"request_body": "",
9+
"url": "http://httpbin.org/post"
10+
},
11+
"response": {
12+
"binary": false,
13+
"body": "{\n \"args\": {}, \n \"data\": \"{\\\"address\\\":{\\\"city\\\":\\\"Los Angeles\\\",\\\"state\\\":\\\"CA\\\",\\\"street\\\":\\\"123 Main St\\\",\\\"zip\\\":\\\"90001\\\"},\\\"age\\\":30,\\\"city\\\":\\\"New York\\\",\\\"country\\\":\\\"USA\\\",\\\"favoriteColor\\\":\\\"blue\\\",\\\"hobbies\\\":[\\\"reading\\\",\\\"traveling\\\",\\\"swimming\\\"],\\\"isMarried\\\":true,\\\"name\\\":\\\"John\\\",\\\"phoneNumbers\\\":[{\\\"number\\\":\\\"555-555-1234\\\",\\\"type\\\":\\\"home\\\"},{\\\"number\\\":\\\"555-555-5678\\\",\\\"type\\\":\\\"work\\\"}]}\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Content-Length\": \"323\", \n \"Host\": \"httpbin.org\", \n \"User-Agent\": \"mint/1.5.1\", \n \"X-Amzn-Trace-Id\": \"Root=1-6502b298-152ed17e42e07eca56f829aa\"\n }, \n \"json\": {\n \"address\": {\n \"city\": \"Los Angeles\", \n \"state\": \"CA\", \n \"street\": \"123 Main St\", \n \"zip\": \"90001\"\n }, \n \"age\": 30, \n \"city\": \"New York\", \n \"country\": \"USA\", \n \"favoriteColor\": \"blue\", \n \"hobbies\": [\n \"reading\", \n \"traveling\", \n \"swimming\"\n ], \n \"isMarried\": true, \n \"name\": \"John\", \n \"phoneNumbers\": [\n {\n \"number\": \"555-555-1234\", \n \"type\": \"home\"\n }, \n {\n \"number\": \"555-555-5678\", \n \"type\": \"work\"\n }\n ]\n }, \n \"origin\": \"62.178.80.139\", \n \"url\": \"http://httpbin.org/post\"\n}\n",
14+
"headers": {
15+
"date": "Thu, 14 Sep 2023 07:13:28 GMT",
16+
"content-type": "application/json",
17+
"content-length": "1240",
18+
"connection": "keep-alive",
19+
"server": "gunicorn/19.9.0",
20+
"access-control-allow-origin": "*",
21+
"access-control-allow-credentials": "true"
22+
},
23+
"status_code": 200,
24+
"type": "ok"
25+
}
26+
}
27+
]

lib/exvcr/handler.ex

+32-5
Original file line numberDiff line numberDiff line change
@@ -179,17 +179,44 @@ defmodule ExVCR.Handler do
179179

180180
defp normalize_url(url) do
181181
original_url = URI.parse(url)
182-
183182
original_url
184183
|> Map.put(:query, normalize_query(original_url.query))
185184
|> URI.to_string()
186185
end
187186

188-
defp normalize_request_body(request_body) do
189-
normalize_query(request_body)
187+
defp normalize_request_body(request_body) when is_binary(request_body) do
188+
case JSX.decode(request_body) do
189+
{:ok, decoded} ->
190+
normalize_request_body(decoded)
191+
192+
{:error, _} ->
193+
normalize_query(request_body)
194+
end
195+
end
196+
197+
defp normalize_request_body(request_body) when is_map(request_body) do
198+
request_body
199+
|> Map.to_list()
200+
|> Enum.sort_by(fn {key, _val} -> key end)
201+
|> Enum.map(fn
202+
{key, val} when is_map(val) -> {key, normalize_request_body(val)}
203+
{key, val} when is_list(val) -> {key, normalize_request_body(val)}
204+
{key, val} -> {key, val}
205+
end)
206+
|> URI.encode_query()
207+
end
208+
209+
defp normalize_request_body(request_body) when is_list(request_body) do
210+
request_body
211+
|> Enum.map(fn
212+
val when is_map(val) -> normalize_request_body(val)
213+
val when is_list(val) -> normalize_request_body(val)
214+
val -> val
215+
end)
216+
|> Enum.map_join(&to_string/1)
190217
end
191-
192-
defp normalize_query(nil), do: nil
218+
219+
defp normalize_query(nil), do: nil
193220

194221
defp normalize_query(query) do
195222
query

test/adapter_finch_test.exs

+74-10
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ defmodule ExVCR.Adapter.FinchTest do
66

77
setup_all do
88
HttpServer.start(path: "/server", port: @port, response: "test_response")
9-
on_exit fn ->
9+
10+
on_exit(fn ->
1011
HttpServer.stop(@port)
11-
end
12+
end)
13+
1214
:ok
1315
end
1416

@@ -17,17 +19,20 @@ defmodule ExVCR.Adapter.FinchTest do
1719
ExVCR.Actor.CurrentRecorder.default_state()
1820
|> ExVCR.Actor.CurrentRecorder.set()
1921
end
22+
2023
url = "http://localhost:#{@port}/server"
2124
{:ok, response} = Finch.build(:get, url) |> Finch.request(ExVCRFinch)
2225
assert response.status == 200
2326
end
2427

2528
test "passthrough works after cassette has been used" do
2629
url = "http://localhost:#{@port}/server"
30+
2731
use_cassette "finch_get_localhost" do
2832
{:ok, response} = Finch.build(:get, url) |> Finch.request(ExVCRFinch)
2933
assert response.status == 200
3034
end
35+
3136
{:ok, response} = Finch.build(:get, url) |> Finch.request(ExVCRFinch)
3237
assert response.status == 200
3338
end
@@ -63,7 +68,11 @@ defmodule ExVCR.Adapter.FinchTest do
6368
test "request with HTTPError" do
6469
use_cassette "finch_httperror", custom: true do
6570
{:error, response} = Finch.build(:get, "http://example.com/") |> Finch.request(ExVCRFinch)
66-
assert response == %Mint.HTTPError{module: Mint.HTTP2, reason: :too_many_concurrent_requests}
71+
72+
assert response == %Mint.HTTPError{
73+
module: Mint.HTTP2,
74+
reason: :too_many_concurrent_requests
75+
}
6776
end
6877
end
6978

@@ -90,31 +99,84 @@ defmodule ExVCR.Adapter.FinchTest do
9099

91100
test "post method" do
92101
use_cassette "finch_post" do
93-
assert_response Finch.build(:post, "http://httpbin.org/post", [], "test") |> Finch.request(ExVCRFinch)
102+
assert_response(
103+
Finch.build(:post, "http://httpbin.org/post", [], "test")
104+
|> Finch.request(ExVCRFinch)
105+
)
106+
end
107+
end
108+
109+
@tag :wip
110+
test "post method with json body" do
111+
use_cassette "finch_post_map" do
112+
assert_response(
113+
Finch.build(
114+
:post,
115+
"http://httpbin.org/post",
116+
[],
117+
JSX.encode!(%{
118+
name: "John",
119+
age: 30,
120+
city: "New York",
121+
country: "USA",
122+
isMarried: true,
123+
hobbies: ["reading", "traveling", "swimming"],
124+
address: %{
125+
street: "123 Main St",
126+
city: "Los Angeles",
127+
state: "CA",
128+
zip: "90001"
129+
},
130+
phoneNumbers: [
131+
%{
132+
type: "home",
133+
number: "555-555-1234"
134+
},
135+
%{
136+
type: "work",
137+
number: "555-555-5678"
138+
}
139+
],
140+
favoriteColor: "blue"
141+
})
142+
)
143+
|> Finch.request(ExVCRFinch)
144+
)
94145
end
95146
end
96147

97148
test "put method" do
98149
use_cassette "finch_put" do
99-
assert_response Finch.build(:put, "http://httpbin.org/put", [], "test") |> Finch.request(ExVCRFinch, receive_timeout: 10_000)
150+
assert_response(
151+
Finch.build(:put, "http://httpbin.org/put", [], "test")
152+
|> Finch.request(ExVCRFinch, receive_timeout: 10_000)
153+
)
100154
end
101155
end
102156

103157
test "patch method" do
104158
use_cassette "finch_patch" do
105-
assert_response Finch.build(:patch, "http://httpbin.org/patch", [], "test") |> Finch.request(ExVCRFinch)
159+
assert_response(
160+
Finch.build(:patch, "http://httpbin.org/patch", [], "test")
161+
|> Finch.request(ExVCRFinch)
162+
)
106163
end
107164
end
108165

109166
test "delete method" do
110167
use_cassette "finch_delete" do
111-
assert_response Finch.build(:delete, "http://httpbin.org/delete") |> Finch.request(ExVCRFinch, receive_timeout: 10_000)
168+
assert_response(
169+
Finch.build(:delete, "http://httpbin.org/delete")
170+
|> Finch.request(ExVCRFinch, receive_timeout: 10_000)
171+
)
112172
end
113173
end
114174

115175
test "get fails with timeout" do
116176
use_cassette "finch_get_timeout" do
117-
{:error, error} = Finch.build(:get, "http://example.com") |> Finch.request(ExVCRFinch, receive_timeout: 1)
177+
{:error, error} =
178+
Finch.build(:get, "http://example.com") |> Finch.request(ExVCRFinch, receive_timeout: 1)
179+
118180
assert error == %Mint.TransportError{reason: :timeout}
119181
end
120182
end
@@ -128,13 +190,15 @@ defmodule ExVCR.Adapter.FinchTest do
128190

129191
use_cassette "example_finch_different" do
130192
assert_raise ExVCR.RequestNotMatchError, ~r/different_from_original/, fn ->
131-
{:ok, _response} = Finch.build(:get, "http://example.com/different_from_original") |> Finch.request(ExVCRFinch)
193+
{:ok, _response} =
194+
Finch.build(:get, "http://example.com/different_from_original")
195+
|> Finch.request(ExVCRFinch)
132196
end
133197
end
134198
end
135199

136200
test "stub request works for Finch" do
137-
use_cassette :stub, [url: "http://example.com/", body: "Stub Response", status_code: 200] do
201+
use_cassette :stub, url: "http://example.com/", body: "Stub Response", status_code: 200 do
138202
{:ok, response} = Finch.build(:get, "http://example.com") |> Finch.request(ExVCRFinch)
139203
assert response.body =~ ~r/Stub Response/
140204
assert Map.new(response.headers)["content-type"] == "text/html"

0 commit comments

Comments
 (0)