defmodule Mv.Membership.MemberGroupTest do @moduledoc """ Tests for MemberGroup join table resource - validations and cascade delete behavior. """ use Mv.DataCase, async: true alias Mv.Membership require Ash.Query import Ash.Expr setup do system_actor = Mv.Helpers.SystemActor.get_system_actor() %{actor: system_actor} end describe "Validations & Associations" do test "create association between member and group", %{actor: actor} do {:ok, member} = Membership.create_member(%{email: "test@test.com"}, actor: actor) {:ok, group} = Membership.create_group(%{name: "Test Group"}, actor: actor) assert {:ok, member_group} = Membership.create_member_group(%{member_id: member.id, group_id: group.id}, actor: actor ) assert member_group.member_id == member.id assert member_group.group_id == group.id end test "prevent duplicate associations (same member + same group)", %{actor: actor} do {:ok, member} = Membership.create_member(%{email: "test@test.com"}, actor: actor) {:ok, group} = Membership.create_group(%{name: "Test Group"}, actor: actor) {:ok, _mg1} = Membership.create_member_group(%{member_id: member.id, group_id: group.id}, actor: actor ) # Try to create duplicate assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member_group(%{member_id: member.id, group_id: group.id}, actor: actor ) assert Enum.any?(errors, fn err -> ((err.field == :member_id or err.field == :group_id) and String.contains?(err.message, "already been taken")) or String.contains?(err.message, "already exists") or String.contains?(err.message, "duplicate") end) end end describe "Cascade Delete Behavior" do test "cascade delete when member deleted (MemberGroup deleted, Group remains)", %{ actor: actor } do {:ok, member} = Membership.create_member(%{email: "test@test.com"}, actor: actor) {:ok, group} = Membership.create_group(%{name: "Test Group"}, actor: actor) {:ok, _mg} = Membership.create_member_group(%{member_id: member.id, group_id: group.id}, actor: actor ) # Delete member :ok = Membership.destroy_member(member, actor: actor) # Group should still exist {:ok, group_reloaded} = Ash.get(Mv.Membership.Group, group.id, actor: actor) assert group_reloaded != nil # MemberGroup should be deleted {:ok, mgs} = Ash.read( Mv.Membership.MemberGroup |> Ash.Query.filter(expr(member_id == ^member.id)), actor: actor, domain: Mv.Membership ) assert mgs == [] end test "cascade delete when group deleted (MemberGroup deleted, Member remains)", %{ actor: actor } do {:ok, member} = Membership.create_member(%{email: "test@test.com"}, actor: actor) {:ok, group} = Membership.create_group(%{name: "Test Group"}, actor: actor) {:ok, _mg} = Membership.create_member_group(%{member_id: member.id, group_id: group.id}, actor: actor ) # Delete group :ok = Membership.destroy_group(group, actor: actor) # Member should still exist {:ok, member_reloaded} = Ash.get(Mv.Membership.Member, member.id, actor: actor) assert member_reloaded != nil # MemberGroup should be deleted {:ok, mgs} = Ash.read( Mv.Membership.MemberGroup |> Ash.Query.filter(expr(group_id == ^group.id)), actor: actor, domain: Mv.Membership ) assert mgs == [] end end end