112 lines
3.5 KiB
Elixir
112 lines
3.5 KiB
Elixir
defmodule ToweropsWeb.InvitationControllerTest do
|
|
use ToweropsWeb.ConnCase, async: true
|
|
|
|
import Towerops.AccountsFixtures
|
|
import Towerops.OrganizationsFixtures
|
|
|
|
alias Towerops.Organizations
|
|
|
|
setup do
|
|
user = user_fixture()
|
|
organization = organization_fixture(user.id)
|
|
|
|
%{user: user, organization: organization}
|
|
end
|
|
|
|
defp create_invitation(org, user, attrs \\ %{}) do
|
|
defaults = %{
|
|
organization_id: org.id,
|
|
invited_by_id: user.id,
|
|
email: "invited-#{System.unique_integer()}@example.com",
|
|
role: "member"
|
|
}
|
|
|
|
{:ok, invitation} = Organizations.create_invitation(Map.merge(defaults, attrs))
|
|
invitation
|
|
end
|
|
|
|
describe "GET /invitations/:token" do
|
|
test "redirects to registration with token when not logged in", %{
|
|
conn: conn,
|
|
organization: organization,
|
|
user: user
|
|
} do
|
|
invitation = create_invitation(organization, user)
|
|
|
|
conn = get(conn, ~p"/invitations/#{invitation.token}")
|
|
|
|
assert redirected_to(conn) =~ ~p"/users/register"
|
|
assert redirected_to(conn) =~ "invitation_token=#{invitation.token}"
|
|
end
|
|
|
|
test "accepts invitation and redirects when logged in", %{
|
|
conn: conn,
|
|
organization: organization,
|
|
user: inviter
|
|
} do
|
|
invitation = create_invitation(organization, inviter)
|
|
|
|
# Log in as a different user who will accept the invitation
|
|
accepting_user = user_fixture()
|
|
conn = log_in_user(conn, accepting_user)
|
|
|
|
conn = get(conn, ~p"/invitations/#{invitation.token}")
|
|
|
|
assert redirected_to(conn) =~ "/settings"
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "joined"
|
|
end
|
|
|
|
test "handles invalid/non-existent token", %{conn: conn} do
|
|
conn = get(conn, ~p"/invitations/invalid-token-abc123")
|
|
|
|
assert redirected_to(conn) == ~p"/"
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "invalid"
|
|
end
|
|
|
|
test "handles expired invitation", %{conn: conn, organization: organization, user: user} do
|
|
# Create an invitation with an already-passed expiration
|
|
invitation = create_invitation(organization, user)
|
|
|
|
# Manually expire it
|
|
invitation
|
|
|> Ecto.Changeset.change(%{expires_at: DateTime.add(DateTime.utc_now(), -1, :day)})
|
|
|> Towerops.Repo.update!()
|
|
|
|
conn = get(conn, ~p"/invitations/#{invitation.token}")
|
|
|
|
assert redirected_to(conn) == ~p"/"
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "invalid"
|
|
end
|
|
|
|
test "handles already-accepted invitation", %{conn: conn, organization: organization, user: user} do
|
|
invitation = create_invitation(organization, user)
|
|
|
|
# Mark as accepted
|
|
invitation
|
|
|> Ecto.Changeset.change(%{accepted_at: DateTime.utc_now()})
|
|
|> Towerops.Repo.update!()
|
|
|
|
conn = get(conn, ~p"/invitations/#{invitation.token}")
|
|
|
|
assert redirected_to(conn) == ~p"/"
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "invalid"
|
|
end
|
|
|
|
test "shows error when user is already a member", %{
|
|
conn: conn,
|
|
organization: organization,
|
|
user: inviter
|
|
} do
|
|
invitation = create_invitation(organization, inviter)
|
|
|
|
# The inviter is already a member, so accepting should fail
|
|
conn = log_in_user(conn, inviter)
|
|
|
|
conn = get(conn, ~p"/invitations/#{invitation.token}")
|
|
|
|
# Should redirect with an error about already being a member
|
|
assert redirected_to(conn) =~ "/dashboard"
|
|
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "already"
|
|
end
|
|
end
|
|
end
|