test: Add role tag support to ConnCase and fix test issues

- Add role tag support (@tag role: :admin/:member/:unauthenticated) to ConnCase
- Fix Keyword.get -> Map.get for tags Map
- Remove duplicate test file index_display_name_test.exs
- Fix CustomField creation in tests (remove slug, use :string instead of :text)
- Fix CustomFieldValue value format to use _union_type/_union_value
This commit is contained in:
Moritz 2026-01-13 14:05:36 +01:00
parent 351eac4c02
commit 970c749a92
Signed by: moritz
GPG key ID: 1020A035E5DD0824
2 changed files with 179 additions and 5 deletions

View file

@ -150,4 +150,153 @@ defmodule MvWeb.MemberLive.FormMembershipFeeTypeTest do
assert html =~ fee_type.name || html =~ "selected"
end
end
describe "custom field value preservation" do
test "custom field values preserved when membership fee type changes", %{
conn: conn,
current_user: admin_user
} do
# Create custom field
custom_field =
Mv.Membership.CustomField
|> Ash.Changeset.for_create(:create, %{
name: "Test Field",
value_type: :string,
required: false
})
|> Ash.create!()
# Create two fee types with same interval
fee_type1 = create_fee_type(%{name: "Type 1", interval: :yearly})
fee_type2 = create_fee_type(%{name: "Type 2", interval: :yearly})
# Create member with fee type 1 and custom field value
member =
Member
|> Ash.Changeset.for_create(:create_member, %{
first_name: "Test",
last_name: "Member",
email: "test#{System.unique_integer([:positive])}@example.com",
membership_fee_type_id: fee_type1.id
})
|> Ash.create!(actor: admin_user)
# Add custom field value
Mv.Membership.CustomFieldValue
|> Ash.Changeset.for_create(:create, %{
member_id: member.id,
custom_field_id: custom_field.id,
value: %{"_union_type" => "string", "_union_value" => "Test Value"}
})
|> Ash.create!(actor: admin_user)
{:ok, view, _html} = live(conn, "/members/#{member.id}/edit")
# Change membership fee type dropdown
html =
view
|> form("#member-form", %{"member[membership_fee_type_id]" => fee_type2.id})
|> render_change()
# Verify custom field value is still present (check for field name or value)
assert html =~ custom_field.name || html =~ "Test Value"
end
test "union/typed values roundtrip correctly", %{conn: conn, current_user: admin_user} do
# Create date custom field
custom_field =
Mv.Membership.CustomField
|> Ash.Changeset.for_create(:create, %{
name: "Date Field",
value_type: :date,
required: false
})
|> Ash.create!()
fee_type = create_fee_type(%{interval: :yearly})
# Create member with date custom field value
member =
Member
|> Ash.Changeset.for_create(:create_member, %{
first_name: "Test",
last_name: "Member",
email: "test#{System.unique_integer([:positive])}@example.com",
membership_fee_type_id: fee_type.id
})
|> Ash.create!(actor: admin_user)
test_date = ~D[2024-01-15]
# Add date custom field value
Mv.Membership.CustomFieldValue
|> Ash.Changeset.for_create(:create, %{
member_id: member.id,
custom_field_id: custom_field.id,
value: %{"_union_type" => "date", "_union_value" => test_date}
})
|> Ash.create!(actor: admin_user)
{:ok, view, _html} = live(conn, "/members/#{member.id}/edit")
# Trigger validation (simulates dropdown change)
html =
view
|> form("#member-form", %{"member[membership_fee_type_id]" => fee_type.id})
|> render_change()
# Verify date value is still present (check for date input or formatted date)
assert html =~ "2024" || html =~ "date"
end
test "removing custom field values works correctly", %{conn: conn, current_user: admin_user} do
# Create custom field
custom_field =
Mv.Membership.CustomField
|> Ash.Changeset.for_create(:create, %{
name: "Test Field",
value_type: :string,
required: false
})
|> Ash.create!()
fee_type = create_fee_type(%{interval: :yearly})
# Create member with custom field value
member =
Member
|> Ash.Changeset.for_create(:create_member, %{
first_name: "Test",
last_name: "Member",
email: "test#{System.unique_integer([:positive])}@example.com",
membership_fee_type_id: fee_type.id
})
|> Ash.create!(actor: admin_user)
# Add custom field value
_cfv =
Mv.Membership.CustomFieldValue
|> Ash.Changeset.for_create(:create, %{
member_id: member.id,
custom_field_id: custom_field.id,
value: %{"_union_type" => "string", "_union_value" => "Test Value"}
})
|> Ash.create!(actor: admin_user)
{:ok, view, _html} = live(conn, "/members/#{member.id}/edit")
# Change membership fee type to trigger validation
# This should preserve the custom field value
html =
view
|> form("#member-form", %{
"member[membership_fee_type_id]" => fee_type.id
})
|> render_change()
# Form should still be valid and custom field value should be preserved
# The custom field value should still be visible in the form
assert html =~ "Test Value" || html =~ custom_field.name
end
end
end

View file

@ -154,11 +154,36 @@ defmodule MvWeb.ConnCase do
# to share the test's database connection in async tests
conn = Plug.Conn.put_private(conn, :ecto_sandbox, pid)
# Create admin user with role for all tests (unless test overrides with its own user)
# This ensures all tests have an authenticated user with proper authorization
admin_user = Mv.Fixtures.user_with_role_fixture("admin")
authenticated_conn = conn_with_password_user(conn, admin_user)
# Handle role tags for future test extensions
# Default to admin to maintain backward compatibility with existing tests
role = Map.get(tags, :role, :admin)
{:ok, conn: authenticated_conn, current_user: admin_user}
{conn, user} =
case role do
:admin ->
# Create admin user with role for all tests (unless test overrides with its own user)
# This ensures all tests have an authenticated user with proper authorization
admin_user = Mv.Fixtures.user_with_role_fixture("admin")
authenticated_conn = conn_with_password_user(conn, admin_user)
{authenticated_conn, admin_user}
:member ->
# Create member user for role-based testing
member_user = Mv.Fixtures.user_with_role_fixture("member")
authenticated_conn = conn_with_password_user(conn, member_user)
{authenticated_conn, member_user}
:unauthenticated ->
# No authentication for unauthenticated tests
{conn, nil}
_other ->
# Fallback: treat unknown role as admin for safety
admin_user = Mv.Fixtures.user_with_role_fixture("admin")
authenticated_conn = conn_with_password_user(conn, admin_user)
{authenticated_conn, admin_user}
end
{:ok, conn: conn, current_user: user}
end
end