fix: add validation for required custom fields
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
carla 2025-12-17 13:31:15 +01:00
parent 894b9b9d5c
commit bbc094daaa
3 changed files with 519 additions and 0 deletions

View file

@ -0,0 +1,447 @@
defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
@moduledoc """
Tests for required custom fields validation.
Tests cover:
- Member creation without required custom field error
- Member creation with empty required custom field (nil/empty string) error
- Member creation with valid required custom field success
- Member update: removing a required custom field value error
- Boolean required custom field: false is valid, nil is invalid
"""
use Mv.DataCase, async: true
alias Mv.Membership
setup do
# Create required custom fields for different types
{:ok, required_string_field} =
Membership.CustomField
|> Ash.Changeset.for_create(:create, %{
name: "required_string",
value_type: :string,
required: true
})
|> Ash.create()
{:ok, required_integer_field} =
Membership.CustomField
|> Ash.Changeset.for_create(:create, %{
name: "required_integer",
value_type: :integer,
required: true
})
|> Ash.create()
{:ok, required_boolean_field} =
Membership.CustomField
|> Ash.Changeset.for_create(:create, %{
name: "required_boolean",
value_type: :boolean,
required: true
})
|> Ash.create()
{:ok, required_date_field} =
Membership.CustomField
|> Ash.Changeset.for_create(:create, %{
name: "required_date",
value_type: :date,
required: true
})
|> Ash.create()
{:ok, optional_field} =
Membership.CustomField
|> Ash.Changeset.for_create(:create, %{
name: "optional_string",
value_type: :string,
required: false
})
|> Ash.create()
%{
required_string_field: required_string_field,
required_integer_field: required_integer_field,
required_boolean_field: required_boolean_field,
required_date_field: required_date_field,
optional_field: optional_field
}
end
describe "create_member with required custom fields" do
@valid_attrs %{
first_name: "John",
last_name: "Doe",
email: "john@example.com"
}
test "fails when required custom field is missing", %{required_string_field: field} do
attrs = Map.put(@valid_attrs, :custom_field_values, [])
assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs)
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ field.name
end
test "fails when required string custom field has nil value", %{
required_string_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => nil}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs)
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ field.name
end
test "fails when required string custom field has empty string value", %{
required_string_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => ""}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs)
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ field.name
end
test "fails when required string custom field has whitespace-only value", %{
required_string_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => " "}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs)
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ field.name
end
test "succeeds when required string custom field has valid value", %{
required_string_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => "test value"}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs)
end
test "fails when required integer custom field has nil value", %{
required_integer_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "integer", "value" => nil}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs)
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ field.name
end
test "succeeds when required integer custom field has zero value", %{
required_integer_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "integer", "value" => 0}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs)
end
test "succeeds when required integer custom field has positive value", %{
required_integer_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "integer", "value" => 42}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs)
end
test "fails when required boolean custom field has nil value", %{
required_boolean_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "boolean", "value" => nil}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs)
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ field.name
end
test "succeeds when required boolean custom field has false value", %{
required_boolean_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "boolean", "value" => false}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs)
end
test "succeeds when required boolean custom field has true value", %{
required_boolean_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "boolean", "value" => true}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs)
end
test "fails when required date custom field has nil value", %{
required_date_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "date", "value" => nil}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs)
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ field.name
end
test "succeeds when required date custom field has valid date value", %{
required_date_field: field
} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "date", "value" => ~D[2020-01-01]}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs)
end
test "succeeds when multiple required custom fields are provided", %{
required_string_field: string_field,
required_integer_field: integer_field,
required_boolean_field: boolean_field
} do
custom_field_values = [
%{
"custom_field_id" => string_field.id,
"value" => %{"type" => "string", "value" => "test"}
},
%{
"custom_field_id" => integer_field.id,
"value" => %{"type" => "integer", "value" => 42}
},
%{
"custom_field_id" => boolean_field.id,
"value" => %{"type" => "boolean", "value" => true}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs)
end
test "fails when one of multiple required custom fields is missing", %{
required_string_field: string_field,
required_integer_field: integer_field
} do
custom_field_values = [
%{
"custom_field_id" => string_field.id,
"value" => %{"type" => "string", "value" => "test"}
}
# Missing required_integer_field
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:error, %Ash.Error.Invalid{errors: errors}} = Membership.create_member(attrs)
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ integer_field.name
end
test "succeeds when optional custom field is missing", %{optional_field: field} do
attrs = Map.put(@valid_attrs, :custom_field_values, [])
assert {:ok, _member} = Membership.create_member(attrs)
end
test "succeeds when optional custom field has nil value", %{optional_field: field} do
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => nil}
}
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs)
end
end
describe "update_member with required custom fields" do
test "fails when removing a required custom field value", %{
required_string_field: field
} do
# Create member with required custom field
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => "test"}
}
]
{:ok, member} =
Membership.create_member(%{
first_name: "John",
last_name: "Doe",
email: "john@example.com",
custom_field_values: custom_field_values
})
# Try to update without the required custom field
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Membership.update_member(member, %{custom_field_values: []})
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ field.name
end
test "fails when setting required custom field value to empty", %{
required_string_field: field
} do
# Create member with required custom field
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => "test"}
}
]
{:ok, member} =
Membership.create_member(%{
first_name: "John",
last_name: "Doe",
email: "john@example.com",
custom_field_values: custom_field_values
})
# Try to update with empty value
updated_custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => ""}
}
]
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Membership.update_member(member, %{
custom_field_values: updated_custom_field_values
})
assert error_message(errors, :custom_field_values) =~ "Required custom fields missing"
assert error_message(errors, :custom_field_values) =~ field.name
end
test "succeeds when updating required custom field to valid value", %{
required_string_field: field
} do
# Create member with required custom field
custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => "old value"}
}
]
{:ok, member} =
Membership.create_member(%{
first_name: "John",
last_name: "Doe",
email: "john@example.com",
custom_field_values: custom_field_values
})
# Update with new valid value
updated_custom_field_values = [
%{
"custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => "new value"}
}
]
assert {:ok, _updated_member} =
Membership.update_member(member, %{
custom_field_values: updated_custom_field_values
})
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_join(" ", &Map.get(&1, :message, ""))
end
end