93 lines
3.5 KiB
Elixir
93 lines
3.5 KiB
Elixir
defmodule MvWeb.MemberLive.IndexPaymentWiringTest do
|
|
@moduledoc """
|
|
§1.16 / §1.17 — the member overview LiveView honours the period-scoped
|
|
payment-count filter and payment-period URL contract (`pay_filter`,
|
|
`pay_from`, `pay_to`), driving the same DB result set the OverviewQuery unit
|
|
tests pin, but through `handle_params` and the query wiring.
|
|
"""
|
|
use MvWeb.ConnCase, async: false
|
|
|
|
import Phoenix.LiveViewTest
|
|
import Mv.Fixtures, only: [create_fee_type: 2, member_fixture_with_actor: 2, create_cycle: 4]
|
|
|
|
setup %{conn: conn} do
|
|
actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
ft = create_fee_type(%{interval: :monthly}, actor)
|
|
|
|
# Deterministic id set: drop the seeded members.
|
|
Mv.Membership.Member
|
|
|> Ash.read!(actor: actor)
|
|
|> Enum.each(&Ash.destroy!(&1, actor: actor))
|
|
|
|
%{conn: conn_with_oidc_user(conn), actor: actor, ft: ft}
|
|
end
|
|
|
|
defp member_with_unpaid(n, actor, ft) do
|
|
member = member_fixture_with_actor(%{}, actor)
|
|
|
|
Enum.each(1..max(n, 0)//1, fn i ->
|
|
create_cycle(member, ft, %{cycle_start: Date.new!(2024, i, 1), status: :unpaid}, actor)
|
|
end)
|
|
|
|
member
|
|
end
|
|
|
|
test "has-unpaid >= 2 shows only members with at least two in-period unpaid cycles", ctx do
|
|
one = member_with_unpaid(1, ctx.actor, ctx.ft)
|
|
two = member_with_unpaid(2, ctx.actor, ctx.ft)
|
|
|
|
{:ok, view, _html} =
|
|
live(ctx.conn, "/members?pay_filter=unpaid_2&pay_from=2024-01-01&pay_to=2024-12-31")
|
|
|
|
assert has_element?(view, "#row-#{two.id}")
|
|
refute has_element?(view, "#row-#{one.id}")
|
|
end
|
|
|
|
test "fully_paid shows only members with zero in-period unpaid cycles", ctx do
|
|
paid = member_with_unpaid(0, ctx.actor, ctx.ft)
|
|
create_cycle(paid, ctx.ft, %{cycle_start: ~D[2024-05-01], status: :paid}, ctx.actor)
|
|
unpaid = member_with_unpaid(1, ctx.actor, ctx.ft)
|
|
|
|
{:ok, view, _html} =
|
|
live(ctx.conn, "/members?pay_filter=fully_paid&pay_from=2024-01-01&pay_to=2024-12-31")
|
|
|
|
assert has_element?(view, "#row-#{paid.id}")
|
|
refute has_element?(view, "#row-#{unpaid.id}")
|
|
end
|
|
|
|
test "the active period scopes the filter: a cycle outside the period does not count", ctx do
|
|
# One unpaid cycle in 2023, none in 2024. With a 2024 period, has-unpaid>=1
|
|
# must not select this member; with the all-outstanding default it must.
|
|
member = member_fixture_with_actor(%{}, ctx.actor)
|
|
create_cycle(member, ctx.ft, %{cycle_start: ~D[2023-03-01], status: :unpaid}, ctx.actor)
|
|
|
|
{:ok, scoped, _} =
|
|
live(ctx.conn, "/members?pay_filter=unpaid_1&pay_from=2024-01-01&pay_to=2024-12-31")
|
|
|
|
refute has_element?(scoped, "#row-#{member.id}")
|
|
|
|
{:ok, all_time, _} = live(ctx.conn, "/members?pay_filter=unpaid_1")
|
|
assert has_element?(all_time, "#row-#{member.id}")
|
|
end
|
|
|
|
describe "period indicator badge (§1.28)" do
|
|
test "no badge in the default all-outstanding scope", ctx do
|
|
{:ok, view, _} = live(ctx.conn, "/members")
|
|
refute has_element?(view, "[data-testid='payment-period-badge']")
|
|
end
|
|
|
|
test "a full year renders the compact year short code", ctx do
|
|
{:ok, view, _} = live(ctx.conn, "/members?pay_from=2026-01-01&pay_to=2026-12-31")
|
|
|
|
assert has_element?(view, "[data-testid='payment-period-badge']", "2026")
|
|
end
|
|
|
|
test "an arbitrary period falls back to a 'filtered' badge with a period tooltip", ctx do
|
|
{:ok, view, _} = live(ctx.conn, "/members?pay_from=2026-02-03&pay_to=2026-08-17")
|
|
|
|
badge = view |> element("[data-testid='payment-period-badge']") |> render()
|
|
assert badge =~ "03.02.2026"
|
|
assert badge =~ "17.08.2026"
|
|
end
|
|
end
|
|
end
|