defmodule Mv.Accounts.EmailUniquenessTest do use Mv.DataCase, async: false alias Mv.Accounts alias Mv.Membership describe "Email uniqueness validation" do test "cannot create member with existing unlinked user email" do # Create a user with email {:ok, _user} = Accounts.create_user(%{ email: "existing@example.com" }) # Try to create member with same email result = Membership.create_member(%{ first_name: "John", last_name: "Doe", email: "existing@example.com" }) assert {:error, %Ash.Error.Invalid{} = error} = result assert error.errors |> Enum.any?(fn e -> e.field == :email and (String.contains?(e.message, "already") or String.contains?(e.message, "used")) end) end test "cannot create user with existing unlinked member email" do # Create a member with email {:ok, _member} = Membership.create_member(%{ first_name: "John", last_name: "Doe", email: "existing@example.com" }) # Try to create user with same email result = Accounts.create_user(%{ email: "existing@example.com" }) assert {:error, %Ash.Error.Invalid{} = error} = result assert error.errors |> Enum.any?(fn e -> e.field == :email and (String.contains?(e.message, "already") or String.contains?(e.message, "used")) end) end test "member email cannot be changed to an existing unlinked user email" do # Create a user with email {:ok, user} = Accounts.create_user(%{ email: "existing_user@example.com" }) # Create a member with different email {:ok, member} = Membership.create_member(%{ first_name: "John", last_name: "Doe", email: "member@example.com" }) # Try to change member email to existing user email result = Membership.update_member(member, %{ email: "existing_user@example.com" }) assert {:error, %Ash.Error.Invalid{} = error} = result assert error.errors |> Enum.any?(fn e -> e.field == :email and (String.contains?(e.message, "already") or String.contains?(e.message, "used")) end) end test "user email cannot be changed to an existing unlinked member email" do # Create a member with email {:ok, member} = Membership.create_member(%{ first_name: "John", last_name: "Doe", email: "existing_member@example.com" }) # Create a user with different email {:ok, user} = Accounts.create_user(%{ email: "user@example.com" }) # Try to change user email to existing member email result = Accounts.update_user(user, %{ email: "existing_member@example.com" }) assert {:error, %Ash.Error.Invalid{} = error} = result assert error.errors |> Enum.any?(fn e -> e.field == :email and (String.contains?(e.message, "already") or String.contains?(e.message, "used")) end) end test "member email syncs to linked user email without validation error" do # Create a user {:ok, user} = Accounts.create_user(%{ email: "user@example.com" }) # Create a member linked to this user # The override change will set member.email = user.email automatically {:ok, member} = Membership.create_member(%{ first_name: "John", last_name: "Doe", email: "member@example.com", user: %{id: user.id} }) # Member email should have been overridden to user email # This happens through our sync mechanism, which should NOT trigger # the "email already used" validation because it's the same user {:ok, member_after_link} = Ash.get(Mv.Membership.Member, member.id) assert member_after_link.email == "user@example.com" end test "user email syncs to linked member without validation error" do # Create a member {:ok, member} = Membership.create_member(%{ first_name: "John", last_name: "Doe", email: "member@example.com" }) # Create a user linked to this member # The override change will set member.email = user.email automatically {:ok, user} = Accounts.create_user(%{ email: "user@example.com", member: %{id: member.id} }) # Member email should have been overridden to user email # This happens through our sync mechanism, which should NOT trigger # the "email already used" validation because it's the same member {:ok, member_after_link} = Ash.get(Mv.Membership.Member, member.id) assert member_after_link.email == "user@example.com" end test "two unlinked users cannot have the same email" do # Create first user {:ok, _user1} = Accounts.create_user(%{ email: "duplicate@example.com" }) # Try to create second user with same email result = Accounts.create_user(%{ email: "duplicate@example.com" }) assert {:error, %Ash.Error.Invalid{}} = result end test "two unlinked members cannot have the same email (members have unique constraint)" do # Create first member {:ok, _member1} = Membership.create_member(%{ first_name: "John", last_name: "Doe", email: "duplicate@example.com" }) # Try to create second member with same email - should fail result = Membership.create_member(%{ first_name: "Jane", last_name: "Smith", email: "duplicate@example.com" }) assert {:error, %Ash.Error.Invalid{}} = result # Members DO have a unique email constraint at database level end end end