towerops/test/towerops_web/controllers/api/v1/invitations_controller_test.exs
Graham McIntire 7613a4dde5
add missing REST API controller tests
Tests for agents, alerts, integrations, organization, members, and
invitations controllers. Refactor alert filters to reduce complexity.
75 new tests, all passing.
2026-03-11 14:43:17 -05:00

144 lines
4.3 KiB
Elixir

defmodule ToweropsWeb.Api.V1.InvitationsControllerTest do
use ToweropsWeb.ConnCase, async: true
import Towerops.AccountsFixtures
import Towerops.OrganizationsFixtures
alias Towerops.ApiTokens
alias Towerops.Organizations
setup do
user = user_fixture()
organization = organization_fixture(user.id)
{:ok, {_token, raw_token}} =
ApiTokens.create_api_token(%{
organization_id: organization.id,
user_id: user.id,
name: "Test Token"
})
conn =
build_conn()
|> put_req_header("authorization", "Bearer #{raw_token}")
|> put_req_header("accept", "application/json")
%{conn: conn, user: user, organization: organization}
end
defp create_test_invitation(organization, user, email \\ "invited@example.com") do
{:ok, invitation} =
Organizations.create_invitation(%{
organization_id: organization.id,
email: email,
role: :technician,
invited_by_id: user.id,
token: Ecto.UUID.generate(),
expires_at: DateTime.utc_now() |> DateTime.add(7 * 86_400, :second) |> DateTime.truncate(:second)
})
invitation
end
describe "index/2" do
test "lists pending invitations", %{
conn: conn,
organization: organization,
user: user
} do
invitation = create_test_invitation(organization, user)
conn = get(conn, ~p"/api/v1/invitations")
assert %{"data" => invitations} = json_response(conn, 200)
assert length(invitations) == 1
inv = List.first(invitations)
assert inv["id"] == invitation.id
assert inv["email"] == "invited@example.com"
assert inv["role"] == "technician"
assert Map.has_key?(inv, "expires_at")
assert Map.has_key?(inv, "invited_by_email")
assert Map.has_key?(inv, "inserted_at")
end
test "returns empty list when no invitations exist", %{conn: conn} do
conn = get(conn, ~p"/api/v1/invitations")
assert %{"data" => []} = json_response(conn, 200)
end
end
describe "create/2" do
test "creates invitation", %{conn: conn} do
params = %{
"email" => "newuser@example.com",
"role" => "technician"
}
conn = post(conn, ~p"/api/v1/invitations", params)
assert %{"data" => data} = json_response(conn, 201)
assert data["email"] == "newuser@example.com"
assert data["role"] == "technician"
assert Map.has_key?(data, "id")
assert Map.has_key?(data, "expires_at")
assert Map.has_key?(data, "inserted_at")
end
test "returns 400 without required params", %{conn: conn} do
conn = post(conn, ~p"/api/v1/invitations", %{})
assert %{"error" => "Missing 'email' and 'role' parameters"} = json_response(conn, 400)
end
end
describe "delete/2" do
test "removes invitation", %{conn: conn, organization: organization, user: user} do
invitation = create_test_invitation(organization, user)
conn = delete(conn, ~p"/api/v1/invitations/#{invitation.id}")
assert response(conn, 204)
end
test "returns 404 for invitation in different organization", %{conn: conn} do
other_user = user_fixture()
other_org = organization_fixture(other_user.id)
invitation = create_test_invitation(other_org, other_user, "other@example.com")
conn = delete(conn, ~p"/api/v1/invitations/#{invitation.id}")
assert %{"error" => "Invitation not found"} = json_response(conn, 404)
end
test "returns 404 for non-existent invitation", %{conn: conn} do
fake_id = Ecto.UUID.generate()
conn = delete(conn, ~p"/api/v1/invitations/#{fake_id}")
assert %{"error" => "Invitation not found"} = json_response(conn, 404)
end
end
describe "authentication" do
test "returns 401 without authorization header" do
conn =
build_conn()
|> put_req_header("accept", "application/json")
|> get(~p"/api/v1/invitations")
assert %{"error" => _message} = json_response(conn, 401)
end
test "returns 401 with invalid token" do
conn =
build_conn()
|> put_req_header("authorization", "Bearer towerops_invalid_token")
|> put_req_header("accept", "application/json")
|> get(~p"/api/v1/invitations")
assert %{"error" => _message} = json_response(conn, 401)
end
end
end