jeudi 12 novembre 2020

Conn being redirect only on test with status 307

I'm writing some controllers tests, however, every controller test, even without authentication, fails because the conn is redirect to somewhere else. The strange is that in my code I never redirect or return such status (307), only CRUD: 200,201, 400 and 500, without redirecting.

Here is one of my controller test:

defmodule SysbovApiWeb.Animals.AnimalsControllerTest do
  use SysbovApiWeb.ConnCase, async: true

  import SysbovApi.Factory

  setup_all :login_and_farm_id

  defp login_and_farm_id(_context) do
    conn = build_conn()

    user = insert(:user)
    %{id: farm_id} = insert(:farm, user_id: user.id)

    session =
      post(conn, "/api/v1/users/sessions", %{
        "email" => user.email,
        "password" => "123456"
      })

    assert %{"token" => token, "user" => _} = json_response(session, 201)

    conn_with_token = conn |> put_req_header("Authorization", "Bearer #{token}")

    %{conn: conn_with_token, farm_id: farm_id}
  end

  describe "create/2" do
    test "returns 201 when all params are correct", %{conn: conn, farm_id: farm_id} do
      conn =
        post(conn, "/api/v1/farms/animals", %{
          "name" => "Macabeuzinho",
          "father" => "Macabeus",
          "mother" => "Macabeia",
          "breed" => "raro",
          "color" => "brown",
          "weight" => Decimal.new("10.10"),
          "farm_id" => farm_id
        })

      assert %{
               "animal" => %{
                 "breed" => _,
                 "color" => _,
                 "farm_id" => _,
                 "father" => _,
                 "id" => _,
                 "mother" => _,
                 "name" => _,
                 "weight" => _
               }
             } = json_response(conn, 201)
    end
  end

  describe "index/2" do
    test "returns all animals given a farm", %{conn: conn, farm_id: farm_id} do
      insert_list(2, :animal, farm_id: farm_id)
      conn = get(conn, "/api/v1/farms/#{farm_id}/animals")

      %{animals: animals} = json_response(conn, 200)

      assert is_list(animals)
      assert length(animals) == 2
    end
  end

  describe "show/2" do
    test "returns a specific animal given a farm", %{conn: conn, farm_id: farm_id} do
      animal = insert(:animal, farm_id: farm_id)
      conn = get(conn, "/api/v1/farms/#{farm_id}/animals/#{animal.id}")

      assert %{
               "animal" => %{
                 "breed" => _,
                 "color" => _,
                 "farm_id" => _,
                 "father" => _,
                 "id" => _,
                 "mother" => _,
                 "name" => _,
                 "weight" => _
               }
             } = json_response(conn, 200)
    end
  end

  describe "delete/2" do
    test "correctly deletes an animal given a id", %{conn: conn, farm_id: farm_id} do
      animal = insert(:animal, farm_id: farm_id)
      conn = delete(conn, "/api/v1/farms/animals/#{animal.id}")

      assert %{deleted: true} = json_response(conn, 200)
    end
  end
end

My controller:

defmodule SysbovApiWeb.Animals.AnimalsController do
  use SysbovApiWeb, :controller

  alias SysbovApi.CreateAnimals
  alias SysbovApi.Farm.AnimalsRepo
  alias SysbovApi.Animals.AnimalsRepo

  def create(conn, params) do
    case CreateAnimals.run(params) do
      {:ok, animal} ->
        conn
        |> put_status(201)
        |> render("create.json", %{animal: animal})

      {:error, changeset} ->
        conn
        |> put_status(400)
        |> render(SysbovApiWeb.ErrorView, "400.json", %{changeset: changeset})
    end
  end

  def index(conn, %{"farm_id" => farm_id}) do
    case AnimalsRepo.get_animals(farm_id) do
      {:ok, animals} ->
        render(conn, "index.json", %{animals: animals})

      _ ->
        conn
        |> put_status(400)
        |> render(SysbovApiWeb.ErrorView, "400.json")
    end
  end

  def show(conn, %{"animal_id" => animal_id}) do
    case AnimalsRepo.get_animal(animal_id) do
      {:ok, animal} ->
        render(conn, "show.json", %{animal: animal})

      {:error, error} ->
        conn
        |> put_status(500)
        |> render("500.json", %{error: error})
    end
  end

  def delete(conn, %{"animal_id" => animal_id}) do
    case AnimalsRepo.delete_animal(animal_id) do
      {:ok, _deleted} ->
        render(conn, "delete.json", %{deleted: true})

      {:error, error} ->
        conn
        |> put_status(500)
        |> render(SysbovApiWeb.ErrorView, "500.json", %{error: error})
    end
  end
end

and my conn case:

defmodule SysbovApiWeb.ConnCase do
  @moduledoc """
  This module defines the test case to be used by
  tests that require setting up a connection.

  Such tests rely on `Phoenix.ConnTest` and also
  import other functionality to make it easier
  to build common data structures and query the data layer.

  Finally, if the test case interacts with the database,
  we enable the SQL sandbox, so changes done to the database
  are reverted at the end of every test. If you are using
  PostgreSQL, you can even run database tests asynchronously
  by setting `use SysbovApiWeb.ConnCase, async: true`, although
  this option is not recommended for other databases.
  """

  alias Ecto.Adapters.SQL.Sandbox

  use ExUnit.CaseTemplate

  using do
    quote do
      # Import conveniences for testing with connections
      import Plug.Conn
      import Phoenix.ConnTest
      import SysbovApiWeb.ConnCase

      alias SysbovApiWeb.Router.Helpers, as: Routes

      # The default endpoint for testing
      @endpoint SysbovApiWeb.Endpoint
    end
  end

  setup tags do
    :ok = Sandbox.checkout(SysbovApi.Repo)

    unless tags[:async] do
      Sandbox.mode(SysbovApi.Repo, {:shared, self()})
    end

    {:ok, conn: Phoenix.ConnTest.build_conn()}
  end
end

the really strange part is that the conn is only redirected when running all tests, if I test each route, manually, all works fine.

What I'm doing wrong?

Aucun commentaire:

Enregistrer un commentaire