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