Tests: use code interface for Member create/update (actor propagation)
This commit is contained in:
parent
5a2f035ecc
commit
4473cfd372
32 changed files with 733 additions and 818 deletions
|
|
@ -9,7 +9,7 @@ defmodule Mv.Membership.CustomFieldValuePoliciesTest do
|
|||
# async: false because we need database commits to be visible across queries
|
||||
use Mv.DataCase, async: false
|
||||
|
||||
alias Mv.Membership.{CustomField, CustomFieldValue, Member}
|
||||
alias Mv.Membership.{CustomField, CustomFieldValue}
|
||||
alias Mv.Accounts
|
||||
alias Mv.Authorization
|
||||
|
||||
|
|
@ -62,13 +62,14 @@ defmodule Mv.Membership.CustomFieldValuePoliciesTest do
|
|||
|
||||
defp create_linked_member_for_user(user, actor) do
|
||||
{:ok, member} =
|
||||
Member
|
||||
|> Ash.Changeset.for_create(:create_member, %{
|
||||
first_name: "Linked",
|
||||
last_name: "Member",
|
||||
email: "linked#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|> Ash.create(actor: actor, return_notifications?: false)
|
||||
Mv.Membership.create_member(
|
||||
%{
|
||||
first_name: "Linked",
|
||||
last_name: "Member",
|
||||
email: "linked#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: actor
|
||||
)
|
||||
|
||||
user
|
||||
|> Ash.Changeset.for_update(:update, %{})
|
||||
|
|
@ -80,13 +81,14 @@ defmodule Mv.Membership.CustomFieldValuePoliciesTest do
|
|||
|
||||
defp create_unlinked_member(actor) do
|
||||
{:ok, member} =
|
||||
Member
|
||||
|> Ash.Changeset.for_create(:create_member, %{
|
||||
first_name: "Unlinked",
|
||||
last_name: "Member",
|
||||
email: "unlinked#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|> Ash.create(actor: actor)
|
||||
Mv.Membership.create_member(
|
||||
%{
|
||||
first_name: "Unlinked",
|
||||
last_name: "Member",
|
||||
email: "unlinked#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: actor
|
||||
)
|
||||
|
||||
member
|
||||
end
|
||||
|
|
|
|||
|
|
@ -78,13 +78,14 @@ defmodule Mv.Membership.MemberPoliciesTest do
|
|||
# NOTE: We need to ensure the member is actually persisted to the database
|
||||
# before we try to link it. Ash may delay writes, so we explicitly return the struct.
|
||||
{:ok, member} =
|
||||
Membership.Member
|
||||
|> Ash.Changeset.for_create(:create_member, %{
|
||||
first_name: "Linked",
|
||||
last_name: "Member",
|
||||
email: "linked#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|> Ash.create(actor: admin, return_notifications?: false)
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Linked",
|
||||
last_name: "Member",
|
||||
email: "linked#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: admin
|
||||
)
|
||||
|
||||
# Link member to user (User.member_id = member.id)
|
||||
# We use force_change_attribute because the member already exists and we just
|
||||
|
|
@ -108,13 +109,14 @@ defmodule Mv.Membership.MemberPoliciesTest do
|
|||
admin = create_admin_user(actor)
|
||||
|
||||
{:ok, member} =
|
||||
Membership.Member
|
||||
|> Ash.Changeset.for_create(:create_member, %{
|
||||
first_name: "Unlinked",
|
||||
last_name: "Member",
|
||||
email: "unlinked#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|> Ash.create(actor: admin)
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Unlinked",
|
||||
last_name: "Member",
|
||||
email: "unlinked#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: admin
|
||||
)
|
||||
|
||||
member
|
||||
end
|
||||
|
|
@ -145,9 +147,7 @@ defmodule Mv.Membership.MemberPoliciesTest do
|
|||
# Update is allowed via HasPermission check with :linked scope (not via special case)
|
||||
# The special case policy only applies to :read actions
|
||||
{:ok, updated_member} =
|
||||
linked_member
|
||||
|> Ash.Changeset.for_update(:update_member, %{first_name: "Updated"})
|
||||
|> Ash.update(actor: user)
|
||||
Membership.update_member(linked_member, %{first_name: "Updated"}, actor: user)
|
||||
|
||||
assert updated_member.first_name == "Updated"
|
||||
end
|
||||
|
|
@ -168,11 +168,8 @@ defmodule Mv.Membership.MemberPoliciesTest do
|
|||
user: user,
|
||||
unlinked_member: unlinked_member
|
||||
} do
|
||||
assert_raise Ash.Error.Forbidden, fn ->
|
||||
unlinked_member
|
||||
|> Ash.Changeset.for_update(:update_member, %{first_name: "Updated"})
|
||||
|> Ash.update!(actor: user)
|
||||
end
|
||||
assert {:error, %Ash.Error.Forbidden{}} =
|
||||
Membership.update_member(unlinked_member, %{first_name: "Updated"}, actor: user)
|
||||
end
|
||||
|
||||
test "list members returns only linked member", %{
|
||||
|
|
@ -187,15 +184,15 @@ defmodule Mv.Membership.MemberPoliciesTest do
|
|||
end
|
||||
|
||||
test "cannot create member (returns forbidden)", %{user: user} do
|
||||
assert_raise Ash.Error.Forbidden, fn ->
|
||||
Membership.Member
|
||||
|> Ash.Changeset.for_create(:create_member, %{
|
||||
first_name: "New",
|
||||
last_name: "Member",
|
||||
email: "new#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|> Ash.create!(actor: user)
|
||||
end
|
||||
assert {:error, %Ash.Error.Forbidden{}} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "New",
|
||||
last_name: "Member",
|
||||
email: "new#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: user
|
||||
)
|
||||
end
|
||||
|
||||
test "cannot destroy member (returns forbidden)", %{
|
||||
|
|
@ -245,26 +242,23 @@ defmodule Mv.Membership.MemberPoliciesTest do
|
|||
end
|
||||
|
||||
test "cannot create member (returns forbidden)", %{user: user} do
|
||||
assert_raise Ash.Error.Forbidden, fn ->
|
||||
Membership.Member
|
||||
|> Ash.Changeset.for_create(:create_member, %{
|
||||
first_name: "New",
|
||||
last_name: "Member",
|
||||
email: "new#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|> Ash.create!(actor: user)
|
||||
end
|
||||
assert {:error, %Ash.Error.Forbidden{}} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "New",
|
||||
last_name: "Member",
|
||||
email: "new#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: user
|
||||
)
|
||||
end
|
||||
|
||||
test "cannot update any member (returns forbidden)", %{
|
||||
user: user,
|
||||
linked_member: linked_member
|
||||
} do
|
||||
assert_raise Ash.Error.Forbidden, fn ->
|
||||
linked_member
|
||||
|> Ash.Changeset.for_update(:update_member, %{first_name: "Updated"})
|
||||
|> Ash.update!(actor: user)
|
||||
end
|
||||
assert {:error, %Ash.Error.Forbidden{}} =
|
||||
Membership.update_member(linked_member, %{first_name: "Updated"}, actor: user)
|
||||
end
|
||||
|
||||
test "cannot destroy any member (returns forbidden)", %{
|
||||
|
|
@ -305,22 +299,21 @@ defmodule Mv.Membership.MemberPoliciesTest do
|
|||
|
||||
test "can create member", %{user: user} do
|
||||
{:ok, member} =
|
||||
Membership.Member
|
||||
|> Ash.Changeset.for_create(:create_member, %{
|
||||
first_name: "New",
|
||||
last_name: "Member",
|
||||
email: "new#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|> Ash.create(actor: user)
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "New",
|
||||
last_name: "Member",
|
||||
email: "new#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: user
|
||||
)
|
||||
|
||||
assert member.first_name == "New"
|
||||
end
|
||||
|
||||
test "can update any member", %{user: user, unlinked_member: unlinked_member} do
|
||||
{:ok, updated_member} =
|
||||
unlinked_member
|
||||
|> Ash.Changeset.for_update(:update_member, %{first_name: "Updated"})
|
||||
|> Ash.update(actor: user)
|
||||
Membership.update_member(unlinked_member, %{first_name: "Updated"}, actor: user)
|
||||
|
||||
assert updated_member.first_name == "Updated"
|
||||
end
|
||||
|
|
@ -363,22 +356,21 @@ defmodule Mv.Membership.MemberPoliciesTest do
|
|||
|
||||
test "can create member", %{user: user} do
|
||||
{:ok, member} =
|
||||
Membership.Member
|
||||
|> Ash.Changeset.for_create(:create_member, %{
|
||||
first_name: "New",
|
||||
last_name: "Member",
|
||||
email: "new#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|> Ash.create(actor: user)
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "New",
|
||||
last_name: "Member",
|
||||
email: "new#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: user
|
||||
)
|
||||
|
||||
assert member.first_name == "New"
|
||||
end
|
||||
|
||||
test "can update any member", %{user: user, unlinked_member: unlinked_member} do
|
||||
{:ok, updated_member} =
|
||||
unlinked_member
|
||||
|> Ash.Changeset.for_update(:update_member, %{first_name: "Updated"})
|
||||
|> Ash.update(actor: user)
|
||||
Membership.update_member(unlinked_member, %{first_name: "Updated"}, actor: user)
|
||||
|
||||
assert updated_member.first_name == "Updated"
|
||||
end
|
||||
|
|
@ -456,9 +448,7 @@ defmodule Mv.Membership.MemberPoliciesTest do
|
|||
|
||||
# Should succeed via HasPermission check (not special case)
|
||||
{:ok, updated_member} =
|
||||
linked_member
|
||||
|> Ash.Changeset.for_update(:update_member, %{first_name: "Updated"})
|
||||
|> Ash.update(actor: user)
|
||||
Membership.update_member(linked_member, %{first_name: "Updated"}, actor: user)
|
||||
|
||||
assert updated_member.first_name == "Updated"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -49,10 +49,8 @@ defmodule Mv.MembershipFees.CycleGeneratorEdgeCasesTest do
|
|||
}
|
||||
|
||||
attrs = Map.merge(default_attrs, attrs)
|
||||
|
||||
Member
|
||||
|> Ash.Changeset.for_create(:create_member, attrs)
|
||||
|> Ash.create!(actor: actor)
|
||||
{:ok, member} = Mv.Membership.create_member(attrs, actor: actor)
|
||||
member
|
||||
end
|
||||
|
||||
# Helper to create a member and explicitly generate cycles with a fixed "today" date.
|
||||
|
|
@ -74,9 +72,12 @@ defmodule Mv.MembershipFees.CycleGeneratorEdgeCasesTest do
|
|||
# Assign fee type if provided (this will trigger auto-generation with real today)
|
||||
member =
|
||||
if fee_type_id do
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type_id})
|
||||
|> Ash.update!(actor: actor)
|
||||
{:ok, updated} =
|
||||
Mv.Membership.update_member(member, %{membership_fee_type_id: fee_type_id},
|
||||
actor: actor
|
||||
)
|
||||
|
||||
updated
|
||||
else
|
||||
member
|
||||
end
|
||||
|
|
@ -130,10 +131,8 @@ defmodule Mv.MembershipFees.CycleGeneratorEdgeCasesTest do
|
|||
)
|
||||
|
||||
# Assign fee type
|
||||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!(actor: actor)
|
||||
{:ok, member} =
|
||||
Mv.Membership.update_member(member, %{membership_fee_type_id: fee_type.id}, actor: actor)
|
||||
|
||||
# Explicitly generate cycles with fixed "today" date
|
||||
{:ok, _, _} = CycleGenerator.generate_cycles_for_member(member.id, today: today)
|
||||
|
|
@ -163,10 +162,8 @@ defmodule Mv.MembershipFees.CycleGeneratorEdgeCasesTest do
|
|||
)
|
||||
|
||||
# Assign fee type
|
||||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!(actor: actor)
|
||||
{:ok, member} =
|
||||
Mv.Membership.update_member(member, %{membership_fee_type_id: fee_type.id}, actor: actor)
|
||||
|
||||
# Explicitly generate cycles with fixed "today" date
|
||||
{:ok, _, _} = CycleGenerator.generate_cycles_for_member(member.id, today: today)
|
||||
|
|
@ -349,10 +346,8 @@ defmodule Mv.MembershipFees.CycleGeneratorEdgeCasesTest do
|
|||
|> Ash.create!(actor: actor)
|
||||
|
||||
# Now assign fee type
|
||||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!(actor: actor)
|
||||
{:ok, member} =
|
||||
Mv.Membership.update_member(member, %{membership_fee_type_id: fee_type.id}, actor: actor)
|
||||
|
||||
# Explicitly generate cycles with fixed "today" date
|
||||
today = ~D[2024-06-15]
|
||||
|
|
@ -616,13 +611,15 @@ defmodule Mv.MembershipFees.CycleGeneratorEdgeCasesTest do
|
|||
)
|
||||
|
||||
# Now assign fee type (simulating a retroactive assignment)
|
||||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2021-01-01]
|
||||
})
|
||||
|> Ash.update!(actor: actor)
|
||||
{:ok, member} =
|
||||
Mv.Membership.update_member(
|
||||
member,
|
||||
%{
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2021-01-01]
|
||||
},
|
||||
actor: actor
|
||||
)
|
||||
|
||||
# Run batch generation with a "today" date after the member left
|
||||
today = ~D[2024-06-15]
|
||||
|
|
|
|||
|
|
@ -40,10 +40,8 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
}
|
||||
|
||||
attrs = Map.merge(default_attrs, attrs)
|
||||
|
||||
Member
|
||||
|> Ash.Changeset.for_create(:create_member, attrs)
|
||||
|> Ash.create!(actor: actor)
|
||||
{:ok, member} = Mv.Membership.create_member(attrs, actor: actor)
|
||||
member
|
||||
end
|
||||
|
||||
# Helper to set up settings with specific include_joining_cycle value
|
||||
|
|
@ -81,8 +79,12 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
# Assign fee type
|
||||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!(actor: actor)
|
||||
|> then(fn m ->
|
||||
{:ok, updated} =
|
||||
Mv.Membership.update_member(m, %{membership_fee_type_id: fee_type.id}, actor: actor)
|
||||
|
||||
updated
|
||||
end)
|
||||
|
||||
# Explicitly generate cycles with fixed "today" date to avoid date dependency
|
||||
today = ~D[2024-06-15]
|
||||
|
|
@ -128,8 +130,12 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
# Now assign fee type to member
|
||||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!(actor: actor)
|
||||
|> then(fn m ->
|
||||
{:ok, updated} =
|
||||
Mv.Membership.update_member(m, %{membership_fee_type_id: fee_type.id}, actor: actor)
|
||||
|
||||
updated
|
||||
end)
|
||||
|
||||
# Generate cycles with specific "today" date
|
||||
today = ~D[2024-06-15]
|
||||
|
|
@ -237,8 +243,12 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
# start from the last existing cycle (2023) and go forward
|
||||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!(actor: actor)
|
||||
|> then(fn m ->
|
||||
{:ok, updated} =
|
||||
Mv.Membership.update_member(m, %{membership_fee_type_id: fee_type.id}, actor: actor)
|
||||
|
||||
updated
|
||||
end)
|
||||
|
||||
# Verify gap was NOT filled and new cycles were generated from last existing
|
||||
all_cycles = get_member_cycles(member.id, actor)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue