aprs.me/test/aprsme_web/plugs/ip_geolocation_test.exs
Graham McIntire 6988116a42
Fix Cloudflare IP geolocation not reaching LiveView on page load
The IPGeolocation plug was setting session data, but the live_session
wasn't forwarding it to the LiveView mount. Also removed the root-path
restriction so geolocation works on any initial page load.
2026-03-22 16:08:00 -05:00

128 lines
3.7 KiB
Elixir

defmodule AprsmeWeb.Plugs.IPGeolocationTest do
use AprsmeWeb.ConnCase
alias AprsmeWeb.Plugs.IPGeolocation
setup %{conn: conn} do
conn =
conn
|> Plug.Session.call(Plug.Session.init(store: :cookie, key: "_aprs_key", signing_salt: "test"))
|> fetch_session()
{:ok, conn: conn}
end
describe "call/2 with Cloudflare headers" do
test "sets session from CF-IPLatitude and CF-IPLongitude headers on root GET", %{conn: conn} do
conn =
conn
|> put_req_header("cf-iplatitude", "37.7749")
|> put_req_header("cf-iplongitude", "-122.4194")
|> IPGeolocation.call([])
geo = get_session(conn, :ip_geolocation)
assert geo == %{"lat" => 37.7749, "lng" => -122.4194}
end
test "skips when CF headers are missing", %{conn: conn} do
conn = IPGeolocation.call(conn, [])
assert get_session(conn, :ip_geolocation) == nil
end
test "skips when only latitude header is present", %{conn: conn} do
conn =
conn
|> put_req_header("cf-iplatitude", "37.7749")
|> IPGeolocation.call([])
assert get_session(conn, :ip_geolocation) == nil
end
test "skips when only longitude header is present", %{conn: conn} do
conn =
conn
|> put_req_header("cf-iplongitude", "-122.4194")
|> IPGeolocation.call([])
assert get_session(conn, :ip_geolocation) == nil
end
test "works on non-root paths", %{conn: conn} do
conn =
conn
|> Map.put(:request_path, "/about")
|> put_req_header("cf-iplatitude", "37.7749")
|> put_req_header("cf-iplongitude", "-122.4194")
|> IPGeolocation.call([])
geo = get_session(conn, :ip_geolocation)
assert geo == %{"lat" => 37.7749, "lng" => -122.4194}
end
test "skips non-GET requests", %{conn: conn} do
conn =
conn
|> Map.put(:method, "POST")
|> put_req_header("cf-iplatitude", "37.7749")
|> put_req_header("cf-iplongitude", "-122.4194")
|> IPGeolocation.call([])
assert get_session(conn, :ip_geolocation) == nil
end
test "uses cached session data without re-reading headers", %{conn: conn} do
geo_data = %{"lat" => 40.7128, "lng" => -74.006}
conn =
conn
|> put_session(:ip_geolocation, geo_data)
|> put_req_header("cf-iplatitude", "37.7749")
|> put_req_header("cf-iplongitude", "-122.4194")
|> IPGeolocation.call([])
assert get_session(conn, :ip_geolocation) == geo_data
end
test "rejects latitude out of range", %{conn: conn} do
conn =
conn
|> put_req_header("cf-iplatitude", "91.0")
|> put_req_header("cf-iplongitude", "-122.4194")
|> IPGeolocation.call([])
assert get_session(conn, :ip_geolocation) == nil
end
test "rejects longitude out of range", %{conn: conn} do
conn =
conn
|> put_req_header("cf-iplatitude", "37.7749")
|> put_req_header("cf-iplongitude", "181.0")
|> IPGeolocation.call([])
assert get_session(conn, :ip_geolocation) == nil
end
test "rejects non-numeric header values", %{conn: conn} do
conn =
conn
|> put_req_header("cf-iplatitude", "not_a_number")
|> put_req_header("cf-iplongitude", "-122.4194")
|> IPGeolocation.call([])
assert get_session(conn, :ip_geolocation) == nil
end
test "handles boundary coordinate values", %{conn: conn} do
conn =
conn
|> put_req_header("cf-iplatitude", "-90.0")
|> put_req_header("cf-iplongitude", "180.0")
|> IPGeolocation.call([])
geo = get_session(conn, :ip_geolocation)
assert geo == %{"lat" => -90.0, "lng" => 180.0}
end
end
end