Testing with Smokestack and AshAuthentication

I wanted to try and clear up two things that I run into with when testing with some of the Ash libraries.

  1. How can I properly authenticate a user for a test
  2. How to work with relationships and Smokestack

The first one is the one I am more stumped with. Essentially let’s say I want to have a test that the user goes to a route that is limited to logged in users and does some actions, what is the appropriate way to create the user?

Right now I am doing the following inside the conn_case.ex

  def log_in_user(conn, user) do
    subject = AshAuthentication.user_to_subject(user)

    conn
    |> Phoenix.ConnTest.init_test_session(%{})
    |> Plug.Conn.put_session("user", subject)
  end

The next one I want to just clarify or see if there are better ways. Is there a way I can create a factory that implicitly builds an association?

# post has_one author
author = insert!(Author)
post = insert!(Post, attrs: %{author_id: author.id})

# is there a way to do something like
# post = insert!(Post)
# and the author will be implicitly created

There is ash_authentication but also ash_authentication_phoenix.
Got me confused recently. :sweat_smile:
Anyway, definitely check the latter. In ash authentication phoenix there is a test:

  test "sign_in routes allow a user to sign in", %{conn: conn} do
    Example.Accounts.User
    |> Ash.Changeset.for_create(:register_with_password, %{
      email: "zach@example.com",
      password: "so-secure!",
      password_confirmation: "so-secure!"
    })
    |> Ash.create!()

    conn = get(conn, "/sign-in")
    assert {:ok, lv, _html} = live(conn)

    lv
    |> form("#user-password-sign-in-with-password", %{
      "user" => %{
        "email" => "zach@example.com",
        "password" => "so-secure!"
      }
    })
    |> render_submit()

    assert_received {_ref, {:redirect, _topic, %{to: new_to}}}
    assert %{path: "/auth/user/password/sign_in_with_token"} = URI.parse(new_to)
  end

As you can see in support there are Example modules which represent example for use.
Also create action register_with_password on changeset is called but you will not find that create action in User module. I think it’s because it’s implicit in password authentication i.e. it’s not necessary to explicitly define the create action for that strategy.

1 Like