I have some issues running tests on a Phoenix controller.
What I want is to supply a list of maps to it, but if I do just that, I get Argument Error
.
Test code
params =
[
%{"id" => 1, "sum" => 6},
%{"id" => 2, "sum" => 4}
]
conn =
conn
|> put(Routes.stat_path(conn, :replace_all), params)
The error
** (ArgumentError) argument error
code: |> put(Routes.stat_path(conn, :replace_all), params)
stacktrace:
(stdlib 4.0.1) :maps.from_list([%{"id" => 1, "sum" => 6}, %{"id" => 2, "sum" => 4}])
(elixir 1.13.4) lib/enum.ex:1448: Enum.into_map/1
(plug 1.14.0) lib/plug/adapters/test/conn.ex:161: Plug.Adapters.Test.Conn.body_or_params/4
(plug 1.14.0) lib/plug/adapters/test/conn.ex:21: Plug.Adapters.Test.Conn.conn/4
(phoenix 1.6.15) lib/phoenix/test/conn_test.ex:236: Phoenix.ConnTest.dispatch_endpoint/5
(phoenix 1.6.15) lib/phoenix/test/conn_test.ex:225: Phoenix.ConnTest.dispatch/5
test/myapp_web/controllers/stat_controller_test.exs:15: (test)
I decided to do a small change and encode JSON myself in the tests:
params =
[
%{"id" => 1, "sum" => 6},
%{"id" => 2, "sum" => 4}
]
|> Jason.encode!()
conn =
conn
# this line is required for binary data
|> put_req_header("content-type", "application/json")
|> put(Routes.stat_path(conn, :replace_all), params)
What I get in the controller now is a bit strange. My data is wrapped into a map with _json
key, so instead of the list (which I need) I get this map:
%{"_json" => [%{"id" => 1, "sum" => 6}, %{"id" => 2, "sum" => 4}]}
What I'm doing wrong and how to properly test a Phoenix controller in case I want to supply a list of maps into it?
The culprit is Plug.Parsers.JSON
.
JSON
documents that aren’t maps (arrays, strings, numbers, etc) are parsed into a"_json"
key to allow proper param merging.
Quoting José from this answer:
You cannot [avoid wrapping] because
conn.params
is a map. So if we set it to alist
, other parts of plug will fail. But the list is stored as is under_json
. You can also disablePlug.Parsers.JSON
and roll your own parser.
That said, for this particular request you are to roll on your own parsed.