defmodule Mv.Membership.MemberTest do use Mv.DataCase, async: false alias Mv.Membership describe "Fields and Validations" do @valid_attrs %{ first_name: "John", last_name: "Doe", birth_date: ~D[1990-01-01], paid: true, email: "john@example.com", phone_number: "+49123456789", 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 required and must not be empty" do attrs = Map.put(@valid_attrs, :first_name, "") assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs) assert error_message(errors, :first_name) =~ "must be present" end test "Last name is required and must not be empty" do attrs = Map.put(@valid_attrs, :last_name, "") assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs) assert error_message(errors, :last_name) =~ "must be present" end test "Email is required" do attrs = Map.put(@valid_attrs, :email, "") assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs) assert error_message(errors, :email) =~ "must be present" end test "Email must be valid" do attrs = Map.put(@valid_attrs, :email, "test@") assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs) assert error_message(errors, :email) =~ "is not a valid email" end test "Birth date is optional but must not be in the future" do attrs = Map.put(@valid_attrs, :birth_date, Date.utc_today() |> Date.add(1)) assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs) assert error_message(errors, :birth_date) =~ "cannot be in the future" end test "Paid is optional but must be boolean if specified" do attrs = Map.put(@valid_attrs, :paid, nil) attrs2 = Map.put(@valid_attrs, :paid, "yes") assert {:ok, _member} = Membership.create_member(Map.delete(attrs, :paid)) assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs2) assert error_message(errors, :paid) =~ "is invalid" end test "Phone number is optional but must have a valid format if specified" do attrs = Map.put(@valid_attrs, :phone_number, "abc") assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs) assert error_message(errors, :phone_number) =~ "is not a valid phone number" attrs2 = Map.delete(@valid_attrs, :phone_number) assert {:ok, _member} = Membership.create_member(attrs2) end test "Join date is optional but must not be in the future" do attrs = Map.put(@valid_attrs, :join_date, Date.utc_today() |> Date.add(1)) assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs) assert error_message(errors, :join_date) =~ "cannot be in the future" attrs2 = Map.delete(@valid_attrs, :join_date) assert {:ok, _member} = Membership.create_member(attrs2) end test "Exit date is optional but must not be before join date if both are specified" do attrs = Map.put(@valid_attrs, :exit_date, ~D[2010-01-01]) assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs) 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) end test "Notes is optional" do attrs = Map.delete(@valid_attrs, :notes) assert {:ok, _member} = Membership.create_member(attrs) end test "City, street, house number are optional" do attrs = @valid_attrs |> Map.drop([:city, :street, :house_number]) assert {:ok, _member} = Membership.create_member(attrs) end test "Postal code is optional but must have 5 digits if specified" do attrs = Map.put(@valid_attrs, :postal_code, "1234") assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs) 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) 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