mitgliederverwaltung/test/mv/vereinfacht/client_test.exs
Moritz 01b9ebd74b
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
Vereinfacht client: email normalization, multi-match warning, Bypass tests, doc note
- Normalize email (trim + downcase) before filter lookup
- Log warning when API returns multiple contacts for same email
- Add Bypass tests for find_contact_by_email (query params, empty/single response parsing)
- Document vereinfacht_required_field? as legacy/unused in vereinfacht-api.md
- Add bypass dependency (dev+test) for HTTP stubbing
2026-03-04 20:55:59 +01:00

134 lines
4.1 KiB
Elixir

defmodule Mv.Vereinfacht.ClientTest do
@moduledoc """
Tests for Mv.Vereinfacht.Client.
"Not configured" path: no HTTP. When configured we use Bypass to stub the API
and assert on request (query params) and response parsing.
"""
use Mv.DataCase, async: false
alias Mv.Vereinfacht.Client
setup do
clear_vereinfacht_env()
:ok
end
describe "create_contact/1" do
test "returns {:error, :not_configured} when Vereinfacht is not configured" do
member = build_member_struct()
assert Client.create_contact(member) == {:error, :not_configured}
end
end
describe "update_contact/2" do
test "returns {:error, :not_configured} when Vereinfacht is not configured" do
member = build_member_struct()
assert Client.update_contact("123", member) == {:error, :not_configured}
end
end
describe "find_contact_by_email/1" do
test "returns {:error, :not_configured} when Vereinfacht is not configured" do
assert Client.find_contact_by_email("kayley.becker@example.com") ==
{:error, :not_configured}
end
@tag :bypass
test "sends filter[isExternal]=true and filter[email]=<encoded> and returns :not_found when data is empty" do
bypass = Bypass.open()
base = "http://127.0.0.1:#{bypass.port}"
set_vereinfacht_env(base)
Bypass.expect_once(bypass, "GET", "/finance-contacts", fn conn ->
qs = conn.query_string || ""
assert qs =~ "filter[isExternal]=true",
"expected query to contain filter[isExternal]=true, got: #{inspect(qs)}"
assert qs =~ "filter[email]=",
"expected query to contain filter[email]=..., got: #{inspect(qs)}"
# Email should be encoded (e.g. @ as %40)
assert qs =~ "filter[email]=test%40example.com",
"expected filter[email] to be URL-encoded (downcased), got: #{inspect(qs)}"
body = Jason.encode!(%{"jsonapi" => %{"version" => "1.0"}, "data" => []})
conn
|> Plug.Conn.put_resp_content_type("application/vnd.api+json")
|> Plug.Conn.send_resp(200, body)
end)
assert Client.find_contact_by_email(" Test@Example.com ") == {:error, :not_found}
end
@tag :bypass
test "returns {:ok, id} when API returns one contact (string id)" do
bypass = Bypass.open()
base = "http://127.0.0.1:#{bypass.port}"
set_vereinfacht_env(base)
Bypass.expect_once(bypass, "GET", "/finance-contacts", fn conn ->
body =
Jason.encode!(%{
"jsonapi" => %{"version" => "1.0"},
"data" => [%{"type" => "finance-contacts", "id" => "123", "attributes" => %{}}]
})
conn
|> Plug.Conn.put_resp_content_type("application/vnd.api+json")
|> Plug.Conn.send_resp(200, body)
end)
assert Client.find_contact_by_email("user@example.com") == {:ok, "123"}
end
@tag :bypass
test "returns {:ok, id} when API returns one contact (integer id)" do
bypass = Bypass.open()
base = "http://127.0.0.1:#{bypass.port}"
set_vereinfacht_env(base)
Bypass.expect_once(bypass, "GET", "/finance-contacts", fn conn ->
body =
Jason.encode!(%{
"jsonapi" => %{"version" => "1.0"},
"data" => [%{"type" => "finance-contacts", "id" => 456, "attributes" => %{}}]
})
conn
|> Plug.Conn.put_resp_content_type("application/vnd.api+json")
|> Plug.Conn.send_resp(200, body)
end)
assert Client.find_contact_by_email("other@example.com") == {:ok, "456"}
end
end
defp build_member_struct do
%{
first_name: "Test",
last_name: "User",
email: "test@example.com",
street: "Street 1",
house_number: "2",
postal_code: "12345",
city: "Berlin"
}
end
defp set_vereinfacht_env(base_url) do
System.put_env("VEREINFACHT_API_URL", base_url)
System.put_env("VEREINFACHT_API_KEY", "test-key")
System.put_env("VEREINFACHT_CLUB_ID", "2")
end
defp clear_vereinfacht_env do
System.delete_env("VEREINFACHT_API_URL")
System.delete_env("VEREINFACHT_API_KEY")
System.delete_env("VEREINFACHT_CLUB_ID")
end
end