93 lines
3.5 KiB
Elixir
93 lines
3.5 KiB
Elixir
defmodule Mv.Accounts.EmailSyncEdgeCasesTest do
|
|
@moduledoc """
|
|
Edge case tests for email synchronization between User and Member.
|
|
Tests various boundary conditions and validation scenarios.
|
|
"""
|
|
use Mv.DataCase, async: false
|
|
alias Mv.Accounts
|
|
alias Mv.Membership
|
|
|
|
describe "Email sync edge cases" do
|
|
@valid_user_attrs %{
|
|
email: "user@example.com"
|
|
}
|
|
|
|
@valid_member_attrs %{
|
|
first_name: "John",
|
|
last_name: "Doe",
|
|
email: "member@example.com"
|
|
}
|
|
|
|
test "simultaneous email updates use user email as source of truth" do
|
|
# Create linked user and member
|
|
{:ok, member} = Membership.create_member(@valid_member_attrs)
|
|
|
|
{:ok, user} =
|
|
Accounts.create_user(Map.put(@valid_user_attrs, :member, %{id: member.id}))
|
|
|
|
# Verify link and initial sync
|
|
{:ok, synced_member} = Ash.get(Mv.Membership.Member, member.id)
|
|
assert synced_member.email == "user@example.com"
|
|
|
|
# Scenario: Both emails are updated "simultaneously"
|
|
# In practice, this tests that when a member email is updated,
|
|
# it syncs to user, and user remains the source of truth
|
|
|
|
# Update member email first
|
|
{:ok, _updated_member} =
|
|
Membership.update_member(member, %{email: "member-new@example.com"})
|
|
|
|
# Verify it synced to user
|
|
{:ok, user_after_member_update} = Ash.get(Mv.Accounts.User, user.id)
|
|
assert to_string(user_after_member_update.email) == "member-new@example.com"
|
|
|
|
# Now update user email - this should override
|
|
{:ok, _updated_user} =
|
|
Accounts.update_user(user_after_member_update, %{email: "user-final@example.com"})
|
|
|
|
# Reload both
|
|
{:ok, final_user} = Ash.get(Mv.Accounts.User, user.id)
|
|
{:ok, final_member} = Ash.get(Mv.Membership.Member, member.id)
|
|
|
|
# User email should be the final truth
|
|
assert to_string(final_user.email) == "user-final@example.com"
|
|
assert final_member.email == "user-final@example.com"
|
|
end
|
|
|
|
test "email validation works for both user and member" do
|
|
# Test that invalid emails are rejected for both resources
|
|
|
|
# Invalid email for user
|
|
invalid_user_result = Accounts.create_user(%{email: "not-an-email"})
|
|
assert {:error, %Ash.Error.Invalid{}} = invalid_user_result
|
|
|
|
# Invalid email for member
|
|
invalid_member_attrs = Map.put(@valid_member_attrs, :email, "also-not-an-email")
|
|
invalid_member_result = Membership.create_member(invalid_member_attrs)
|
|
assert {:error, %Ash.Error.Invalid{}} = invalid_member_result
|
|
|
|
# Valid emails should work
|
|
{:ok, _user} = Accounts.create_user(@valid_user_attrs)
|
|
{:ok, _member} = Membership.create_member(@valid_member_attrs)
|
|
end
|
|
|
|
test "identity constraints prevent duplicate emails" do
|
|
# Create first user with an email
|
|
{:ok, user1} = Accounts.create_user(%{email: "duplicate@example.com"})
|
|
assert to_string(user1.email) == "duplicate@example.com"
|
|
|
|
# Try to create second user with same email - should fail due to unique constraint
|
|
result = Accounts.create_user(%{email: "duplicate@example.com"})
|
|
assert {:error, %Ash.Error.Invalid{}} = result
|
|
|
|
# Same for members
|
|
member_attrs = Map.put(@valid_member_attrs, :email, "member-dup@example.com")
|
|
{:ok, member1} = Membership.create_member(member_attrs)
|
|
assert member1.email == "member-dup@example.com"
|
|
|
|
# Try to create second member with same email - should fail
|
|
result2 = Membership.create_member(member_attrs)
|
|
assert {:error, %Ash.Error.Invalid{}} = result2
|
|
end
|
|
end
|
|
end
|