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