4
votes

I'm new to Phoenix and I'm testing a custom Plug that should redirect to the /404.html page if a condition is not met. The code works correctly when I try the success/failure paths but I'm having a difficult time understanding why my testing approach is blowing up.

The test failure boils down to the following:

%Plug.Conn{} |> Phoenix.Controller.redirect(to: "/404.html")

My expectation is that this should return a conn object which I can then run assertions on. However, when I try to run the above code I get the following error:

** (UndefinedFunctionError) function Plug.Conn.send_resp/4 is undefined or private. Did you mean one of:

This is a bit weird since the Phoenix.Controller module implements a send_resp/4 function and it imports the Plug.Conn at the top of its definition.

Why is it ignoring that function and trying to hit Plug.Conn directly? I'm not calling that private function, a public function is delegating to it, which should be kosher unless I've missed something obvious. Is there an easy solution to this problem or should I take another approach?

EDIT

Here is the full stack trace from iex:

%Plug.Conn{} |> Phoenix.Controller.redirect(to: "/404.html")

** (UndefinedFunctionError) function Plug.Conn.send_resp/4 is undefined or private. Did you mean one of:

  * send_resp/1
  * send_resp/3

(plug) Plug.Conn.send_resp(nil, 302, [{"content-type", "text/html; charset=utf-8"}, {"cache-control", "max-age=0, private, must-revalidate"}, {"location", "/404.html"}], "<html><body>You are being <a href=\"/404.html\">redirected</a>.</body></html>")
(plug) lib/plug/conn.ex:393: Plug.Conn.send_resp/1

The redirect function's implementation can be found here: https://github.com/phoenixframework/phoenix/blob/v1.2.3/lib/phoenix/controller.ex#L297

The send_resp function I expect it to hit can be found here: https://github.com/phoenixframework/phoenix/blob/v1.2.3/lib/phoenix/controller.ex#L748

1
Can you post the stacktrace of that error and the code around the line it refers to?Dogbert
edited the post to include the stack tracetomciopp
I think you need to use Phoenix.ConnTest.build_conn() instead of %Plug.Conn{} for testing.Dogbert
This works, however I still quite don't understand why using Plug.Conn directly does not work. I will dig in deeper and see what is going on.tomciopp
Also, if it helps, you can use the redirected_to/2 helper.Daniel Zendejas

1 Answers

0
votes

As the first line of your Stacktrace indicates. nil is the first argument to the Plug.Conn.send_resp/4 function. The Plug.Conn.send_resp/4 function does not exist though. Only arity one and three as you can see in the docs of in the code.

What you probably mixed it up with is the Phoenix.Controller.send_resp/4 function as you linked it.

Nontheless the main issue is, that nil is passed to the send_resp function which would not work for either function. It seems the conn was lost somewhere.

Thus I suggest to go with @Dogbert's comment and use Phoenix.ConnTest.build_conn() to mock a conn instead of initializing an empty conn struct with %Plug.Conn{}.