Access `query_params` in `Conn` built from `Plug.Test.conn`

I’m trying to use https://hexdocs.pm/plug/Plug.Test.html to write a test for a very simple Plug, that has to access a query parameters.

The plug can be reduced to this:

defmodule BarPlug do 
 def call(conn, _) do
    conn_with_params = Conn.fetch_query_params(conn)
    bar = conn_with_params.query_params["bar"]
    Conn.assign(conn, :bar, bar)
  end
end

And, naively following the doc, I’m trying to test it with:

defmodule BarPlug.Test do
  use ExUnit.Case, async: true
  use Plug.Test

  test "Reads query params" do
    conn = :get
    |> conn("foo", "bar=10")
    |> BarPlug.call([])

    assert conn.assigns.bar == "10"
  end

This fails, and Inspecting the conn, before or after the fetch_query_params calls, the Conn is the same:

%Plug.Conn{
  adapter: {Plug.Adapters.Test.Conn, :...},
  assigns: %{},
  before_send: [],
  body_params: %Plug.Conn.Unfetched{aspect: :body_params},
  cookies: %Plug.Conn.Unfetched{aspect: :cookies},
  halted: false,
  host: "www.example.com",
  method: "GET",
  owner: #PID<0.1089.0>,
  params: %{},
  path_info: ["foo"],
  path_params: %{},
  peer: {{127, 0, 0, 1}, 111317},
  port: 80,
  private: %{},
  query_params: %{},
  query_string: "",
  remote_ip: {127, 0, 0, 1},
  req_cookies: %Plug.Conn.Unfetched{aspect: :cookies},
  req_headers: [],
  request_path: "foo",
  resp_body: nil,
  resp_cookies: %{},
  resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}],
  scheme: :http,
  script_name: [],
  secret_key_base: nil,
  state: :unset,
  status: nil
}

Now, using a full URL works, but it contradicts the doc:

 test "Reads query params" do
    conn = :get
    |> conn("/foo?bar=10")
    |> Locale.Plug.call([])

    assert conn.assigns.bar == "10"
  end

Before assuming that the doc is wrong somehow, am I missing something obvious here ?

From the docs:

The params_or_body field must be one of:
a binary - containing a request body. For such cases, :headers must be given as option with a content-type;

Maybe try setting the :headers? Or conn |> Conn.put_req_headers("content-type", "...").

Or maybe it’s just ignored for the :get requests, since why would they provide a content type …

Would using a map instead work?

conn(:get, "foo", %{"bar" => 10})

Again from the docs

a map or list - containing the parameters which will automatically set the content-type to multipart. The map or list may contain other lists or maps and all entries will be normalized to string keys;

Looking at the implementation the query params must be passed in the URI.

That make sense. I opened a JIRA ticket to see if it’s only a documentation issue :confused:

https://github.com/elixir-plug/plug/issues/711

Thanks !