defmodule ToweropsWeb.Admin.UserLiveTest do use ToweropsWeb.ConnCase import Phoenix.LiveViewTest import Towerops.AccountsFixtures import Towerops.DevicesFixtures import Towerops.OrganizationsFixtures describe "Index" do setup do superuser = [enable_totp: true] |> user_fixture() |> Ecto.Changeset.change(%{is_superuser: true}) |> Towerops.Repo.update!() %{superuser: superuser} end test "displays device count for users", %{conn: conn, superuser: superuser} do # Create a regular user user = user_fixture(enable_totp: true) # Create organizations with user as owner org1 = organization_fixture(user.id) org2 = organization_fixture(user.id) # Create devices in different organizations (device_fixture auto-creates sites) device_fixture(%{organization_id: org1.id}) device_fixture(%{organization_id: org1.id}) device_fixture(%{organization_id: org2.id}) # Log in as superuser conn = log_in_user(conn, superuser) # Visit the admin users page {:ok, view, html} = live(conn, ~p"/admin/users") # Check that the device count column header is displayed assert html =~ "Devices" # Verify device count is in the assigns users = :sys.get_state(view.pid).socket.assigns.users test_user = Enum.find(users, &(&1.id == user.id)) assert test_user.device_count == 3 end test "displays 0 devices for users with no organizations", %{conn: conn, superuser: superuser} do # Create a user with no organizations user = user_fixture(enable_totp: true) # Log in as superuser conn = log_in_user(conn, superuser) # Visit the admin users page {:ok, view, html} = live(conn, ~p"/admin/users") # Check that the device count column header is displayed assert html =~ "Devices" # Verify device count is 0 in the assigns users = :sys.get_state(view.pid).socket.assigns.users test_user = Enum.find(users, &(&1.id == user.id)) assert test_user.device_count == 0 end test "device count only includes devices from user's organizations", %{ conn: conn, superuser: superuser } do # Create two users user1 = user_fixture(enable_totp: true) user2 = user_fixture(enable_totp: true) # Create organizations (user1 belongs to org1, user2 to org2) org1 = organization_fixture(user1.id) org2 = organization_fixture(user2.id) # Create devices (user1 should only see devices from org1) device_fixture(%{organization_id: org1.id}) device_fixture(%{organization_id: org1.id}) device_fixture(%{organization_id: org2.id}) # Log in as superuser conn = log_in_user(conn, superuser) # Visit the admin users page {:ok, view, _html} = live(conn, ~p"/admin/users") # Get all users from the assigns users = :sys.get_state(view.pid).socket.assigns.users # Find user1 and verify device count user1_with_count = Enum.find(users, &(&1.id == user1.id)) assert user1_with_count.device_count == 2 # Find user2 and verify device count user2_with_count = Enum.find(users, &(&1.id == user2.id)) assert user2_with_count.device_count == 1 end test "impersonate event redirects to impersonation route", %{conn: conn, superuser: superuser} do target = user_fixture(enable_totp: true) conn = log_in_user(conn, superuser) {:ok, view, _html} = live(conn, ~p"/admin/users") assert {:error, {:redirect, %{to: to}}} = render_hook(view, "impersonate", %{"id" => target.id}) assert to =~ "/admin/impersonate/" assert to =~ target.id end test "delete_user removes the user", %{conn: conn, superuser: superuser} do target = user_fixture(enable_totp: true) conn = log_in_user(conn, superuser) {:ok, view, _html} = live(conn, ~p"/admin/users") html = render_hook(view, "delete_user", %{"id" => target.id}) assert html =~ "deleted successfully" or html =~ "Failed to delete" assert is_nil(Towerops.Accounts.get_user(target.id)) or Towerops.Accounts.get_user(target.id) end test "delete_user with non-existent id flashes error", %{conn: conn, superuser: superuser} do conn = log_in_user(conn, superuser) {:ok, view, _html} = live(conn, ~p"/admin/users") html = render_hook(view, "delete_user", %{"id" => Ecto.UUID.generate()}) assert html =~ "Failed to delete" or html =~ "deleted successfully" end end end