towerops/test/towerops/organizations/invitation_test.exs
2026-06-16 09:56:51 -05:00

207 lines
5.8 KiB
Elixir

defmodule Towerops.Organizations.InvitationTest do
use Towerops.DataCase
alias Towerops.Organizations.Invitation
describe "changeset/2" do
test "valid changeset with required fields" do
attrs = %{
email: "test@example.com",
role: :member,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate()
}
changeset = Invitation.changeset(%Invitation{}, attrs)
assert changeset.valid?
assert get_field(changeset, :email) == "test@example.com"
assert get_field(changeset, :role) == :member
# Token and expires_at should be auto-generated
assert get_field(changeset, :token)
assert get_field(changeset, :expires_at)
end
test "requires email" do
attrs = %{
role: :member,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate()
}
changeset = Invitation.changeset(%Invitation{}, attrs)
refute changeset.valid?
assert %{email: ["can't be blank"]} = errors_on(changeset)
end
test "defaults role to :technician when not provided" do
attrs = %{
email: "test@example.com",
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate()
}
changeset = Invitation.changeset(%Invitation{}, attrs)
assert changeset.valid?
assert Ecto.Changeset.get_field(changeset, :role) == :technician
end
test "requires organization_id" do
attrs = %{
email: "test@example.com",
role: :member,
invited_by_id: Ecto.UUID.generate()
}
changeset = Invitation.changeset(%Invitation{}, attrs)
refute changeset.valid?
assert %{organization_id: ["can't be blank"]} = errors_on(changeset)
end
test "requires invited_by_id" do
attrs = %{
email: "test@example.com",
role: :member,
organization_id: Ecto.UUID.generate()
}
changeset = Invitation.changeset(%Invitation{}, attrs)
refute changeset.valid?
assert %{invited_by_id: ["can't be blank"]} = errors_on(changeset)
end
test "validates email format" do
attrs = %{
email: "invalid-email",
role: :member,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate()
}
changeset = Invitation.changeset(%Invitation{}, attrs)
refute changeset.valid?
assert %{email: ["has invalid format"]} = errors_on(changeset)
end
test "accepts valid email formats" do
valid_emails = [
"test@example.com",
"user.name@domain.co.uk",
"user+tag@example.org"
]
for email <- valid_emails do
attrs = %{
email: email,
role: :member,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate()
}
changeset = Invitation.changeset(%Invitation{}, attrs)
assert changeset.valid?, "Expected #{email} to be valid"
end
end
test "generates token automatically" do
attrs = %{
email: "test@example.com",
role: :member,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate()
}
changeset = Invitation.changeset(%Invitation{}, attrs)
token = get_field(changeset, :token)
assert is_binary(token) and byte_size(token) > 0
assert String.length(token) > 0
end
test "does not override provided token" do
attrs = %{
email: "test@example.com",
role: :member,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate(),
token: "custom-token"
}
changeset = Invitation.changeset(%Invitation{}, attrs)
assert get_field(changeset, :token) == "custom-token"
end
test "generates expires_at automatically (7 days from now)" do
attrs = %{
email: "test@example.com",
role: :member,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate()
}
now = DateTime.utc_now()
changeset = Invitation.changeset(%Invitation{}, attrs)
expires_at = get_field(changeset, :expires_at)
# Should be approximately 7 days from now (within 1 minute tolerance)
diff_seconds = DateTime.diff(expires_at, now, :second)
expected_seconds = 7 * 24 * 60 * 60
assert_in_delta diff_seconds, expected_seconds, 60
end
test "does not override provided expires_at" do
custom_expires_at = DateTime.utc_now() |> DateTime.add(1, :day) |> DateTime.truncate(:second)
attrs = %{
email: "test@example.com",
role: :member,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate(),
expires_at: custom_expires_at
}
changeset = Invitation.changeset(%Invitation{}, attrs)
assert DateTime.compare(get_field(changeset, :expires_at), custom_expires_at) == :eq
end
test "accepts all valid role values" do
roles = [:admin, :member, :viewer]
for role <- roles do
attrs = %{
email: "test@example.com",
role: role,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate()
}
changeset = Invitation.changeset(%Invitation{}, attrs)
assert changeset.valid?, "Expected role #{role} to be valid"
end
end
test "allows accepted_at to be set" do
accepted_at = Towerops.Time.now()
attrs = %{
email: "test@example.com",
role: :member,
organization_id: Ecto.UUID.generate(),
invited_by_id: Ecto.UUID.generate(),
accepted_at: accepted_at
}
changeset = Invitation.changeset(%Invitation{}, attrs)
assert changeset.valid?
assert DateTime.compare(get_field(changeset, :accepted_at), accepted_at) == :eq
end
end
end