mitgliederverwaltung/test/membership/member_test.exs
Moritz e9ed61a8fd
Tests: restore settings in on_exit to avoid leftover state
Setup + on_exit save/restore member_field_visibility and
member_field_required in member, setting, index_component and
form_error_handling tests.
2026-02-23 22:51:18 +01:00

182 lines
5.7 KiB
Elixir

defmodule Mv.Membership.MemberTest do
use Mv.DataCase, async: false
alias Mv.Membership
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
%{actor: system_actor}
end
describe "Fields and Validations" do
@valid_attrs %{
first_name: "John",
last_name: "Doe",
email: "john@example.com",
join_date: ~D[2020-01-01],
exit_date: nil,
notes: "Test note",
city: "Berlin",
street: "Main Street",
house_number: "1A",
postal_code: "12345"
}
test "First name is optional", %{actor: actor} do
attrs = Map.delete(@valid_attrs, :first_name)
assert {:ok, _member} = Membership.create_member(attrs, actor: actor)
end
test "Last name is optional", %{actor: actor} do
attrs = Map.delete(@valid_attrs, :last_name)
assert {:ok, _member} = Membership.create_member(attrs, actor: actor)
end
test "Email is required", %{actor: actor} do
attrs = Map.put(@valid_attrs, :email, "")
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Membership.create_member(attrs, actor: actor)
assert error_message(errors, :email) =~ "must be present"
end
test "Email must be valid", %{actor: actor} do
attrs = Map.put(@valid_attrs, :email, "test@")
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Membership.create_member(attrs, actor: actor)
assert error_message(errors, :email) =~ "is not a valid email"
end
test "Join date cannot be in the future", %{actor: actor} do
attrs = Map.put(@valid_attrs, :join_date, Date.utc_today() |> Date.add(1))
assert {:error,
%Ash.Error.Invalid{errors: [%Ash.Error.Changes.InvalidAttribute{field: :join_date}]}} =
Membership.create_member(attrs, actor: actor)
end
test "Exit date is optional but must not be before join date if both are specified", %{
actor: actor
} do
attrs = Map.put(@valid_attrs, :exit_date, ~D[2010-01-01])
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Membership.create_member(attrs, actor: actor)
assert error_message(errors, :exit_date) =~ "cannot be before join date"
attrs2 = Map.delete(@valid_attrs, :exit_date)
assert {:ok, _member} = Membership.create_member(attrs2, actor: actor)
end
test "Notes is optional", %{actor: actor} do
attrs = Map.delete(@valid_attrs, :notes)
assert {:ok, _member} = Membership.create_member(attrs, actor: actor)
end
test "City, street, house number are optional", %{actor: actor} do
attrs = @valid_attrs |> Map.drop([:city, :street, :house_number])
assert {:ok, _member} = Membership.create_member(attrs, actor: actor)
end
test "Postal code is optional but must have 5 digits if specified", %{actor: actor} do
attrs = Map.put(@valid_attrs, :postal_code, "1234")
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Membership.create_member(attrs, actor: actor)
assert error_message(errors, :postal_code) =~ "must consist of 5 digits"
attrs2 = Map.delete(@valid_attrs, :postal_code)
assert {:ok, _member} = Membership.create_member(attrs2, actor: actor)
end
end
describe "Settings-driven required fields" do
@valid_attrs %{
first_name: "John",
last_name: "Doe",
email: "john@example.com"
}
setup do
{:ok, settings} = Membership.get_settings()
saved_visibility = settings.member_field_visibility || %{}
saved_required = settings.member_field_required || %{}
on_exit(fn ->
{:ok, s} = Membership.get_settings()
Membership.update_settings(s, %{
member_field_visibility: saved_visibility,
member_field_required: saved_required
})
end)
:ok
end
test "when first_name is required in settings, create without first_name fails", %{
actor: actor
} do
{:ok, settings} = Membership.get_settings()
{:ok, _} =
Membership.update_single_member_field(settings,
field: "first_name",
show_in_overview: true,
required: true
)
attrs = Map.delete(@valid_attrs, :first_name)
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Membership.create_member(attrs, actor: actor)
assert error_message(errors, :first_name) =~ "can't be blank"
end
test "when first_name is required in settings, create with first_name succeeds", %{
actor: actor
} do
{:ok, settings} = Membership.get_settings()
{:ok, _} =
Membership.update_single_member_field(settings,
field: "first_name",
show_in_overview: true,
required: true
)
assert {:ok, _member} = Membership.create_member(@valid_attrs, actor: actor)
end
end
describe "Authorization" do
@valid_attrs %{
first_name: "John",
last_name: "Doe",
email: "john@example.com"
}
test "user without role cannot create member" do
# Create a user without a role
user = Mv.Fixtures.user_fixture()
# Ensure user has no role (nil role)
user_without_role = %{user | role: nil}
# Attempt to create a member with user without role as actor
# This should fail with Ash.Error.Forbidden containing a Policy error
assert {:error, %Ash.Error.Forbidden{errors: [%Ash.Error.Forbidden.Policy{}]}} =
Membership.create_member(@valid_attrs, actor: user_without_role)
end
end
# Helper function for error evaluation
defp error_message(errors, field) do
errors
|> Enum.filter(fn err -> Map.get(err, :field) == field end)
|> Enum.map(&Map.get(&1, :message, ""))
|> List.first()
end
end