antonmi / espec_phoenix

ESpec for Phoenix web framework.
MIT License
137 stars 33 forks source link

Controller tests do not run plugs #4

Closed sevenseacat closed 9 years ago

sevenseacat commented 9 years ago

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?

antonmi commented 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!

baoist commented 8 years ago

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.