test: updated
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
carla 2025-12-17 14:34:10 +01:00
parent bbc094daaa
commit 6084827c73
2 changed files with 278 additions and 192 deletions

View file

@ -354,7 +354,15 @@ defmodule Mv.Membership.Member do
Enum.reduce(custom_field_values_arg, %{}, fn cfv, acc -> Enum.reduce(custom_field_values_arg, %{}, fn cfv, acc ->
custom_field_id = Map.get(cfv, "custom_field_id") custom_field_id = Map.get(cfv, "custom_field_id")
value_map = Map.get(cfv, "value", %{}) value_map = Map.get(cfv, "value", %{})
actual_value = Map.get(value_map, "value")
# Support both "value" and "_union_value" keys, without using || to preserve false values
actual_value =
cond do
Map.has_key?(value_map, "value") -> Map.get(value_map, "value")
Map.has_key?(value_map, "_union_value") -> Map.get(value_map, "_union_value")
true -> nil
end
Map.put(acc, custom_field_id, actual_value) Map.put(acc, custom_field_id, actual_value)
end) end)
end end

View file

@ -69,6 +69,33 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
} }
end end
# Helper function to create all required custom fields with valid default values
defp all_required_custom_fields_with_defaults(%{
required_string_field: string_field,
required_integer_field: integer_field,
required_boolean_field: boolean_field,
required_date_field: date_field
}) do
[
%{
"custom_field_id" => string_field.id,
"value" => %{"_union_type" => "string", "_union_value" => "default"}
},
%{
"custom_field_id" => integer_field.id,
"value" => %{"_union_type" => "integer", "_union_value" => 0}
},
%{
"custom_field_id" => boolean_field.id,
"value" => %{"_union_type" => "boolean", "_union_value" => false}
},
%{
"custom_field_id" => date_field.id,
"value" => %{"_union_type" => "date", "_union_value" => ~D[2020-01-01]}
}
]
end
describe "create_member with required custom fields" do describe "create_member with required custom fields" do
@valid_attrs %{ @valid_attrs %{
first_name: "John", first_name: "John",
@ -84,15 +111,20 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ field.name assert error_message(errors, :custom_field_values) =~ field.name
end end
test "fails when required string custom field has nil value", %{ test "fails when required string custom field has nil value",
required_string_field: field
} do
custom_field_values = [
%{ %{
"custom_field_id" => field.id, required_string_field: field
"value" => %{"type" => "string", "value" => nil} } = context do
} # Start with all required fields having valid values
] custom_field_values =
all_required_custom_fields_with_defaults(context)
|> Enum.map(fn cfv ->
if cfv["custom_field_id"] == field.id do
%{cfv | "value" => %{"_union_type" => "string", "_union_value" => nil}}
else
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
@ -101,15 +133,20 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ field.name assert error_message(errors, :custom_field_values) =~ field.name
end end
test "fails when required string custom field has empty string value", %{ test "fails when required string custom field has empty string value",
required_string_field: field
} do
custom_field_values = [
%{ %{
"custom_field_id" => field.id, required_string_field: field
"value" => %{"type" => "string", "value" => ""} } = context do
} # Start with all required fields having valid values
] custom_field_values =
all_required_custom_fields_with_defaults(context)
|> Enum.map(fn cfv ->
if cfv["custom_field_id"] == field.id do
%{cfv | "value" => %{"_union_type" => "string", "_union_value" => ""}}
else
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
@ -118,15 +155,20 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ field.name assert error_message(errors, :custom_field_values) =~ field.name
end end
test "fails when required string custom field has whitespace-only value", %{ test "fails when required string custom field has whitespace-only value",
required_string_field: field
} do
custom_field_values = [
%{ %{
"custom_field_id" => field.id, required_string_field: field
"value" => %{"type" => "string", "value" => " "} } = context do
} # Start with all required fields having valid values
] custom_field_values =
all_required_custom_fields_with_defaults(context)
|> Enum.map(fn cfv ->
if cfv["custom_field_id"] == field.id do
%{cfv | "value" => %{"_union_type" => "string", "_union_value" => " "}}
else
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
@ -135,30 +177,39 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ field.name assert error_message(errors, :custom_field_values) =~ field.name
end end
test "succeeds when required string custom field has valid value", %{ test "succeeds when required string custom field has valid value",
required_string_field: field
} do
custom_field_values = [
%{ %{
"custom_field_id" => field.id, required_string_field: field
"value" => %{"type" => "string", "value" => "test value"} } = context do
} # Start with all required fields having valid values, then update the string field
] custom_field_values =
all_required_custom_fields_with_defaults(context)
|> Enum.map(fn cfv ->
if cfv["custom_field_id"] == field.id do
%{cfv | "value" => %{"_union_type" => "string", "_union_value" => "test value"}}
else
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs) assert {:ok, _member} = Membership.create_member(attrs)
end end
test "fails when required integer custom field has nil value", %{ test "fails when required integer custom field has nil value",
%{
required_integer_field: field required_integer_field: field
} do } = context do
custom_field_values = [ custom_field_values =
%{ all_required_custom_fields_with_defaults(context)
"custom_field_id" => field.id, |> Enum.map(fn cfv ->
"value" => %{"type" => "integer", "value" => nil} if cfv["custom_field_id"] == field.id do
} %{cfv | "value" => %{"_union_type" => "integer", "_union_value" => nil}}
] else
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
@ -167,45 +218,49 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ field.name assert error_message(errors, :custom_field_values) =~ field.name
end end
test "succeeds when required integer custom field has zero value", %{ test "succeeds when required integer custom field has zero value",
required_integer_field: field
} do
custom_field_values = [
%{ %{
"custom_field_id" => field.id, required_integer_field: _field
"value" => %{"type" => "integer", "value" => 0} } = context do
} custom_field_values = all_required_custom_fields_with_defaults(context)
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs) assert {:ok, _member} = Membership.create_member(attrs)
end end
test "succeeds when required integer custom field has positive value", %{ test "succeeds when required integer custom field has positive value",
required_integer_field: field
} do
custom_field_values = [
%{ %{
"custom_field_id" => field.id, required_integer_field: field
"value" => %{"type" => "integer", "value" => 42} } = context do
} custom_field_values =
] all_required_custom_fields_with_defaults(context)
|> Enum.map(fn cfv ->
if cfv["custom_field_id"] == field.id do
%{cfv | "value" => %{"_union_type" => "integer", "_union_value" => 42}}
else
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs) assert {:ok, _member} = Membership.create_member(attrs)
end end
test "fails when required boolean custom field has nil value", %{ test "fails when required boolean custom field has nil value",
%{
required_boolean_field: field required_boolean_field: field
} do } = context do
custom_field_values = [ custom_field_values =
%{ all_required_custom_fields_with_defaults(context)
"custom_field_id" => field.id, |> Enum.map(fn cfv ->
"value" => %{"type" => "boolean", "value" => nil} if cfv["custom_field_id"] == field.id do
} %{cfv | "value" => %{"_union_type" => "boolean", "_union_value" => nil}}
] else
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
@ -214,45 +269,49 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ field.name assert error_message(errors, :custom_field_values) =~ field.name
end end
test "succeeds when required boolean custom field has false value", %{ test "succeeds when required boolean custom field has false value",
required_boolean_field: field
} do
custom_field_values = [
%{ %{
"custom_field_id" => field.id, required_boolean_field: _field
"value" => %{"type" => "boolean", "value" => false} } = context do
} custom_field_values = all_required_custom_fields_with_defaults(context)
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs) assert {:ok, _member} = Membership.create_member(attrs)
end end
test "succeeds when required boolean custom field has true value", %{ test "succeeds when required boolean custom field has true value",
required_boolean_field: field
} do
custom_field_values = [
%{ %{
"custom_field_id" => field.id, required_boolean_field: field
"value" => %{"type" => "boolean", "value" => true} } = context do
} custom_field_values =
] all_required_custom_fields_with_defaults(context)
|> Enum.map(fn cfv ->
if cfv["custom_field_id"] == field.id do
%{cfv | "value" => %{"_union_type" => "boolean", "_union_value" => true}}
else
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs) assert {:ok, _member} = Membership.create_member(attrs)
end end
test "fails when required date custom field has nil value", %{ test "fails when required date custom field has nil value",
%{
required_date_field: field required_date_field: field
} do } = context do
custom_field_values = [ custom_field_values =
%{ all_required_custom_fields_with_defaults(context)
"custom_field_id" => field.id, |> Enum.map(fn cfv ->
"value" => %{"type" => "date", "value" => nil} if cfv["custom_field_id"] == field.id do
} %{cfv | "value" => %{"_union_type" => "date", "_union_value" => nil}}
] else
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
@ -261,57 +320,60 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ field.name assert error_message(errors, :custom_field_values) =~ field.name
end end
test "succeeds when required date custom field has valid date value", %{ test "succeeds when required date custom field has valid date value",
required_date_field: field
} do
custom_field_values = [
%{ %{
"custom_field_id" => field.id, required_date_field: _field
"value" => %{"type" => "date", "value" => ~D[2020-01-01]} } = context do
} custom_field_values = all_required_custom_fields_with_defaults(context)
]
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs) assert {:ok, _member} = Membership.create_member(attrs)
end end
test "succeeds when multiple required custom fields are provided", %{ test "succeeds when multiple required custom fields are provided",
%{
required_string_field: string_field, required_string_field: string_field,
required_integer_field: integer_field, required_integer_field: integer_field,
required_boolean_field: boolean_field required_boolean_field: boolean_field
} do } = context do
custom_field_values = [ custom_field_values =
%{ all_required_custom_fields_with_defaults(context)
"custom_field_id" => string_field.id, |> Enum.map(fn cfv ->
"value" => %{"type" => "string", "value" => "test"} cond do
}, cfv["custom_field_id"] == string_field.id ->
%{ %{cfv | "value" => %{"_union_type" => "string", "_union_value" => "test"}}
"custom_field_id" => integer_field.id,
"value" => %{"type" => "integer", "value" => 42} cfv["custom_field_id"] == integer_field.id ->
}, %{cfv | "value" => %{"_union_type" => "integer", "_union_value" => 42}}
%{
"custom_field_id" => boolean_field.id, cfv["custom_field_id"] == boolean_field.id ->
"value" => %{"type" => "boolean", "value" => true} %{cfv | "value" => %{"_union_type" => "boolean", "_union_value" => true}}
}
] true ->
cfv
end
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs) assert {:ok, _member} = Membership.create_member(attrs)
end end
test "fails when one of multiple required custom fields is missing", %{ test "fails when one of multiple required custom fields is missing",
%{
required_string_field: string_field, required_string_field: string_field,
required_integer_field: integer_field required_integer_field: integer_field
} do } = context do
custom_field_values = [ # Provide only string field, missing integer, boolean, and date
%{ custom_field_values =
"custom_field_id" => string_field.id, all_required_custom_fields_with_defaults(context)
"value" => %{"type" => "string", "value" => "test"} |> Enum.filter(fn cfv ->
} cfv["custom_field_id"] == string_field.id
# Missing required_integer_field end)
] |> Enum.map(fn cfv ->
%{cfv | "value" => %{"_union_type" => "string", "_union_value" => "test"}}
end)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values) attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
@ -320,17 +382,24 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ integer_field.name assert error_message(errors, :custom_field_values) =~ integer_field.name
end end
test "succeeds when optional custom field is missing", %{optional_field: field} do test "succeeds when optional custom field is missing", %{} = context do
attrs = Map.put(@valid_attrs, :custom_field_values, []) # Provide all required fields, but no optional field
custom_field_values = all_required_custom_fields_with_defaults(context)
attrs = Map.put(@valid_attrs, :custom_field_values, custom_field_values)
assert {:ok, _member} = Membership.create_member(attrs) assert {:ok, _member} = Membership.create_member(attrs)
end end
test "succeeds when optional custom field has nil value", %{optional_field: field} do test "succeeds when optional custom field has nil value",
custom_field_values = [ %{optional_field: field} = context do
# Provide all required fields plus optional field with nil
custom_field_values =
all_required_custom_fields_with_defaults(context) ++
[
%{ %{
"custom_field_id" => field.id, "custom_field_id" => field.id,
"value" => %{"type" => "string", "value" => nil} "value" => %{"_union_type" => "string", "_union_value" => nil}
} }
] ]
@ -341,16 +410,12 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
end end
describe "update_member with required custom fields" do describe "update_member with required custom fields" do
test "fails when removing a required custom field value", %{ 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, required_string_field: field
"value" => %{"type" => "string", "value" => "test"} } = context do
} # Create member with all required custom fields
] custom_field_values = all_required_custom_fields_with_defaults(context)
{:ok, member} = {:ok, member} =
Membership.create_member(%{ Membership.create_member(%{
@ -368,16 +433,12 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ field.name assert error_message(errors, :custom_field_values) =~ field.name
end end
test "fails when setting required custom field value to empty", %{ 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, required_string_field: field
"value" => %{"type" => "string", "value" => "test"} } = context do
} # Create member with all required custom fields
] custom_field_values = all_required_custom_fields_with_defaults(context)
{:ok, member} = {:ok, member} =
Membership.create_member(%{ Membership.create_member(%{
@ -387,13 +448,16 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
custom_field_values: custom_field_values custom_field_values: custom_field_values
}) })
# Try to update with empty value # Try to update with empty value for the string field
updated_custom_field_values = [ updated_custom_field_values =
%{ all_required_custom_fields_with_defaults(context)
"custom_field_id" => field.id, |> Enum.map(fn cfv ->
"value" => %{"type" => "string", "value" => ""} if cfv["custom_field_id"] == field.id do
} %{cfv | "value" => %{"_union_type" => "string", "_union_value" => ""}}
] else
cfv
end
end)
assert {:error, %Ash.Error.Invalid{errors: errors}} = assert {:error, %Ash.Error.Invalid{errors: errors}} =
Membership.update_member(member, %{ Membership.update_member(member, %{
@ -404,16 +468,12 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
assert error_message(errors, :custom_field_values) =~ field.name assert error_message(errors, :custom_field_values) =~ field.name
end end
test "succeeds when updating required custom field to valid value", %{ 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, required_string_field: field
"value" => %{"type" => "string", "value" => "old value"} } = context do
} # Create member with all required custom fields
] custom_field_values = all_required_custom_fields_with_defaults(context)
{:ok, member} = {:ok, member} =
Membership.create_member(%{ Membership.create_member(%{
@ -423,13 +483,31 @@ defmodule Mv.Membership.MemberRequiredCustomFieldsTest do
custom_field_values: custom_field_values custom_field_values: custom_field_values
}) })
# Update with new valid value # Load existing custom field values to get their IDs
updated_custom_field_values = [ {:ok, member_with_cfvs} = Ash.load(member, :custom_field_values)
# Update with new valid value for the string field, using existing IDs
updated_custom_field_values =
member_with_cfvs.custom_field_values
|> Enum.map(fn cfv ->
if cfv.custom_field_id == field.id do
%{ %{
"custom_field_id" => field.id, "id" => cfv.id,
"value" => %{"type" => "string", "value" => "new value"} "custom_field_id" => cfv.custom_field_id,
"value" => %{"_union_type" => "string", "_union_value" => "new value"}
} }
] else
# Keep other fields as they are
value_type = Atom.to_string(cfv.value.type)
actual_value = cfv.value.value
%{
"id" => cfv.id,
"custom_field_id" => cfv.custom_field_id,
"value" => %{"_union_type" => value_type, "_union_value" => actual_value}
}
end
end)
assert {:ok, _updated_member} = assert {:ok, _updated_member} =
Membership.update_member(member, %{ Membership.update_member(member, %{