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]= 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