diff --git a/test/mv/membership/member_export_build_test.exs b/test/mv/membership/member_export_build_test.exs deleted file mode 100644 index 8b13789..0000000 --- a/test/mv/membership/member_export_build_test.exs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/mv/membership/members_pdf_test.exs b/test/mv/membership/members_pdf_test.exs deleted file mode 100644 index 8b13789..0000000 --- a/test/mv/membership/members_pdf_test.exs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/mv_web/member_live/index_test.exs b/test/mv_web/member_live/index_test.exs index 7642067..686a8e8 100644 --- a/test/mv_web/member_live/index_test.exs +++ b/test/mv_web/member_live/index_test.exs @@ -3,8 +3,13 @@ defmodule MvWeb.MemberLive.IndexTest do import Phoenix.LiveViewTest require Ash.Query + alias Mv.Helpers.SystemActor + alias Mv.Membership + alias Mv.Membership.CustomField + alias Mv.Membership.CustomFieldValue alias Mv.MembershipFees.MembershipFeeCycle alias Mv.MembershipFees.MembershipFeeType + alias MvWeb.MemberLive.Index, as: MemberIndex # Helper to create a membership fee type (shared across all tests) defp create_fee_type(attrs, actor) do @@ -298,10 +303,10 @@ defmodule MvWeb.MemberLive.IndexTest do @tag :ui test "member index does not render Edit or Delete actions", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() {:ok, _member} = - Mv.Membership.create_member( + Membership.create_member( %{first_name: "Test", last_name: "User", email: "test@example.com"}, actor: system_actor ) @@ -315,10 +320,10 @@ defmodule MvWeb.MemberLive.IndexTest do @tag :ui test "row click navigates to member show", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() {:ok, member} = - Mv.Membership.create_member( + Membership.create_member( %{first_name: "Row", last_name: "Click", email: "rowclick@example.com"}, actor: system_actor ) @@ -338,10 +343,10 @@ defmodule MvWeb.MemberLive.IndexTest do @describetag :ui test "clickable rows have hover and focus-within ring classes", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() {:ok, _member} = - Mv.Membership.create_member( + Membership.create_member( %{first_name: "Hover", last_name: "Test", email: "hover@example.com"}, actor: system_actor ) @@ -356,10 +361,10 @@ defmodule MvWeb.MemberLive.IndexTest do end test "selected outline only from checkbox selection, not from highlight param", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() {:ok, member} = - Mv.Membership.create_member( + Membership.create_member( %{first_name: "Highlight", last_name: "Only", email: "highlight@example.com"}, actor: system_actor ) @@ -374,11 +379,11 @@ defmodule MvWeb.MemberLive.IndexTest do describe "copy_emails feature" do setup do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() # Create test members {:ok, member1} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "Max", last_name: "Mustermann", @@ -388,7 +393,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, member2} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "Erika", last_name: "Musterfrau", @@ -398,7 +403,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, member3} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "Hans", last_name: "Müller-Lüdenscheidt", @@ -485,7 +490,7 @@ defmodule MvWeb.MemberLive.IndexTest do render_click(view, "select_member", %{"id" => member1.id}) # Delete the member from the database - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() Ash.destroy!(member1, actor: system_actor) # Trigger copy_emails event directly - selection still contains the deleted ID @@ -526,10 +531,10 @@ defmodule MvWeb.MemberLive.IndexTest do conn = conn_with_oidc_user(conn) # Create a member with known data - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() {:ok, test_member} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "Test", last_name: "Format", @@ -598,10 +603,10 @@ defmodule MvWeb.MemberLive.IndexTest do describe "export dropdown" do setup do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() {:ok, m1} = - Mv.Membership.create_member( + Membership.create_member( %{first_name: "Export", last_name: "One", email: "export1@example.com"}, actor: system_actor ) @@ -755,12 +760,12 @@ defmodule MvWeb.MemberLive.IndexTest do } attrs = Map.merge(default_attrs, attrs) - {:ok, member} = Mv.Membership.create_member(attrs, actor: actor) + {:ok, member} = Membership.create_member(attrs, actor: actor) member end test "filter shows only members with paid status in last cycle", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() conn = conn_with_oidc_user(conn) fee_type = create_fee_type(%{interval: :yearly}, system_actor) today = Date.utc_today() @@ -807,7 +812,7 @@ defmodule MvWeb.MemberLive.IndexTest do end test "filter shows only members with unpaid status in last cycle", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() conn = conn_with_oidc_user(conn) fee_type = create_fee_type(%{interval: :yearly}, system_actor) today = Date.utc_today() @@ -854,7 +859,7 @@ defmodule MvWeb.MemberLive.IndexTest do end test "filter shows only members with paid status in current cycle", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() conn = conn_with_oidc_user(conn) fee_type = create_fee_type(%{interval: :yearly}, system_actor) today = Date.utc_today() @@ -901,7 +906,7 @@ defmodule MvWeb.MemberLive.IndexTest do end test "filter shows only members with unpaid status in current cycle", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() conn = conn_with_oidc_user(conn) fee_type = create_fee_type(%{interval: :yearly}, system_actor) today = Date.utc_today() @@ -970,11 +975,9 @@ defmodule MvWeb.MemberLive.IndexTest do end describe "boolean custom field filters" do - alias Mv.Membership.CustomField - # Helper to create a boolean custom field (uses system actor for authorization) defp create_boolean_custom_field(attrs \\ %{}) do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() default_attrs = %{ name: "test_boolean_#{System.unique_integer([:positive])}", @@ -990,7 +993,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Helper to create a non-boolean custom field (uses system actor for authorization) defp create_string_custom_field(attrs \\ %{}) do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() default_attrs = %{ name: "test_string_#{System.unique_integer([:positive])}", @@ -1244,7 +1247,7 @@ defmodule MvWeb.MemberLive.IndexTest do test "handle_params removes filter when custom field is deleted", %{conn: conn} do conn = conn_with_oidc_user(conn) - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field = create_boolean_custom_field() # Set up filter via URL @@ -1359,10 +1362,10 @@ defmodule MvWeb.MemberLive.IndexTest do } |> Map.merge(member_attrs) - {:ok, member} = Mv.Membership.create_member(attrs, actor: actor) + {:ok, member} = Membership.create_member(attrs, actor: actor) {:ok, _cfv} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member.id, custom_field_id: custom_field.id, @@ -1377,33 +1380,33 @@ defmodule MvWeb.MemberLive.IndexTest do # 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 = Mv.Helpers.SystemActor.get_system_actor() + 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 = MvWeb.MemberLive.Index.get_boolean_custom_field_value(member, boolean_field) + 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 = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field = create_boolean_custom_field() member = create_member_with_boolean_value(%{}, boolean_field, false, system_actor) - result = MvWeb.MemberLive.Index.get_boolean_custom_field_value(member, boolean_field) + 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 = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field = create_boolean_custom_field() {:ok, member} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "Test", last_name: "Member", @@ -1414,7 +1417,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Create CustomFieldValue with map format (Ash expects _union_type and _union_value) {:ok, _cfv} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member.id, custom_field_id: boolean_field.id, @@ -1425,7 +1428,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Reload member with custom field values member = member |> Ash.load!(:custom_field_values, actor: system_actor) - result = MvWeb.MemberLive.Index.get_boolean_custom_field_value(member, boolean_field) + result = MemberIndex.get_boolean_custom_field_value(member, boolean_field) assert result == true end @@ -1433,11 +1436,11 @@ defmodule MvWeb.MemberLive.IndexTest do test "get_boolean_custom_field_value returns nil when no CustomFieldValue exists", %{ conn: _conn } do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field = create_boolean_custom_field() {:ok, member} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "Test", last_name: "Member", @@ -1449,7 +1452,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Member has no custom field value for this field member = member |> Ash.load!(:custom_field_values, actor: system_actor) - result = MvWeb.MemberLive.Index.get_boolean_custom_field_value(member, boolean_field) + result = MemberIndex.get_boolean_custom_field_value(member, boolean_field) assert result == nil end @@ -1457,11 +1460,11 @@ defmodule MvWeb.MemberLive.IndexTest do test "get_boolean_custom_field_value returns nil when CustomFieldValue has nil value", %{ conn: _conn } do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field = create_boolean_custom_field() {:ok, member} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "Test", last_name: "Member", @@ -1472,7 +1475,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Create CustomFieldValue with nil value (edge case) {:ok, _cfv} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member.id, custom_field_id: boolean_field.id, @@ -1482,7 +1485,7 @@ defmodule MvWeb.MemberLive.IndexTest do member = member |> Ash.load!(:custom_field_values, actor: system_actor) - result = MvWeb.MemberLive.Index.get_boolean_custom_field_value(member, boolean_field) + result = MemberIndex.get_boolean_custom_field_value(member, boolean_field) assert result == nil end @@ -1490,12 +1493,12 @@ defmodule MvWeb.MemberLive.IndexTest do test "get_boolean_custom_field_value returns nil for non-boolean CustomFieldValue", %{ conn: _conn } do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() string_field = create_string_custom_field() boolean_field = create_boolean_custom_field() {:ok, member} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "Test", last_name: "Member", @@ -1506,7 +1509,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Create string custom field value (not boolean) {:ok, _cfv} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member.id, custom_field_id: string_field.id, @@ -1517,7 +1520,7 @@ defmodule MvWeb.MemberLive.IndexTest do member = member |> Ash.load!(:custom_field_values, actor: system_actor) # Try to get boolean value from string field - should return nil - result = MvWeb.MemberLive.Index.get_boolean_custom_field_value(member, boolean_field) + result = MemberIndex.get_boolean_custom_field_value(member, boolean_field) assert result == nil end @@ -1525,7 +1528,7 @@ defmodule MvWeb.MemberLive.IndexTest do # 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 - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field = create_boolean_custom_field() member_with_true = @@ -1545,7 +1548,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, member_without_value} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "NoValue", last_name: "Member", @@ -1559,10 +1562,10 @@ defmodule MvWeb.MemberLive.IndexTest do members = [member_with_true, member_with_false, member_without_value] filters = %{to_string(boolean_field.id) => true} - all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor) + all_custom_fields = CustomField |> Ash.read!(actor: system_actor) result = - MvWeb.MemberLive.Index.apply_boolean_custom_field_filters( + MemberIndex.apply_boolean_custom_field_filters( members, filters, all_custom_fields @@ -1576,7 +1579,7 @@ defmodule MvWeb.MemberLive.IndexTest do test "apply_boolean_custom_field_filters filters members with false value and excludes true/without values", %{conn: _conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field = create_boolean_custom_field() member_with_true = @@ -1596,7 +1599,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, member_without_value} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "NoValue", last_name: "Member", @@ -1610,10 +1613,10 @@ defmodule MvWeb.MemberLive.IndexTest do members = [member_with_true, member_with_false, member_without_value] filters = %{to_string(boolean_field.id) => false} - all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor) + all_custom_fields = CustomField |> Ash.read!(actor: system_actor) result = - MvWeb.MemberLive.Index.apply_boolean_custom_field_filters( + MemberIndex.apply_boolean_custom_field_filters( members, filters, all_custom_fields @@ -1628,7 +1631,7 @@ defmodule MvWeb.MemberLive.IndexTest do test "apply_boolean_custom_field_filters returns all members when filter map is empty", %{ conn: _conn } do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field = create_boolean_custom_field() member1 = @@ -1649,10 +1652,10 @@ defmodule MvWeb.MemberLive.IndexTest do members = [member1, member2] filters = %{} - all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor) + all_custom_fields = CustomField |> Ash.read!(actor: system_actor) result = - MvWeb.MemberLive.Index.apply_boolean_custom_field_filters( + MemberIndex.apply_boolean_custom_field_filters( members, filters, all_custom_fields @@ -1668,13 +1671,13 @@ defmodule MvWeb.MemberLive.IndexTest do test "apply_boolean_custom_field_filters applies multiple filters with AND logic", %{ conn: _conn } do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field1 = create_boolean_custom_field(%{name: "Field1"}) boolean_field2 = create_boolean_custom_field(%{name: "Field2"}) # Member with both fields = true {:ok, member_both_true} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "BothTrue", last_name: "Member", @@ -1684,7 +1687,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, _cfv1} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member_both_true.id, custom_field_id: boolean_field1.id, @@ -1693,7 +1696,7 @@ defmodule MvWeb.MemberLive.IndexTest do |> Ash.create(actor: system_actor) {:ok, _cfv2} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member_both_true.id, custom_field_id: boolean_field2.id, @@ -1705,7 +1708,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Member with field1 = true, field2 = false {:ok, member_mixed} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "Mixed", last_name: "Member", @@ -1715,7 +1718,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, _cfv3} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member_mixed.id, custom_field_id: boolean_field1.id, @@ -1724,7 +1727,7 @@ defmodule MvWeb.MemberLive.IndexTest do |> Ash.create(actor: system_actor) {:ok, _cfv4} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member_mixed.id, custom_field_id: boolean_field2.id, @@ -1741,10 +1744,10 @@ defmodule MvWeb.MemberLive.IndexTest do to_string(boolean_field2.id) => true } - all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor) + all_custom_fields = CustomField |> Ash.read!(actor: system_actor) result = - MvWeb.MemberLive.Index.apply_boolean_custom_field_filters( + MemberIndex.apply_boolean_custom_field_filters( members, filters, all_custom_fields @@ -1758,7 +1761,7 @@ defmodule MvWeb.MemberLive.IndexTest do test "apply_boolean_custom_field_filters ignores filter with non-existent custom field ID", %{ conn: _conn } do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() boolean_field = create_boolean_custom_field() fake_id = Ecto.UUID.generate() @@ -1772,10 +1775,10 @@ defmodule MvWeb.MemberLive.IndexTest do members = [member] filters = %{fake_id => true} - all_custom_fields = Mv.Membership.CustomField |> Ash.read!(actor: system_actor) + all_custom_fields = CustomField |> Ash.read!(actor: system_actor) result = - MvWeb.MemberLive.Index.apply_boolean_custom_field_filters( + MemberIndex.apply_boolean_custom_field_filters( members, filters, all_custom_fields @@ -1788,7 +1791,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Integration tests for boolean custom field filters in load_members test "boolean filter integration filters members by boolean custom field value via URL parameter", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() conn = conn_with_oidc_user(conn) boolean_field = create_boolean_custom_field() @@ -1809,7 +1812,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, _member_without_value} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "NoValue", last_name: "Member", @@ -1836,7 +1839,7 @@ defmodule MvWeb.MemberLive.IndexTest do end test "boolean filter integration works together with cycle_status_filter", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() conn = conn_with_oidc_user(conn) boolean_field = create_boolean_custom_field() fee_type = create_fee_type(%{interval: :yearly}, system_actor) @@ -1845,7 +1848,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Member with true boolean value and paid status {:ok, member_paid_true} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "PaidTrue", last_name: "Member", @@ -1856,7 +1859,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, _cfv} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member_paid_true.id, custom_field_id: boolean_field.id, @@ -1873,7 +1876,7 @@ defmodule MvWeb.MemberLive.IndexTest do # Member with true boolean value but unpaid status {:ok, member_unpaid_true} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "UnpaidTrue", last_name: "Member", @@ -1884,7 +1887,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, _cfv2} = - Mv.Membership.CustomFieldValue + CustomFieldValue |> Ash.Changeset.for_create(:create, %{ member_id: member_unpaid_true.id, custom_field_id: boolean_field.id, @@ -1909,7 +1912,7 @@ defmodule MvWeb.MemberLive.IndexTest do end test "boolean filter integration works together with search query", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() conn = conn_with_oidc_user(conn) boolean_field = create_boolean_custom_field() @@ -1939,7 +1942,7 @@ defmodule MvWeb.MemberLive.IndexTest do end test "boolean filter works even when custom field is not visible in overview", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() conn = conn_with_oidc_user(conn) # Create boolean field with show_in_overview: false @@ -1962,7 +1965,7 @@ defmodule MvWeb.MemberLive.IndexTest do ) {:ok, _member_without_value} = - Mv.Membership.create_member( + Membership.create_member( %{ first_name: "NoValue", last_name: "Member", @@ -2016,7 +2019,7 @@ defmodule MvWeb.MemberLive.IndexTest do @tag :slow test "boolean filter performance with 150 members", %{conn: conn} do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() conn = conn_with_oidc_user(conn) boolean_field = create_boolean_custom_field() diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index 89b6ab0..f924a55 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -17,6 +17,14 @@ defmodule MvWeb.ConnCase do use ExUnit.CaseTemplate + alias AshAuthentication.Plug.Helpers, as: AuthPlugHelpers + alias Mv.Accounts + alias Mv.Authorization.Actor + alias Mv.DataCase + alias Mv.Fixtures + alias Mv.Helpers.SystemActor + alias Phoenix.ConnTest + using do quote do # The default endpoint for testing @@ -92,8 +100,8 @@ defmodule MvWeb.ConnCase do def sign_in_user_via_oidc(conn, user) do # Mock OIDC sign-in by creating a token directly conn - |> Phoenix.ConnTest.init_test_session(%{}) - |> AshAuthentication.Plug.Helpers.store_in_session(user) + |> ConnTest.init_test_session(%{}) + |> AuthPlugHelpers.store_in_session(user) end @doc """ @@ -114,8 +122,8 @@ defmodule MvWeb.ConnCase do user = create_test_user(Map.merge(default_attrs, user_attrs)) # Create admin role and assign it - admin_role = Mv.Fixtures.role_fixture("admin") - system_actor = Mv.Helpers.SystemActor.get_system_actor() + admin_role = Fixtures.role_fixture("admin") + system_actor = SystemActor.get_system_actor() {:ok, user} = user @@ -124,7 +132,7 @@ defmodule MvWeb.ConnCase do |> Ash.update(actor: system_actor) # Load role for authorization - user_with_role = Ash.load!(user, :role, domain: Mv.Accounts, actor: system_actor) + user_with_role = Ash.load!(user, :role, domain: Accounts, actor: system_actor) sign_in_user_via_oidc(conn, user_with_role) end @@ -134,8 +142,8 @@ defmodule MvWeb.ConnCase do """ def conn_with_password_user(conn, user) do conn - |> Phoenix.ConnTest.init_test_session(%{}) - |> AshAuthentication.Plug.Helpers.store_in_session(user) + |> ConnTest.init_test_session(%{}) + |> AuthPlugHelpers.store_in_session(user) end @doc """ @@ -143,14 +151,14 @@ defmodule MvWeb.ConnCase do This is useful for tests that need full access to resources. """ def conn_with_admin_user(conn) do - admin_user = Mv.Fixtures.user_with_role_fixture("admin") + admin_user = Fixtures.user_with_role_fixture("admin") conn_with_password_user(conn, admin_user) end setup tags do - pid = Mv.DataCase.setup_sandbox(tags) + pid = DataCase.setup_sandbox(tags) - conn = Phoenix.ConnTest.build_conn() + conn = ConnTest.build_conn() # Set metadata for Phoenix.Ecto.SQL.Sandbox plug to allow LiveView processes # to share the test's database connection in async tests conn = Plug.Conn.put_private(conn, :ecto_sandbox, pid) @@ -164,27 +172,27 @@ defmodule MvWeb.ConnCase 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") + admin_user = 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" role uses "own_data" permission set (Mitglied role) - member_user = Mv.Fixtures.user_with_role_fixture("own_data") + member_user = Fixtures.user_with_role_fixture("own_data") authenticated_conn = conn_with_password_user(conn, member_user) {authenticated_conn, member_user} :read_only -> # Vorstand/Buchhaltung: can read members, groups; cannot edit or access admin/settings - read_only_user = Mv.Fixtures.user_with_role_fixture("read_only") - read_only_user = Mv.Authorization.Actor.ensure_loaded(read_only_user) + read_only_user = Fixtures.user_with_role_fixture("read_only") + read_only_user = Actor.ensure_loaded(read_only_user) authenticated_conn = conn_with_password_user(conn, read_only_user) {authenticated_conn, read_only_user} :normal_user -> # Kassenwart: can read/update members, groups; cannot access users/settings/admin - normal_user = Mv.Fixtures.user_with_role_fixture("normal_user") + normal_user = Fixtures.user_with_role_fixture("normal_user") authenticated_conn = conn_with_password_user(conn, normal_user) {authenticated_conn, normal_user} @@ -194,7 +202,7 @@ defmodule MvWeb.ConnCase do _other -> # Fallback: treat unknown role as admin for safety - admin_user = Mv.Fixtures.user_with_role_fixture("admin") + admin_user = Fixtures.user_with_role_fixture("admin") authenticated_conn = conn_with_password_user(conn, admin_user) {authenticated_conn, admin_user} end diff --git a/test/support/data_case.ex b/test/support/data_case.ex index 630125c..60bc0e1 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -16,6 +16,9 @@ defmodule Mv.DataCase do use ExUnit.CaseTemplate + alias Ecto.Adapters.SQL.Sandbox, as: Sandbox + alias Mv.Repo + require Ash.Query using do @@ -30,11 +33,11 @@ defmodule Mv.DataCase do end setup tags do - Mv.DataCase.setup_sandbox(tags) + setup_sandbox(tags) # Ensure "Mitglied" role exists for default role assignment to work in tests # Note: This runs in every test because each test runs in a sandboxed database. # The check is fast (single query) and idempotent (skips if role exists). - Mv.DataCase.ensure_default_role() + ensure_default_role() :ok end @@ -43,8 +46,8 @@ defmodule Mv.DataCase do Returns the owner pid for use with Phoenix.Ecto.SQL.Sandbox. """ def setup_sandbox(tags) do - pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Mv.Repo, shared: not tags[:async]) - on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) + pid = Sandbox.start_owner!(Repo, shared: not tags[:async]) + on_exit(fn -> Sandbox.stop_owner(pid) end) pid end diff --git a/test/support/fixtures.ex b/test/support/fixtures.ex index fd4166d..d7cddda 100644 --- a/test/support/fixtures.ex +++ b/test/support/fixtures.ex @@ -1,11 +1,13 @@ defmodule Mv.Fixtures do @moduledoc """ Shared test fixtures for consistent test data creation. - - This module provides factory functions for creating test data across - different test suites, ensuring consistency and reducing duplication. """ + alias Mv.Accounts + alias Mv.Authorization + alias Mv.Helpers.SystemActor + alias Mv.Membership + @doc """ Creates a member with default or custom attributes. @@ -27,7 +29,7 @@ defmodule Mv.Fixtures do """ def member_fixture(attrs \\ %{}) do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() attrs |> Enum.into(%{ @@ -35,7 +37,7 @@ defmodule Mv.Fixtures do last_name: "Member", email: "test#{System.unique_integer([:positive])}@example.com" }) - |> Mv.Membership.create_member(actor: system_actor) + |> Membership.create_member(actor: system_actor) |> case do {:ok, member} -> member {:error, error} -> raise "Failed to create member: #{inspect(error)}" @@ -66,13 +68,13 @@ defmodule Mv.Fixtures do """ def user_fixture(attrs \\ %{}) do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() attrs |> Enum.into(%{ email: "user#{System.unique_integer([:positive])}@example.com" }) - |> Mv.Accounts.create_user(actor: system_actor) + |> Accounts.create_user(actor: system_actor) |> case do {:ok, user} -> user {:error, error} -> raise "Failed to create user: #{inspect(error)}" @@ -123,10 +125,10 @@ defmodule Mv.Fixtures do """ def role_fixture(permission_set_name) do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() role_name = "Test Role #{permission_set_name} #{System.unique_integer([:positive])}" - case Mv.Authorization.create_role( + case Authorization.create_role( %{ name: role_name, description: "Test role for #{permission_set_name}", @@ -157,7 +159,7 @@ defmodule Mv.Fixtures do """ def user_with_role_fixture(permission_set_name \\ "admin", user_attrs \\ %{}) do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() # Create role with permission set role = role_fixture(permission_set_name) @@ -168,7 +170,7 @@ defmodule Mv.Fixtures do |> Enum.into(%{ email: "user#{System.unique_integer([:positive])}@example.com" }) - |> Mv.Accounts.create_user(actor: system_actor) + |> Accounts.create_user(actor: system_actor) # Assign role to user {:ok, user} = @@ -178,7 +180,7 @@ defmodule Mv.Fixtures do |> Ash.update(actor: system_actor) # Reload user with role preloaded (critical for authorization!) - {:ok, user_with_role} = Ash.load(user, :role, domain: Mv.Accounts, actor: system_actor) + {:ok, user_with_role} = Ash.load(user, :role, domain: Accounts, actor: system_actor) user_with_role end @@ -284,14 +286,14 @@ defmodule Mv.Fixtures do """ def group_fixture(attrs \\ %{}) do - system_actor = Mv.Helpers.SystemActor.get_system_actor() + system_actor = SystemActor.get_system_actor() attrs |> Enum.into(%{ name: "Test Group #{System.unique_integer([:positive])}", description: "Test description" }) - |> Mv.Membership.create_group(actor: system_actor) + |> Membership.create_group(actor: system_actor) |> case do {:ok, group} -> group {:error, error} -> raise "Failed to create group: #{inspect(error)}"