Closed sevenseacat closed 9 years ago
Hi! Thanks for trying ESpec!
The initial purpose of controller specs action
helper is just to call the controller function.
in version 0.1.3
defmodule ESpec.Phoenix.Controllers.Helpers do
...
def action(action, params \\ %{}) do
conn = conn()
|> put_private(:phoenix_controller, @controller)
|> Phoenix.Controller.put_view(Phoenix.Controller.__view__(@controller))
|> with_session
|> Phoenix.ConnTest.fetch_flash()
apply(@controller, action, [conn, params])
end
...
end
So action
helper just set view, fetch session and flash, and then apply the function.
If you want use all your controller stack it is preferable to use requests spec.
I agree with you that there will be a good option to have possibility to test controller actions with plugs.
I've added a third argument to action
helper in '0.1.4'. Now you are able to send a custom connection to action/3
helper. The function now looks:
def action(action, params \\ %{}, connection \\ conn()) do
conn = connection
|> put_private(:phoenix_controller, @controller)
...
apply(@controller, action, [conn, params])
end
So, the third argument is a custom conn struct. There is an example in app/spec/controllers/user_controller_spec.exs:
context "set custom conn to test with plugs" do
let :custom_conn, do: App.UserController.custom_plug(conn())
subject do: action(:index, %{}, custom_conn)
it "check custom_plug assigns" do
subject |> should have_in_assigns(hello: "world")
end
end
Thanks!
FWIW, I came across this issue and just extended action
as authentication_action
in ESpec.Phoenix.Extend
.
spec/espec_phoenix_extend.exs:
Code.require_file(“spec/helpers/authentication_action.exs”)
defmodule ESpec.Phoenix.Extend do
# …
def controller do
quote do
# …
use Espec.Helpers.AuthenticationAction
end
end
# …
end
spec/helpers/authentication_action.exs:
defmodule Espec.Helpers.AuthenticationAction do
defmacro __using__(_args) do
quote do
use Plug.Test
def authentication_action(action, params \\ %{}, connection \\ conn()) do
conn = connection
|> put_private(:phoenix_controller, @controller)
|> Phoenix.Controller.put_view(Phoenix.Controller.__view__(@controller))
|> with_session
|> with_auth
|> Phoenix.ConnTest.fetch_flash()
apply(@controller, action, [conn, params])
end
@authenticate MyApp.Plug.Authenticate.init(
repo: MyApp.Repo
)
defp with_auth(conn) do
conn
|> MyApp.Plug.Authenticate.call(@authenticate)
end
end
end
end
Basically a lot of copy/paste from controller helpers.
I think this should be classified as a bug. If you have plugs that are responsible for doing authentication, authorization, and loading data, then the controller action can't possibly run without them.
edit: The auth is less of a problem than the loading of data. In plugs we can assign data to
conn
and that gets passed to the controller action - is there a way we can do that before running tests, because the actions rely on the data being present?