Having a problem with code in Programming Phoenix book >= 1.4

defmodule RumblWeb.VideoControllerTest do
  use RumblWeb.ConnCase, async: true

  test "requires user athentication on all actions", %{conn: conn} do
    Enum.each([
      get(conn, Routes.video_path(conn, :new)),
      get(conn, Routes.video_path(conn, :index)),
      get(conn, Routes.video_path(conn, :show, "123")),
      get(conn, Routes.video_path(conn, :edit, "123")),
      put(conn, Routes.video_path(conn, :update, "123", %{})),
      post(conn, Routes.video_path(conn, :create, %{})),
      delete(conn, Routes.video_path(conn, :delete, "123")),
    ], fn conn ->
      assert html_response(conn, 302)
      assert conn.halted
    end)
  end

  setup %{conn: conn, login_as: username} do
    user = user_fixture(username: username)
    conn = assign(conn, :current_user, user) 
    IO.puts("THIS CODE IS EXECUTING")
    {:ok, conn: conn, user: user}
  end

  test "lists all user's videos on index", %{conn: conn, user: user} do
    user_video = video_fixture(user, title: "funny cats")
    other_video = video_fixture(user_fixture(username: "other"), title: "another video")

    conn = get conn, Routes.video_path(conn, :index)
    assert html_response(conn, 200) =~ ~r/Listing Videos/
    assert String.contains?(conn.resp_body, user_video.title)
    refute String.contains?(conn.resp_body, other_video.title)
  end

  describe "with a logged-in user" do
    setup %{conn: conn, login_as: username} do
      IO.puts("THIS CODE IS ALSO EXECUTING")
      user = user_fixture(username: username)
      conn = assign(conn, :current_user, user)
      
      {:ok, conn: conn, user: user}
    end

    @tag login_as: "max"
    test "lists all user's videos on index", %{conn: conn, user: user} do
      user_video = video_fixture(user, title: "funny cats")
      other_video = video_fixture(user_fixture(username: "other"),
        title: "another video")
      conn = get conn, Routes.video_path(conn, :index)
      response = html_response(conn, 200)
      assert response =~ ~r/Listing Videos/
      assert response =~ user_video.title
      refute response =~ other_video.title
      
      
    end
  end
end
defmodule Rumbl.TestHelpers do
   alias Rumbl.{
      Accounts,
      Multimedia
   }

   def user_fixture(attrs \\ %{}) do
      {:ok, user} =
         attrs
         |> Enum.into(%{
            name: "Some User",
            username: "user#{System.unique_integer([:positive])}",
            password: attrs[:password] || "supersecret"
         })
         |> IO.inspect(label: "WHAT IS BEING PASSED TO REGISTER_USER()")
         |> Accounts.register_user()

      # IO.inspect(user, label: "THIS IS USER FROM user_fixture/2")     
      user 
   end

   def video_fixture(%Accounts.User{} = user, attrs \\ %{}) do
      attrs =
         Enum.into(attrs, %{
            title: "A Title",
            url: "http://example.com",
            description: "a description"
         })

      {:ok, video} = Multimedia.create_video(user, attrs)

      video
   end
   
end

In the above code from the book, the tests calls user_fixture twice. There is a unique_index for the username in the migration for the user.

defmodule Rumbl.Repo.Migrations.CreateUsers do
  use Ecto.Migration

  def change do
      create table(:users) do
        add :name, :string
        add :username, :string, null: false
        add :password_hash, :string

        timestamps()
      end

      create unique_index(:users, [:username])
  end
end

so when a username: “max” is attempted to be created for the second time an error is returned. The book says all the tests pass with the command mix test test/rumbl_web --only login_as so I’m wondering if I’m missing something, especially in the @tag implementation.

mbp:rumbl pyop$ mix test test/rumbl_web --only login_as
Compiling 6 files (.ex)
Excluding tags: [:test]
Including tags: [:login_as]

WHAT IS BEING PASSED TO REGISTER_USER(): %{name: "Some User", password: "supersecret", username: "max"}
THIS CODE IS EXECUTING
THIS CODE IS ALSO EXECUTING
WHAT IS BEING PASSED TO REGISTER_USER(): %{name: "Some User", password: "supersecret", username: "max"}


  1) test with a logged-in user lists all user's videos on index (RumblWeb.VideoControllerTest)
     test/rumbl_web/controllers/video_controller_test.exs:46
     ** (Ecto.ConstraintError) constraint error when attempting to insert struct:

         * users_username_index (unique_constraint)

     If you would like to stop this constraint violation from raising an
     exception and instead add it as an error to your changeset, please
     call `unique_constraint/3` on your changeset with the constraint
     `:name` as an option.

     The changeset defined the following constraints:

         * users_name_index (unique_constraint)

     stacktrace:
       (ecto) lib/ecto/repo/schema.ex:689: anonymous fn/4 in Ecto.Repo.Schema.constraints_to_errors/3
       (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2
       (ecto) lib/ecto/repo/schema.ex:674: Ecto.Repo.Schema.constraints_to_errors/3
       (ecto) lib/ecto/repo/schema.ex:274: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
       (rumbl) test/support/test_helpers.ex:16: Rumbl.TestHelpers.user_fixture/1
       test/rumbl_web/controllers/video_controller_test.exs:39: RumblWeb.VideoControllerTest.__ex_unit_setup_2/1
       test/rumbl_web/controllers/video_controller_test.exs:1: RumblWeb.VideoControllerTest.__ex_unit__/2



Finished in 2.0 seconds
4 tests, 1 failure, 3 excluded

Disclaimer: I have lost an unacceptable degree of sanity while attempting to debug this and could have missed something basic and obvious.

The repo is here: https://github.com/somersbmatthews/rumbl2

Any help is appreciated, thanks.

The top-level setup %{conn: conn, login_as: username} do function is also going to run for each case inside the describe - you don’t need a second copy there.

thanks @al2o3cr, I’m missing a test now, but the tests do what they’re supposed to do now without error. The second user name is now “other”. I should let it go and move on, lol.

mbp:rumbl pyop$ mix test test/rumbl_web --only login_as
Excluding tags: [:test]
Including tags: [:login_as]

WHAT IS BEING PASSED TO REGISTER_USER(): %{name: "Some User", password: "supersecret", username: "max"}
THIS CODE IS EXECUTING
THIS IS SECOND USER TEST CODE
WHAT IS BEING PASSED TO REGISTER_USER(): %{name: "Some User", password: "supersecret", username: "other"}
.

Finished in 2.1 seconds
4 tests, 0 failures, 3 excluded