refactor(member-live): modularize the overview and drop the superseded in-memory paths
Extract the cookie parser, export-payload builder and fee-status helper into their own modules and remove the filter/sort/load helpers the database pushdown made dead, so the overview LiveView stays a thin coordinator over focused units.
This commit is contained in:
parent
c2cb3edab8
commit
77fc11a0b0
17 changed files with 375 additions and 875 deletions
|
|
@ -1,365 +0,0 @@
|
|||
defmodule MvWeb.MemberLive.Index.MembershipFeeStatusTest do
|
||||
@moduledoc """
|
||||
Tests for MembershipFeeStatus helper module.
|
||||
"""
|
||||
use Mv.DataCase, async: false
|
||||
|
||||
import Mv.Fixtures, only: [create_fee_type: 1, create_cycle: 3]
|
||||
|
||||
alias Mv.Membership.Member
|
||||
alias MvWeb.MemberLive.Index.MembershipFeeStatus
|
||||
|
||||
require Ash.Query
|
||||
|
||||
# Helper to create a member
|
||||
defp create_member(attrs) do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
default_attrs = %{
|
||||
first_name: "Test",
|
||||
last_name: "Member",
|
||||
email: "test.member.#{System.unique_integer([:positive])}@example.com"
|
||||
}
|
||||
|
||||
attrs = Map.merge(default_attrs, attrs)
|
||||
{:ok, member} = Mv.Membership.create_member(attrs, actor: system_actor)
|
||||
member
|
||||
end
|
||||
|
||||
describe "load_cycles_for_members/2" do
|
||||
test "efficiently loads cycles for members" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
|
||||
member1 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
member2 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
|
||||
create_cycle(member1, fee_type, %{cycle_start: ~D[2023-01-01], status: :paid})
|
||||
create_cycle(member2, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
||||
|
||||
query =
|
||||
Member
|
||||
|> Ash.Query.filter(id in [^member1.id, ^member2.id])
|
||||
|> MembershipFeeStatus.load_cycles_for_members()
|
||||
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
members = Ash.read!(query, actor: system_actor)
|
||||
|
||||
assert length(members) == 2
|
||||
|
||||
# Verify cycles are loaded
|
||||
member1_loaded = Enum.find(members, &(&1.id == member1.id))
|
||||
member2_loaded = Enum.find(members, &(&1.id == member2.id))
|
||||
|
||||
assert member1_loaded.membership_fee_cycles != nil
|
||||
assert member2_loaded.membership_fee_cycles != nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_cycle_status_for_member/2" do
|
||||
test "returns status of last completed cycle" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
# Create member without fee type to avoid auto-generation
|
||||
member = create_member(%{})
|
||||
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
# Assign fee type
|
||||
member =
|
||||
member
|
||||
|> then(fn m ->
|
||||
{:ok, updated} =
|
||||
Mv.Membership.update_member(m, %{membership_fee_type_id: fee_type.id},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
updated
|
||||
end)
|
||||
|
||||
# Delete any auto-generated cycles
|
||||
cycles =
|
||||
Mv.MembershipFees.MembershipFeeCycle
|
||||
|> Ash.Query.filter(member_id == ^member.id)
|
||||
|> Ash.read!(actor: system_actor)
|
||||
|
||||
Enum.each(cycles, fn cycle -> Ash.destroy!(cycle, actor: system_actor) end)
|
||||
|
||||
# Create cycles with dates that ensure 2023 is last completed
|
||||
# Use a fixed "today" date in 2024 to make 2023 the last completed
|
||||
create_cycle(member, fee_type, %{cycle_start: ~D[2022-01-01], status: :paid})
|
||||
create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
||||
|
||||
# Load cycles with membership_fee_type relationship
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
member =
|
||||
member
|
||||
|> Ash.load!([membership_fee_cycles: [:membership_fee_type]], actor: system_actor)
|
||||
|> Ash.load!(:membership_fee_type, actor: system_actor)
|
||||
|
||||
# Use fixed date in 2024 to ensure 2023 is last completed
|
||||
# We need to manually set the date for the helper function
|
||||
# Since get_cycle_status_for_member doesn't take a date, we need to ensure
|
||||
# the cycles are properly loaded with their fee_type relationship
|
||||
status = MembershipFeeStatus.get_cycle_status_for_member(member, false)
|
||||
|
||||
# The status depends on what Date.utc_today() returns
|
||||
# If we're in 2024 or later, 2023 should be last completed
|
||||
# If we're still in 2023, 2022 would be last completed
|
||||
# For this test, we'll just verify it returns a valid status
|
||||
assert status in [:paid, :unpaid, :suspended, nil]
|
||||
end
|
||||
|
||||
test "returns status of current cycle when show_current is true" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
# Create member without fee type to avoid auto-generation
|
||||
member = create_member(%{})
|
||||
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
# Assign fee type
|
||||
member =
|
||||
member
|
||||
|> then(fn m ->
|
||||
{:ok, updated} =
|
||||
Mv.Membership.update_member(m, %{membership_fee_type_id: fee_type.id},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
updated
|
||||
end)
|
||||
|
||||
# Delete any auto-generated cycles
|
||||
cycles =
|
||||
Mv.MembershipFees.MembershipFeeCycle
|
||||
|> Ash.Query.filter(member_id == ^member.id)
|
||||
|> Ash.read!(actor: system_actor)
|
||||
|
||||
Enum.each(cycles, fn cycle -> Ash.destroy!(cycle, actor: system_actor) end)
|
||||
|
||||
# Create cycles - use current year for current cycle
|
||||
today = Date.utc_today()
|
||||
current_year_start = %{today | month: 1, day: 1}
|
||||
last_year_start = %{current_year_start | year: current_year_start.year - 1}
|
||||
|
||||
create_cycle(member, fee_type, %{cycle_start: last_year_start, status: :paid})
|
||||
create_cycle(member, fee_type, %{cycle_start: current_year_start, status: :suspended})
|
||||
|
||||
# Load cycles with membership_fee_type relationship
|
||||
member =
|
||||
member
|
||||
|> Ash.load!([membership_fee_cycles: [:membership_fee_type]], actor: system_actor)
|
||||
|> Ash.load!(:membership_fee_type, actor: system_actor)
|
||||
|
||||
status = MembershipFeeStatus.get_cycle_status_for_member(member, true)
|
||||
|
||||
# Should return status of current cycle
|
||||
assert status == :suspended
|
||||
end
|
||||
|
||||
test "returns nil if no cycles exist" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
# Create member without fee type to avoid auto-generation
|
||||
member = create_member(%{})
|
||||
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
# Assign fee type
|
||||
member =
|
||||
member
|
||||
|> then(fn m ->
|
||||
{:ok, updated} =
|
||||
Mv.Membership.update_member(m, %{membership_fee_type_id: fee_type.id},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
updated
|
||||
end)
|
||||
|
||||
# Delete any auto-generated cycles
|
||||
cycles =
|
||||
Mv.MembershipFees.MembershipFeeCycle
|
||||
|> Ash.Query.filter(member_id == ^member.id)
|
||||
|> Ash.read!(actor: system_actor)
|
||||
|
||||
Enum.each(cycles, fn cycle -> Ash.destroy!(cycle, actor: system_actor) end)
|
||||
|
||||
# Load cycles and fee type first (will be empty)
|
||||
member =
|
||||
member
|
||||
|> Ash.load!([membership_fee_cycles: [:membership_fee_type]], actor: system_actor)
|
||||
|> Ash.load!(:membership_fee_type, actor: system_actor)
|
||||
|
||||
status = MembershipFeeStatus.get_cycle_status_for_member(member, false)
|
||||
|
||||
assert status == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "format_cycle_status_badge/1" do
|
||||
test "returns badge component for paid status" do
|
||||
result = MembershipFeeStatus.format_cycle_status_badge(:paid)
|
||||
assert result.color == "badge-success"
|
||||
assert result.icon == "hero-check-circle"
|
||||
assert result.label == "Paid" || result.label == "Bezahlt"
|
||||
end
|
||||
|
||||
test "returns badge component for unpaid status" do
|
||||
result = MembershipFeeStatus.format_cycle_status_badge(:unpaid)
|
||||
assert result.color == "badge-error"
|
||||
assert result.icon == "hero-x-circle"
|
||||
assert result.label == "Unpaid" || result.label == "Unbezahlt"
|
||||
end
|
||||
|
||||
test "returns badge component for suspended status" do
|
||||
result = MembershipFeeStatus.format_cycle_status_badge(:suspended)
|
||||
assert result.color == "badge-ghost"
|
||||
assert result.icon == "hero-pause-circle"
|
||||
assert result.label == "Suspended" || result.label == "Ausgesetzt"
|
||||
end
|
||||
|
||||
test "handles nil status gracefully" do
|
||||
result = MembershipFeeStatus.format_cycle_status_badge(nil)
|
||||
assert result == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "filter_members_by_cycle_status/3" do
|
||||
test "filters paid members in last cycle" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
today = Date.utc_today()
|
||||
last_year_start = Date.new!(today.year - 1, 1, 1)
|
||||
|
||||
# Member with paid last cycle
|
||||
member1 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
create_cycle(member1, fee_type, %{cycle_start: last_year_start, status: :paid})
|
||||
|
||||
# Member with unpaid last cycle
|
||||
member2 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
create_cycle(member2, fee_type, %{cycle_start: last_year_start, status: :unpaid})
|
||||
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
members =
|
||||
[member1, member2]
|
||||
|> Enum.map(fn m ->
|
||||
m
|
||||
|> Ash.load!([membership_fee_cycles: [:membership_fee_type]], actor: system_actor)
|
||||
|> Ash.load!(:membership_fee_type, actor: system_actor)
|
||||
end)
|
||||
|
||||
filtered = MembershipFeeStatus.filter_members_by_cycle_status(members, :paid, false)
|
||||
|
||||
assert length(filtered) == 1
|
||||
assert List.first(filtered).id == member1.id
|
||||
end
|
||||
|
||||
test "filters unpaid members in last cycle" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
today = Date.utc_today()
|
||||
last_year_start = Date.new!(today.year - 1, 1, 1)
|
||||
|
||||
# Member with paid last cycle
|
||||
member1 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
create_cycle(member1, fee_type, %{cycle_start: last_year_start, status: :paid})
|
||||
|
||||
# Member with unpaid last cycle
|
||||
member2 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
create_cycle(member2, fee_type, %{cycle_start: last_year_start, status: :unpaid})
|
||||
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
members =
|
||||
[member1, member2]
|
||||
|> Enum.map(fn m ->
|
||||
m
|
||||
|> Ash.load!([membership_fee_cycles: [:membership_fee_type]], actor: system_actor)
|
||||
|> Ash.load!(:membership_fee_type, actor: system_actor)
|
||||
end)
|
||||
|
||||
filtered = MembershipFeeStatus.filter_members_by_cycle_status(members, :unpaid, false)
|
||||
|
||||
assert length(filtered) == 1
|
||||
assert List.first(filtered).id == member2.id
|
||||
end
|
||||
|
||||
test "filters paid members in current cycle" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
today = Date.utc_today()
|
||||
current_year_start = Date.new!(today.year, 1, 1)
|
||||
|
||||
# Member with paid current cycle
|
||||
member1 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
create_cycle(member1, fee_type, %{cycle_start: current_year_start, status: :paid})
|
||||
|
||||
# Member with unpaid current cycle
|
||||
member2 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
create_cycle(member2, fee_type, %{cycle_start: current_year_start, status: :unpaid})
|
||||
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
members =
|
||||
[member1, member2]
|
||||
|> Enum.map(fn m ->
|
||||
m
|
||||
|> Ash.load!([membership_fee_cycles: [:membership_fee_type]], actor: system_actor)
|
||||
|> Ash.load!(:membership_fee_type, actor: system_actor)
|
||||
end)
|
||||
|
||||
filtered = MembershipFeeStatus.filter_members_by_cycle_status(members, :paid, true)
|
||||
|
||||
assert length(filtered) == 1
|
||||
assert List.first(filtered).id == member1.id
|
||||
end
|
||||
|
||||
test "filters unpaid members in current cycle" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
today = Date.utc_today()
|
||||
current_year_start = Date.new!(today.year, 1, 1)
|
||||
|
||||
# Member with paid current cycle
|
||||
member1 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
create_cycle(member1, fee_type, %{cycle_start: current_year_start, status: :paid})
|
||||
|
||||
# Member with unpaid current cycle
|
||||
member2 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
create_cycle(member2, fee_type, %{cycle_start: current_year_start, status: :unpaid})
|
||||
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
members =
|
||||
[member1, member2]
|
||||
|> Enum.map(fn m ->
|
||||
m
|
||||
|> Ash.load!([membership_fee_cycles: [:membership_fee_type]], actor: system_actor)
|
||||
|> Ash.load!(:membership_fee_type, actor: system_actor)
|
||||
end)
|
||||
|
||||
filtered = MembershipFeeStatus.filter_members_by_cycle_status(members, :unpaid, true)
|
||||
|
||||
assert length(filtered) == 1
|
||||
assert List.first(filtered).id == member2.id
|
||||
end
|
||||
|
||||
test "returns all members when filter is nil" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
member1 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
member2 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
members =
|
||||
[member1, member2]
|
||||
|> Enum.map(fn m ->
|
||||
m
|
||||
|> Ash.load!([membership_fee_cycles: [:membership_fee_type]], actor: system_actor)
|
||||
|> Ash.load!(:membership_fee_type, actor: system_actor)
|
||||
end)
|
||||
|
||||
# filter_unpaid_members should still work for backwards compatibility
|
||||
filtered = MembershipFeeStatus.filter_unpaid_members(members, false)
|
||||
|
||||
# Both members have no cycles, so both should be filtered out
|
||||
assert Enum.empty?(filtered)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -95,6 +95,9 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
|||
html = render(view)
|
||||
# Should show suspended status (current cycle)
|
||||
assert html =~ "hero-pause-circle" || html =~ "suspended"
|
||||
|
||||
# The toggle button exposes its pressed state to assistive tech.
|
||||
assert has_element?(view, ~s([data-testid=toggle-cycle-view][aria-pressed="true"]))
|
||||
end
|
||||
|
||||
test "shows correct color coding for paid status", %{conn: conn} do
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ defmodule MvWeb.MemberLive.IndexPaginationTest do
|
|||
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
require Ash.Query
|
||||
|
||||
alias Mv.Helpers.SystemActor
|
||||
|
||||
require Ash.Query
|
||||
|
||||
# Matches the :overview default_limit / @page_limit in the LiveView.
|
||||
@page_limit 50
|
||||
|
||||
|
|
|
|||
|
|
@ -708,27 +708,6 @@ defmodule MvWeb.MemberLive.IndexTest do
|
|||
# Flash message should appear
|
||||
assert has_element?(view, "#flash-group")
|
||||
end
|
||||
|
||||
test "copy excludes a member whose email is blank from the recipient list", %{conn: conn} do
|
||||
# The Member create action requires an email, so a blank-email member cannot
|
||||
# be persisted; we exercise the preserved defensive filter in
|
||||
# format_selected_member_emails/2 directly. One member has an email, the
|
||||
# other has a blank one — only the former is a recipient (§1.10).
|
||||
with_email = %{
|
||||
id: Ecto.UUID.generate(),
|
||||
first_name: "Has",
|
||||
last_name: "Mail",
|
||||
email: "has@example.com"
|
||||
}
|
||||
|
||||
blank_email = %{id: Ecto.UUID.generate(), first_name: "Blank", last_name: "Mail", email: ""}
|
||||
selected = MapSet.new([with_email.id, blank_email.id])
|
||||
|
||||
emails = MemberIndex.format_selected_member_emails([with_email, blank_email], selected)
|
||||
|
||||
assert emails == ["Has Mail <has@example.com>"]
|
||||
_ = conn
|
||||
end
|
||||
end
|
||||
|
||||
describe "copy_emails empty-recipient feedback" do
|
||||
|
|
@ -1800,153 +1779,6 @@ defmodule MvWeb.MemberLive.IndexTest do
|
|||
|> Ash.load!(:custom_field_values, actor: actor)
|
||||
end
|
||||
|
||||
# Tests for get_boolean_custom_field_value/2
|
||||
test "get_boolean_custom_field_value extracts true from Ash.Union format", %{conn: _conn} do
|
||||
system_actor = SystemActor.get_system_actor()
|
||||
boolean_field = create_boolean_custom_field()
|
||||
member = create_member_with_boolean_value(%{}, boolean_field, true, system_actor)
|
||||
|
||||
# Test the function (will fail until implemented)
|
||||
result = MemberIndex.get_boolean_custom_field_value(member, boolean_field)
|
||||
|
||||
assert result == true
|
||||
end
|
||||
|
||||
test "get_boolean_custom_field_value extracts false from Ash.Union format", %{conn: _conn} do
|
||||
system_actor = SystemActor.get_system_actor()
|
||||
boolean_field = create_boolean_custom_field()
|
||||
member = create_member_with_boolean_value(%{}, boolean_field, false, system_actor)
|
||||
|
||||
result = MemberIndex.get_boolean_custom_field_value(member, boolean_field)
|
||||
|
||||
assert result == false
|
||||
end
|
||||
|
||||
test "get_boolean_custom_field_value extracts true from map format with _union_type and _union_value keys",
|
||||
%{conn: _conn} do
|
||||
system_actor = SystemActor.get_system_actor()
|
||||
boolean_field = create_boolean_custom_field()
|
||||
|
||||
{:ok, member} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Test",
|
||||
last_name: "Member",
|
||||
email: "test.member.#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
# Create CustomFieldValue with map format (Ash expects _union_type and _union_value)
|
||||
{:ok, _cfv} =
|
||||
CustomFieldValue
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
member_id: member.id,
|
||||
custom_field_id: boolean_field.id,
|
||||
value: %{"_union_type" => "boolean", "_union_value" => true}
|
||||
})
|
||||
|> Ash.create(actor: system_actor)
|
||||
|
||||
# Reload member with custom field values
|
||||
member = member |> Ash.load!(:custom_field_values, actor: system_actor)
|
||||
|
||||
result = MemberIndex.get_boolean_custom_field_value(member, boolean_field)
|
||||
|
||||
assert result == true
|
||||
end
|
||||
|
||||
test "get_boolean_custom_field_value returns nil when no CustomFieldValue exists", %{
|
||||
conn: _conn
|
||||
} do
|
||||
system_actor = SystemActor.get_system_actor()
|
||||
boolean_field = create_boolean_custom_field()
|
||||
|
||||
{:ok, member} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Test",
|
||||
last_name: "Member",
|
||||
email: "test.member.#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
# Member has no custom field value for this field
|
||||
member = member |> Ash.load!(:custom_field_values, actor: system_actor)
|
||||
|
||||
result = MemberIndex.get_boolean_custom_field_value(member, boolean_field)
|
||||
|
||||
assert result == nil
|
||||
end
|
||||
|
||||
test "get_boolean_custom_field_value returns nil when CustomFieldValue has nil value", %{
|
||||
conn: _conn
|
||||
} do
|
||||
system_actor = SystemActor.get_system_actor()
|
||||
boolean_field = create_boolean_custom_field()
|
||||
|
||||
{:ok, member} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Test",
|
||||
last_name: "Member",
|
||||
email: "test.member.#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
# Create CustomFieldValue with nil value (edge case)
|
||||
{:ok, _cfv} =
|
||||
CustomFieldValue
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
member_id: member.id,
|
||||
custom_field_id: boolean_field.id,
|
||||
value: nil
|
||||
})
|
||||
|> Ash.create(actor: system_actor)
|
||||
|
||||
member = member |> Ash.load!(:custom_field_values, actor: system_actor)
|
||||
|
||||
result = MemberIndex.get_boolean_custom_field_value(member, boolean_field)
|
||||
|
||||
assert result == nil
|
||||
end
|
||||
|
||||
test "get_boolean_custom_field_value returns nil for non-boolean CustomFieldValue", %{
|
||||
conn: _conn
|
||||
} do
|
||||
system_actor = SystemActor.get_system_actor()
|
||||
string_field = create_string_custom_field()
|
||||
boolean_field = create_boolean_custom_field()
|
||||
|
||||
{:ok, member} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Test",
|
||||
last_name: "Member",
|
||||
email: "test.member.#{System.unique_integer([:positive])}@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
# Create string custom field value (not boolean)
|
||||
{:ok, _cfv} =
|
||||
CustomFieldValue
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
member_id: member.id,
|
||||
custom_field_id: string_field.id,
|
||||
value: %{"_union_type" => "string", "_union_value" => "test"}
|
||||
})
|
||||
|> Ash.create(actor: system_actor)
|
||||
|
||||
member = member |> Ash.load!(:custom_field_values, actor: system_actor)
|
||||
|
||||
# Try to get boolean value from string field - should return nil
|
||||
result = MemberIndex.get_boolean_custom_field_value(member, boolean_field)
|
||||
|
||||
assert result == nil
|
||||
end
|
||||
|
||||
# Tests for apply_boolean_custom_field_filters/2
|
||||
test "apply_boolean_custom_field_filters filters members with true value and excludes false/without values",
|
||||
%{conn: _conn} do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue