207 lines
5.8 KiB
Elixir
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
|