- Add 17 missing @spec annotations (layouts, error_json, error_html, skewt_svg) - Move 12+ nested alias/import/require to module top level - Add phx-change/id attributes to 11 raw HTML <form> tags - Remove 4 unused LiveView assigns (:bounds, :data_provider) - Add 3 missing doctest references (HrrrNativeClient, BulkFetch, Accounts) - Break 2 long lines (path_compute.ex:382) - Strengthen weak test assertions (is_binary→byte_size, is_list→!=[]) - Replace Module.concat with Module.safe_concat (2 occurrences) - Replace length/1 > 0 with list != [] (9 occurrences) - Remove no-op assert true, fix no-assertion tests Remaining: 24 socket.assigns introspection warnings (deliberate test pattern for observable behavior testing), 1 formatter-resistant long line, 3 app-code usage warnings.
139 lines
4.2 KiB
Elixir
139 lines
4.2 KiB
Elixir
defmodule MicrowavepropWeb.Api.V1.MeControllerTest do
|
|
use MicrowavepropWeb.ConnCase, async: true
|
|
|
|
alias Microwaveprop.Accounts
|
|
alias Microwaveprop.AccountsFixtures
|
|
alias MicrowavepropWeb.Api.RateLimiter
|
|
|
|
setup %{conn: conn} do
|
|
RateLimiter.reset()
|
|
user = AccountsFixtures.user_fixture()
|
|
{:ok, {plaintext, _record}} = Accounts.create_api_token(user, %{name: "test"})
|
|
|
|
authed = put_req_header(conn, "authorization", "Bearer " <> plaintext)
|
|
%{user: user, plaintext: plaintext, authed: authed}
|
|
end
|
|
|
|
describe "GET /api/v1/me" do
|
|
test "requires auth", %{conn: conn} do
|
|
conn = get(conn, ~p"/api/v1/me")
|
|
assert json_response(conn, 401)
|
|
end
|
|
|
|
test "returns the authenticated user's profile", %{authed: conn, user: user} do
|
|
conn = get(conn, ~p"/api/v1/me")
|
|
body = json_response(conn, 200)
|
|
assert body["data"]["email"] == user.email
|
|
assert body["data"]["callsign"] == user.callsign
|
|
assert body["data"]["is_admin"] in [true, false]
|
|
end
|
|
end
|
|
|
|
describe "PATCH /api/v1/me" do
|
|
test "updates the home QTH from a Maidenhead grid", %{authed: conn} do
|
|
conn = patch(conn, ~p"/api/v1/me", %{"home_grid" => "EM12kx"})
|
|
body = json_response(conn, 200)
|
|
assert body["data"]["home_grid"] == "EM12kx"
|
|
assert is_float(body["data"]["home_lat"])
|
|
end
|
|
|
|
test "returns 422 on bad QTH", %{authed: conn} do
|
|
conn = patch(conn, ~p"/api/v1/me", %{"home_grid" => "ZZ99zz"})
|
|
assert json_response(conn, 422)
|
|
end
|
|
end
|
|
|
|
describe "GET /api/v1/me/contacts" do
|
|
test "returns contacts owned by the user", %{authed: conn, user: user} do
|
|
{:ok, contact} =
|
|
Microwaveprop.Radio.create_contact(
|
|
%{
|
|
"station1" => "W5XD",
|
|
"station2" => "K5XD",
|
|
"qso_timestamp" => "2026-01-01T00:00:00Z",
|
|
"band" => "10000",
|
|
"grid1" => "EM12",
|
|
"grid2" => "EM13",
|
|
"mode" => "CW",
|
|
"submitter_email" => "fixture@example.com"
|
|
},
|
|
user.id
|
|
)
|
|
|
|
conn = get(conn, ~p"/api/v1/me/contacts")
|
|
body = json_response(conn, 200)
|
|
assert [%{"id" => id, "mine?" => true}] = body["data"]
|
|
assert id == contact.id
|
|
end
|
|
end
|
|
|
|
describe "GET /api/v1/me/beacons" do
|
|
test "returns beacons submitted by the user", %{authed: conn, user: user} do
|
|
{:ok, _b} =
|
|
Microwaveprop.Beacons.create_beacon(user, %{
|
|
frequency_mhz: 10_368.1,
|
|
callsign: "W5HN",
|
|
lat: 32.897,
|
|
lon: -97.038,
|
|
power_mw: 1000.0,
|
|
height_ft: 100,
|
|
keying: "on_off"
|
|
})
|
|
|
|
conn = get(conn, ~p"/api/v1/me/beacons")
|
|
assert %{"data" => [_one]} = json_response(conn, 200)
|
|
end
|
|
end
|
|
|
|
describe "API token CRUD" do
|
|
test "lists, then revokes, an API token", %{authed: conn} do
|
|
list = conn |> get(~p"/api/v1/me/api-tokens") |> json_response(200)
|
|
assert [%{"id" => id} | _] = list["data"]
|
|
|
|
revoke = conn |> delete(~p"/api/v1/me/api-tokens/#{id}") |> json_response(200)
|
|
assert revoke["data"]["revoked_at"]
|
|
end
|
|
|
|
test "404 when revoking unknown id", %{authed: conn} do
|
|
conn =
|
|
delete(
|
|
conn,
|
|
~p"/api/v1/me/api-tokens/00000000-0000-0000-0000-000000000000"
|
|
)
|
|
|
|
assert json_response(conn, 404)
|
|
end
|
|
end
|
|
|
|
describe "beacon monitor CRUD" do
|
|
test "creates, lists, and deletes a beacon monitor", %{authed: conn} do
|
|
created =
|
|
conn
|
|
|> post(~p"/api/v1/me/beacon-monitors", %{"name" => "Tower"})
|
|
|> json_response(201)
|
|
|
|
id = created["data"]["id"]
|
|
|
|
list = conn |> get(~p"/api/v1/me/beacon-monitors") |> json_response(200)
|
|
assert Enum.any?(list["data"], &(&1["id"] == id))
|
|
|
|
conn = delete(conn, ~p"/api/v1/me/beacon-monitors/#{id}")
|
|
assert response(conn, 204)
|
|
end
|
|
|
|
test "422 when creating with empty name", %{authed: conn} do
|
|
conn = post(conn, ~p"/api/v1/me/beacon-monitors", %{"name" => ""})
|
|
assert json_response(conn, 422)
|
|
end
|
|
|
|
test "404 when deleting unknown monitor", %{authed: conn} do
|
|
conn =
|
|
delete(
|
|
conn,
|
|
~p"/api/v1/me/beacon-monitors/00000000-0000-0000-0000-000000000000"
|
|
)
|
|
|
|
assert json_response(conn, 404)
|
|
end
|
|
end
|
|
end
|