feat(member-live): wire date filters into LiveView lifecycle
This commit is contained in:
parent
ddd4a9a878
commit
e3295ab4b5
10 changed files with 1037 additions and 140 deletions
|
|
@ -0,0 +1,89 @@
|
|||
defmodule MvWeb.MemberLive.Index.CustomFieldValueLookupTest do
|
||||
@moduledoc """
|
||||
Unit tests for the shared custom-field-value lookup helper.
|
||||
|
||||
The lookup must handle both shapes a CFV entry can take on a loaded member:
|
||||
|
||||
* `%{custom_field_id: id, value: ...}` — id present directly
|
||||
* `%{custom_field: %{id: id, ...}, value: ...}` — id nested under loaded relation
|
||||
"""
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias MvWeb.MemberLive.Index.CustomFieldValueLookup
|
||||
|
||||
defp uuid, do: "11111111-2222-3333-4444-555555555555"
|
||||
|
||||
describe "find_by_id/2" do
|
||||
test "matches when custom_field_id key is present" do
|
||||
id = uuid()
|
||||
cfv = %{custom_field_id: id, value: :anything}
|
||||
member = %{custom_field_values: [cfv]}
|
||||
|
||||
assert CustomFieldValueLookup.find_by_id(member, id) == cfv
|
||||
end
|
||||
|
||||
test "matches when nested custom_field relation is loaded" do
|
||||
id = uuid()
|
||||
cfv = %{custom_field: %{id: id, value_type: :date}, value: :anything}
|
||||
member = %{custom_field_values: [cfv]}
|
||||
|
||||
assert CustomFieldValueLookup.find_by_id(member, id) == cfv
|
||||
end
|
||||
|
||||
test "compares stringified ids — accepts atom or binary ids on the cfv side" do
|
||||
id = uuid()
|
||||
cfv = %{custom_field_id: id, value: :v}
|
||||
member = %{custom_field_values: [cfv]}
|
||||
|
||||
# Same id, passed as binary
|
||||
assert CustomFieldValueLookup.find_by_id(member, id) == cfv
|
||||
end
|
||||
|
||||
test "returns nil when no entry has a matching id" do
|
||||
member = %{
|
||||
custom_field_values: [
|
||||
%{custom_field_id: "11111111-1111-1111-1111-111111111111", value: 1}
|
||||
]
|
||||
}
|
||||
|
||||
assert CustomFieldValueLookup.find_by_id(member, uuid()) == nil
|
||||
end
|
||||
|
||||
test "returns nil when custom_field_values is nil" do
|
||||
assert CustomFieldValueLookup.find_by_id(%{custom_field_values: nil}, uuid()) == nil
|
||||
end
|
||||
|
||||
test "returns nil when custom_field_values is not loaded (Ash.NotLoaded)" do
|
||||
member = %{custom_field_values: %Ash.NotLoaded{type: :relationship}}
|
||||
assert CustomFieldValueLookup.find_by_id(member, uuid()) == nil
|
||||
end
|
||||
|
||||
test "returns nil when custom_field_values is empty" do
|
||||
assert CustomFieldValueLookup.find_by_id(%{custom_field_values: []}, uuid()) == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "find_by_field/2" do
|
||||
test "matches a custom_field struct via its :id" do
|
||||
id = uuid()
|
||||
cfv = %{custom_field_id: id, value: :v}
|
||||
member = %{custom_field_values: [cfv]}
|
||||
custom_field = %{id: id, value_type: :boolean}
|
||||
|
||||
assert CustomFieldValueLookup.find_by_field(member, custom_field) == cfv
|
||||
end
|
||||
|
||||
test "matches when only the nested custom_field is present" do
|
||||
id = uuid()
|
||||
cfv = %{custom_field: %{id: id}, value: :v}
|
||||
member = %{custom_field_values: [cfv]}
|
||||
|
||||
assert CustomFieldValueLookup.find_by_field(member, %{id: id}) == cfv
|
||||
end
|
||||
|
||||
test "returns nil when no entry matches" do
|
||||
member = %{custom_field_values: [%{custom_field_id: "other", value: :v}]}
|
||||
assert CustomFieldValueLookup.find_by_field(member, %{id: uuid()}) == nil
|
||||
end
|
||||
end
|
||||
end
|
||||
85
test/mv_web/live/member_live/index/filter_params_test.exs
Normal file
85
test/mv_web/live/member_live/index/filter_params_test.exs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
defmodule MvWeb.MemberLive.Index.FilterParamsTest do
|
||||
@moduledoc """
|
||||
Unit tests for the shared filter-param parsers.
|
||||
"""
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias MvWeb.MemberLive.Index.FilterParams
|
||||
|
||||
describe "parse_prefix_filters/3" do
|
||||
test "extracts only entries whose key starts with the prefix" do
|
||||
params = %{
|
||||
"group_abc" => "in",
|
||||
"group_def" => "not_in",
|
||||
"fee_type_xyz" => "in",
|
||||
"unrelated" => "in",
|
||||
"query" => "alice"
|
||||
}
|
||||
|
||||
result = FilterParams.parse_prefix_filters(params, "group_", & &1)
|
||||
|
||||
assert result == %{"abc" => "in", "def" => "not_in"}
|
||||
end
|
||||
|
||||
test "strips exactly one occurrence of the prefix, even when the rest starts with the prefix again" do
|
||||
# Quirky but legal: a key like "p_p_abc" with prefix "p_" must produce id "p_abc".
|
||||
params = %{"p_p_abc" => "v"}
|
||||
result = FilterParams.parse_prefix_filters(params, "p_", & &1)
|
||||
assert result == %{"p_abc" => "v"}
|
||||
end
|
||||
|
||||
test "applies parse_value_fn to every value" do
|
||||
params = %{"x_one" => "in", "x_two" => "not_in", "x_three" => "garbage"}
|
||||
|
||||
result =
|
||||
FilterParams.parse_prefix_filters(
|
||||
params,
|
||||
"x_",
|
||||
&FilterParams.parse_in_not_in_value/1
|
||||
)
|
||||
|
||||
assert result == %{"one" => :in, "two" => :not_in, "three" => nil}
|
||||
end
|
||||
|
||||
test "returns empty map when no key matches the prefix" do
|
||||
params = %{"a" => "1", "b" => "2"}
|
||||
assert FilterParams.parse_prefix_filters(params, "z_", & &1) == %{}
|
||||
end
|
||||
|
||||
test "ignores non-binary keys" do
|
||||
params = %{"x_a" => "1", :atom_key => "2", 123 => "3"}
|
||||
result = FilterParams.parse_prefix_filters(params, "x_", & &1)
|
||||
assert result == %{"a" => "1"}
|
||||
end
|
||||
|
||||
test "returns empty map for empty input" do
|
||||
assert FilterParams.parse_prefix_filters(%{}, "x_", & &1) == %{}
|
||||
end
|
||||
end
|
||||
|
||||
describe "parse_in_not_in_value/1" do
|
||||
test "maps 'in' to :in" do
|
||||
assert FilterParams.parse_in_not_in_value("in") == :in
|
||||
end
|
||||
|
||||
test "maps 'not_in' to :not_in" do
|
||||
assert FilterParams.parse_in_not_in_value("not_in") == :not_in
|
||||
end
|
||||
|
||||
test "trims whitespace around recognized values" do
|
||||
assert FilterParams.parse_in_not_in_value(" in ") == :in
|
||||
assert FilterParams.parse_in_not_in_value("\tnot_in\n") == :not_in
|
||||
end
|
||||
|
||||
test "returns nil for unrecognized strings" do
|
||||
assert FilterParams.parse_in_not_in_value("yes") == nil
|
||||
assert FilterParams.parse_in_not_in_value("") == nil
|
||||
end
|
||||
|
||||
test "returns nil for non-binary input" do
|
||||
assert FilterParams.parse_in_not_in_value(nil) == nil
|
||||
assert FilterParams.parse_in_not_in_value(:in) == nil
|
||||
assert FilterParams.parse_in_not_in_value(123) == nil
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue