test: add comprehensive tests for membership fee UI components
Add tests for all membership fee UI components following TDD principles:
This commit is contained in:
parent
bc989422e2
commit
5789079ab0
9 changed files with 1695 additions and 0 deletions
221
test/mv_web/member_live/membership_fee_integration_test.exs
Normal file
221
test/mv_web/member_live/membership_fee_integration_test.exs
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
defmodule MvWeb.MemberLive.MembershipFeeIntegrationTest do
|
||||
@moduledoc """
|
||||
Integration tests for membership fee UI workflows.
|
||||
"""
|
||||
use MvWeb.ConnCase, async: false
|
||||
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
alias Mv.Membership.Member
|
||||
alias Mv.MembershipFees.MembershipFeeType
|
||||
alias Mv.MembershipFees.MembershipFeeCycle
|
||||
|
||||
require Ash.Query
|
||||
|
||||
setup do
|
||||
# Create admin user
|
||||
{:ok, user} =
|
||||
Mv.Accounts.User
|
||||
|> Ash.Changeset.for_create(:register_with_password, %{
|
||||
email: "admin#{System.unique_integer([:positive])}@mv.local",
|
||||
password: "testpassword123"
|
||||
})
|
||||
|> Ash.create()
|
||||
|
||||
conn = log_in_user(build_conn(), user)
|
||||
%{conn: conn, user: user}
|
||||
end
|
||||
|
||||
# Helper to create a membership fee type
|
||||
defp create_fee_type(attrs) do
|
||||
default_attrs = %{
|
||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
||||
amount: Decimal.new("50.00"),
|
||||
interval: :yearly
|
||||
}
|
||||
|
||||
attrs = Map.merge(default_attrs, attrs)
|
||||
|
||||
MembershipFeeType
|
||||
|> Ash.Changeset.for_create(:create, attrs)
|
||||
|> Ash.create!()
|
||||
end
|
||||
|
||||
# Helper to create a member
|
||||
defp create_member(attrs) do
|
||||
default_attrs = %{
|
||||
first_name: "Test",
|
||||
last_name: "Member",
|
||||
email: "test.member.#{System.unique_integer([:positive])}@example.com"
|
||||
}
|
||||
|
||||
attrs = Map.merge(default_attrs, attrs)
|
||||
|
||||
Member
|
||||
|> Ash.Changeset.for_create(:create_member, attrs)
|
||||
|> Ash.create!()
|
||||
end
|
||||
|
||||
describe "end-to-end workflows" do
|
||||
test "create type → assign to member → view cycles → change status", %{conn: conn} do
|
||||
# Create type
|
||||
fee_type = create_fee_type(%{name: "Regular", interval: :yearly})
|
||||
|
||||
# Assign to member
|
||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
|
||||
# View cycles
|
||||
{:ok, view, html} = live(conn, "/members/#{member.id}")
|
||||
|
||||
assert html =~ "Membership Fees" || html =~ "Mitgliedsbeiträge"
|
||||
|
||||
# Get a cycle
|
||||
cycles =
|
||||
MembershipFeeCycle
|
||||
|> Ash.Query.filter(member_id == ^member.id)
|
||||
|> Ash.read!()
|
||||
|
||||
if length(cycles) > 0 do
|
||||
cycle = List.first(cycles)
|
||||
|
||||
# Change status
|
||||
view
|
||||
|> element("button[phx-click='mark_as_paid'][phx-value-cycle-id='#{cycle.id}']")
|
||||
|> render_click()
|
||||
|
||||
# Verify status changed
|
||||
updated_cycle = Ash.read_one!(MembershipFeeCycle |> Ash.Query.filter(id == ^cycle.id))
|
||||
assert updated_cycle.status == :paid
|
||||
end
|
||||
end
|
||||
|
||||
test "change member type → cycles regenerate", %{conn: conn} do
|
||||
fee_type1 =
|
||||
create_fee_type(%{name: "Type 1", interval: :yearly, amount: Decimal.new("50.00")})
|
||||
|
||||
fee_type2 =
|
||||
create_fee_type(%{name: "Type 2", interval: :yearly, amount: Decimal.new("75.00")})
|
||||
|
||||
member = create_member(%{membership_fee_type_id: fee_type1.id})
|
||||
|
||||
# Change type
|
||||
{:ok, view, _html} = live(conn, "/members/#{member.id}/edit")
|
||||
|
||||
view
|
||||
|> form("form", %{"member[membership_fee_type_id]" => fee_type2.id})
|
||||
|> render_submit()
|
||||
|
||||
# Verify cycles regenerated with new amount
|
||||
cycles =
|
||||
MembershipFeeCycle
|
||||
|> Ash.Query.filter(member_id == ^member.id)
|
||||
|> Ash.Query.filter(status == :unpaid)
|
||||
|> Ash.read!()
|
||||
|
||||
# Future unpaid cycles should have new amount
|
||||
Enum.each(cycles, fn cycle ->
|
||||
if Date.compare(cycle.cycle_start, Date.utc_today()) != :lt do
|
||||
assert Decimal.equal?(cycle.amount, fee_type2.amount)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
test "update settings → new members get default type", %{conn: conn} do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
|
||||
# Update settings
|
||||
Mv.Membership.Setting
|
||||
|> Ash.Changeset.for_update(:update_membership_fee_settings, %{
|
||||
default_membership_fee_type_id: fee_type.id
|
||||
})
|
||||
|> Ash.update!()
|
||||
|
||||
# Create new member
|
||||
{:ok, view, _html} = live(conn, "/members/new")
|
||||
|
||||
form_data = %{
|
||||
"member[first_name]" => "New",
|
||||
"member[last_name]" => "Member",
|
||||
"member[email]" => "new#{System.unique_integer([:positive])}@example.com"
|
||||
}
|
||||
|
||||
{:error, {:live_redirect, %{to: _to}}} =
|
||||
view
|
||||
|> form("form", form_data)
|
||||
|> render_submit()
|
||||
|
||||
# Verify member got default type
|
||||
member =
|
||||
Member
|
||||
|> Ash.Query.filter(email == ^form_data["member[email]"])
|
||||
|> Ash.read_one!()
|
||||
|
||||
assert member.membership_fee_type_id == fee_type.id
|
||||
end
|
||||
|
||||
test "delete cycle → confirmation → cycle deleted", %{conn: conn} do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
|
||||
cycle =
|
||||
MembershipFeeCycle
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
cycle_start: ~D[2023-01-01],
|
||||
amount: Decimal.new("50.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id,
|
||||
status: :unpaid
|
||||
})
|
||||
|> Ash.create!()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||
|
||||
# Delete cycle with confirmation
|
||||
view
|
||||
|> element("button[phx-click='delete_cycle'][phx-value-cycle-id='#{cycle.id}']")
|
||||
|> render_click()
|
||||
|
||||
# Confirm deletion
|
||||
view
|
||||
|> element("button[phx-click='confirm_delete_cycle'][phx-value-cycle-id='#{cycle.id}']")
|
||||
|> render_click()
|
||||
|
||||
# Verify cycle deleted
|
||||
assert_raise Ash.Error.Query.NotFound, fn ->
|
||||
Ash.read_one!(MembershipFeeCycle |> Ash.Query.filter(id == ^cycle.id))
|
||||
end
|
||||
end
|
||||
|
||||
test "edit cycle amount → modal → amount updated", %{conn: conn} do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
||||
|
||||
cycle =
|
||||
MembershipFeeCycle
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
cycle_start: ~D[2023-01-01],
|
||||
amount: Decimal.new("50.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id,
|
||||
status: :unpaid
|
||||
})
|
||||
|> Ash.create!()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||
|
||||
# Open edit modal
|
||||
view
|
||||
|> element("button[phx-click='edit_cycle_amount'][phx-value-cycle-id='#{cycle.id}']")
|
||||
|> render_click()
|
||||
|
||||
# Update amount
|
||||
view
|
||||
|> form("form", %{"amount" => "75.00"})
|
||||
|> render_submit()
|
||||
|
||||
# Verify amount updated
|
||||
updated_cycle = Ash.read_one!(MembershipFeeCycle |> Ash.Query.filter(id == ^cycle.id))
|
||||
assert updated_cycle.amount == Decimal.new("75.00")
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue