defmodule Mv.Membership.MemberEmailSyncTest do @moduledoc """ Tests for email synchronization from Member to User. When a member and user are linked, email changes should sync bidirectionally. User.email is the source of truth when linking occurs. """ use Mv.DataCase, async: false alias Mv.Accounts alias Mv.Membership describe "Member email synchronization to linked User" do @valid_user_attrs %{ email: "user@example.com" } @valid_member_attrs %{ first_name: "John", last_name: "Doe", email: "member@example.com" } test "updating member email syncs to linked user" do # Create a user {:ok, user} = Accounts.create_user(@valid_user_attrs) assert to_string(user.email) == "user@example.com" # Create a member linked to the user {:ok, member} = Membership.create_member(Map.put(@valid_member_attrs, :user, %{id: user.id})) # Verify initial state - member email should be overridden by user email {:ok, member_after_create} = Ash.get(Mv.Membership.Member, member.id) assert member_after_create.email == "user@example.com" # Update member email {:ok, updated_member} = Membership.update_member(member, %{email: "newmember@example.com"}) assert updated_member.email == "newmember@example.com" # Verify user email was also updated {:ok, synced_user} = Ash.get(Mv.Accounts.User, user.id) assert to_string(synced_user.email) == "newmember@example.com" end test "creating member linked to user syncs user email to member" do # Create a user with their own email {:ok, user} = Accounts.create_user(@valid_user_attrs) assert to_string(user.email) == "user@example.com" # Create a member linked to this user {:ok, member} = Membership.create_member(Map.put(@valid_member_attrs, :user, %{id: user.id})) # Member should have been created with user's email (user is source of truth) assert member.email == "user@example.com" # Verify the link {:ok, loaded_member} = Ash.get(Mv.Membership.Member, member.id, load: [:user]) assert loaded_member.user.id == user.id end test "linking member to existing user syncs user email to member" do # Create a standalone user {:ok, user} = Accounts.create_user(@valid_user_attrs) assert to_string(user.email) == "user@example.com" # Create a standalone member {:ok, member} = Membership.create_member(@valid_member_attrs) assert member.email == "member@example.com" # Link the member to the user {:ok, linked_member} = Membership.update_member(member, %{user: %{id: user.id}}) # Verify the link {:ok, loaded_member} = Ash.get(Mv.Membership.Member, linked_member.id, load: [:user]) assert loaded_member.user.id == user.id # Verify member email was overridden with user email assert loaded_member.email == "user@example.com" end test "updating member email when no user linked does not error" do # Create a standalone member without user link {:ok, member} = Membership.create_member(@valid_member_attrs) assert member.email == "member@example.com" # Load to verify no user link {:ok, loaded_member} = Ash.get(Mv.Membership.Member, member.id, load: [:user]) assert loaded_member.user == nil # Update member email - should work fine without error {:ok, updated_member} = Membership.update_member(member, %{email: "newemail@example.com"}) assert updated_member.email == "newemail@example.com" end test "unlinking member from user does not sync email" do # Create user {:ok, user} = Accounts.create_user(@valid_user_attrs) # Create member linked to user {:ok, member} = Membership.create_member(Map.put(@valid_member_attrs, :user, %{id: user.id})) # Verify member email was synced to user email {:ok, synced_member} = Ash.get(Mv.Membership.Member, member.id) assert synced_member.email == "user@example.com" # Verify link exists {:ok, loaded_member} = Ash.get(Mv.Membership.Member, member.id, load: [:user]) assert loaded_member.user != nil # Unlink member from user {:ok, unlinked_member} = Membership.update_member(member, %{user: nil}) # Verify unlink {:ok, loaded_unlinked} = Ash.get(Mv.Membership.Member, unlinked_member.id, load: [:user]) assert loaded_unlinked.user == nil # User email should remain unchanged after unlinking {:ok, user_after_unlink} = Ash.get(Mv.Accounts.User, user.id) assert to_string(user_after_unlink.email) == "user@example.com" end end end