test/openagents_web/live/member_index_live_test.exs

main at 58e6347eeb72 · 5 KB

defmodule OpenAgentsWeb.MemberIndexLiveTest do
  use OpenAgentsWeb.ConnCase, async: false

  import Phoenix.LiveViewTest
  import OpenAgents.AccountsFixtures

  alias OpenAgents.Repositories

  defp plain_user(login) do
    github_id = System.unique_integer([:positive, :monotonic])

    {:ok, user} =
      OpenAgents.Accounts.upsert_github_user(%{
        github_id: github_id,
        github_login: login,
        github_avatar_url: "https://avatars.githubusercontent.com/u/#{github_id}?v=4"
      })

    user
  end

  defp sign_in_owner(conn, key) do
    user = repository_user_fixture(key)

    {:ok, _} =
      Repositories.add_member(
        Repositories.get_by_path!("OpenAgentsInc", "openagents.com"),
        user,
        "owner"
      )

    {Plug.Test.init_test_session(conn, %{"user_id" => user.id}), user}
  end

  test "an owner sees the members and their roles", %{conn: conn} do
    {conn, _owner} = sign_in_owner(conn, "members-view-owner")
    member = repository_user_fixture("members-view-member")

    {:ok, _membership} =
      Repositories.add_member(
        Repositories.get_by_path!("OpenAgentsInc", "openagents.com"),
        member,
        "contributor"
      )

    {:ok, _view, html} = live(conn, ~p"/OpenAgentsInc/openagents.com/members")

    assert html =~ "members-view-owner"
    assert html =~ "members-view-member"
    assert html =~ String.capitalize("contributor")
  end

  test "an owner adds a member by GitHub login", %{conn: conn} do
    {conn, _owner} = sign_in_owner(conn, "members-add-owner")
    recruit = plain_user("recruit")

    {:ok, view, _html} = live(conn, ~p"/OpenAgentsInc/openagents.com/members")

    view
    |> form("#add-member-form", member: %{login: "recruit", role: "maintainer"})
    |> render_submit()

    html = render(view)
    assert has_element?(view, "#members")
    assert html =~ "recruit"

    assert Repositories.membership_role(
             Repositories.get_by_path!("OpenAgentsInc", "openagents.com"),
             recruit
           ) ==
             "maintainer"
  end

  test "adding an unknown login explains what to do", %{conn: conn} do
    {conn, _owner} = sign_in_owner(conn, "members-unknown-owner")

    {:ok, view, _html} = live(conn, ~p"/OpenAgentsInc/openagents.com/members")

    html =
      view
      |> form("#add-member-form", member: %{login: "never-signed-in", role: "viewer"})
      |> render_submit()

    assert html =~ "need to sign in once"
  end

  test "an owner changes a member's role", %{conn: conn} do
    {conn, _owner} = sign_in_owner(conn, "members-role-owner")
    member = repository_user_fixture("role-target")
    repository = Repositories.get_by_path!("OpenAgentsInc", "openagents.com")
    {:ok, _membership} = Repositories.add_member(repository, member, "contributor")

    {:ok, view, _html} = live(conn, ~p"/OpenAgentsInc/openagents.com/members")

    view
    |> form("#member-role-form-member-#{member.id}", %{
      "user_id" => member.id,
      "role" => "maintainer"
    })
    |> render_change()

    assert Repositories.membership_role(
             Repositories.get_by_path!("OpenAgentsInc", "openagents.com"),
             member
           ) ==
             "maintainer"
  end

  test "an owner removes a member", %{conn: conn} do
    {conn, _owner} = sign_in_owner(conn, "members-remove-owner")
    member = repository_user_fixture("remove-target")
    repository = Repositories.get_by_path!("OpenAgentsInc", "openagents.com")
    {:ok, _membership} = Repositories.add_member(repository, member, "contributor")

    {:ok, view, _html} = live(conn, ~p"/OpenAgentsInc/openagents.com/members")

    view
    |> element(~s{button[phx-click="remove_member"][phx-value-user-id="#{member.id}"]})
    |> render_click()

    refute Repositories.member?(repository, member)
  end

  test "a demoted owner cannot keep administering through an open page", %{conn: conn} do
    {conn, owner} = sign_in_owner(conn, "members-stale-owner")
    recruit = plain_user("members-stale-recruit")
    repository = Repositories.get_by_path!("OpenAgentsInc", "openagents.com")

    {:ok, view, _html} = live(conn, ~p"/OpenAgentsInc/openagents.com/members")
    {:ok, _} = Repositories.add_member(repository, owner, "contributor")

    html =
      view
      |> form("#add-member-form", member: %{login: recruit.github_login, role: "viewer"})
      |> render_submit()

    assert html =~ "Only repository owners can manage members"
    refute Repositories.member?(repository, recruit)
  end

  test "the last owner cannot be removed through the page", %{conn: conn} do
    {conn, owner} = sign_in_owner(conn, "members-last-owner")

    {:ok, view, _html} = live(conn, ~p"/OpenAgentsInc/openagents.com/members")

    html =
      view
      |> element(~s{button[phx-click="remove_member"][phx-value-user-id="#{owner.id}"]})
      |> render_click()

    assert html =~ "at least one owner"

    assert Repositories.member?(
             Repositories.get_by_path!("OpenAgentsInc", "openagents.com"),
             owner
           )
  end

  test "a non-owner is sent away", %{conn: conn} do
    user = repository_user_fixture("plain-contributor")
    repository = Repositories.get_by_path!("OpenAgentsInc", "openagents.com")
    {:ok, _membership} = Repositories.add_member(repository, user, "contributor")
    conn = Plug.Test.init_test_session(conn, %{"user_id" => user.id})

    {:error, {:redirect, %{to: to}}} = live(conn, ~p"/OpenAgentsInc/openagents.com/members")

    assert to == "/OpenAgentsInc/openagents.com/issues"
  end
end