mitgliederverwaltung/test/membership/member_fuzzy_search_linking_test.exs
Moritz 0f48a9b15a
Add actor parameter to all tests requiring authorization
This commit adds actor: system_actor to all Ash operations in tests that
require authorization.
2026-01-24 02:21:02 +01:00

187 lines
4.8 KiB
Elixir

defmodule Mv.Membership.MemberFuzzySearchLinkingTest do
@moduledoc """
Tests fuzzy search in Member.available_for_linking action.
Verifies PostgreSQL trigram matching for member search.
"""
use Mv.DataCase, async: false
alias Mv.Accounts
alias Mv.Membership
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
%{actor: system_actor}
end
describe "available_for_linking with fuzzy search" do
test "finds member despite typo", %{actor: actor} do
# Create member with specific name
{:ok, member} =
Membership.create_member(
%{
first_name: "Jonathan",
last_name: "Smith",
email: "jonathan@example.com"
},
actor: actor
)
# Search with typo
query =
Mv.Membership.Member
|> Ash.Query.for_read(:available_for_linking, %{
user_email: nil,
search_query: "Jonatan"
})
{:ok, members} = Ash.read(query, domain: Mv.Membership, actor: actor)
# Should find Jonathan despite typo
assert length(members) == 1
assert hd(members).id == member.id
end
test "finds member with partial match", %{actor: actor} do
# Create member
{:ok, member} =
Membership.create_member(
%{
first_name: "Alexander",
last_name: "Williams",
email: "alex@example.com"
},
actor: actor
)
# Search with partial
query =
Mv.Membership.Member
|> Ash.Query.for_read(:available_for_linking, %{
user_email: nil,
search_query: "Alex"
})
{:ok, members} = Ash.read(query, domain: Mv.Membership, actor: actor)
# Should find Alexander
assert length(members) == 1
assert hd(members).id == member.id
end
test "email match overrides fuzzy search", %{actor: actor} do
# Create two members
{:ok, member1} =
Membership.create_member(
%{
first_name: "John",
last_name: "Doe",
email: "john@example.com"
},
actor: actor
)
{:ok, _member2} =
Membership.create_member(
%{
first_name: "Jane",
last_name: "Smith",
email: "jane@example.com"
},
actor: actor
)
# Search with user_email that matches member1, but search_query that would match member2
query =
Mv.Membership.Member
|> Ash.Query.for_read(:available_for_linking, %{
user_email: "john@example.com",
search_query: "Jane"
})
{:ok, members} = Ash.read(query, domain: Mv.Membership, actor: actor)
# Apply email filter
filtered_members = Mv.Membership.Member.filter_by_email_match(members, "john@example.com")
# Should only return member1 (email match takes precedence)
assert length(filtered_members) == 1
assert hd(filtered_members).id == member1.id
end
test "limits to 10 results", %{actor: actor} do
# Create 15 members with similar names
for i <- 1..15 do
Membership.create_member(
%{
first_name: "Test#{i}",
last_name: "Member",
email: "test#{i}@example.com"
},
actor: actor
)
end
# Search for "Test"
query =
Mv.Membership.Member
|> Ash.Query.for_read(:available_for_linking, %{
user_email: nil,
search_query: "Test"
})
{:ok, members} = Ash.read(query, domain: Mv.Membership, actor: actor)
# Should return max 10 members
assert length(members) == 10
end
test "excludes linked members", %{actor: actor} do
# Create member and link to user
{:ok, member1} =
Membership.create_member(
%{
first_name: "Linked",
last_name: "Member",
email: "linked@example.com"
},
actor: actor
)
{:ok, _user} =
Accounts.create_user(
%{
email: "user@example.com",
member: %{id: member1.id}
},
actor: actor
)
# Create unlinked member
{:ok, member2} =
Membership.create_member(
%{
first_name: "Unlinked",
last_name: "Member",
email: "unlinked@example.com"
},
actor: actor
)
# Search for "Member"
query =
Mv.Membership.Member
|> Ash.Query.for_read(:available_for_linking, %{
user_email: nil,
search_query: "Member"
})
{:ok, members} = Ash.read(query, domain: Mv.Membership, actor: actor)
# Should only return unlinked member
member_ids = Enum.map(members, & &1.id)
refute member1.id in member_ids
assert member2.id in member_ids
end
end
end