diff --git a/appview/test/atvouch/tangled/comment_builder_test.exs b/appview/test/atvouch/tangled/comment_builder_test.exs index 2068b50..50663cd 100644 --- a/appview/test/atvouch/tangled/comment_builder_test.exs +++ b/appview/test/atvouch/tangled/comment_builder_test.exs @@ -85,20 +85,14 @@ defmodule Atvouch.Tangled.CommentBuilderTest do assert result =~ "- no route from [@dave.test](https://bsky.app/profile/did:plc:dave)" end - test "falls back to DID when handle is nil" do - routes = [{@alice_did, nil, {:direct, @author_did}}] - result = CommentBuilder.build_comment(@author_did, nil, routes) - - refute result =~ "##" - assert result =~ "- [#{@alice_did}](https://bsky.app/profile/#{@alice_did}) -> [#{@author_did}](https://bsky.app/profile/#{@author_did})" - end - - test "falls back to DID when handle is empty string" do - routes = [{@alice_did, "", {:direct, @author_did}}] - result = CommentBuilder.build_comment(@author_did, "", routes) - - refute result =~ "##" - assert result =~ "- [#{@alice_did}](https://bsky.app/profile/#{@alice_did}) -> [#{@author_did}](https://bsky.app/profile/#{@author_did})" + test "falls back to DID when handle is nil or empty string" do + for maintainer_handle <- [nil, ""] do + routes = [{@alice_did, maintainer_handle, {:direct, @author_did}}] + result = CommentBuilder.build_comment(@author_did, maintainer_handle, routes) + + refute result =~ "##" + assert result =~ "- [#{@alice_did}](https://bsky.app/profile/#{@alice_did}) -> [#{@author_did}](https://bsky.app/profile/#{@author_did})" + end end test "formats three-hop path" do diff --git a/appview/test/atvouch/tangled/scraper_test.exs b/appview/test/atvouch/tangled/scraper_test.exs index f7816a0..bc7e996 100644 --- a/appview/test/atvouch/tangled/scraper_test.exs +++ b/appview/test/atvouch/tangled/scraper_test.exs @@ -48,30 +48,6 @@ defmodule Atvouch.Tangled.ScraperTest do """ end - test "parses pulls page HTML to extract PR list with timestamps" do - html = - wrap_page( - pr_entry("alice.test", "3abc123", 3, "Fix broken tests", "2026-03-19T14:37:19+00:00") <> - pr_entry("alice.test", "3abc123", 2, "Add new feature", "2026-03-10T16:25:26+00:00") <> - pr_entry("alice.test", "3abc123", 1, "Initial setup", "2026-02-15T10:00:00+00:00") - ) - - pulls = Scraper.parse_pulls_page(html) - - assert length(pulls) == 3 - {3, title3, ts3} = Enum.at(pulls, 0) - assert title3 =~ "Fix broken tests" - assert ts3 == "2026-03-19T14:37:19+00:00" - - {2, title2, ts2} = Enum.at(pulls, 1) - assert title2 =~ "Add new feature" - assert ts2 == "2026-03-10T16:25:26+00:00" - - {1, title1, ts1} = Enum.at(pulls, 2) - assert title1 =~ "Initial setup" - assert ts1 == "2026-02-15T10:00:00+00:00" - end - test "handles empty pulls page" do html = wrap_page("
No pull requests found.
") pulls = Scraper.parse_pulls_page(html) diff --git a/appview/test/atvouch/tangled/session_test.exs b/appview/test/atvouch/tangled/session_test.exs index da8093d..2addfa7 100644 --- a/appview/test/atvouch/tangled/session_test.exs +++ b/appview/test/atvouch/tangled/session_test.exs @@ -15,21 +15,7 @@ defmodule Atvouch.Tangled.SessionTest do {:ok, tangled_port: servers.tangled_port} end - test "successful login returns cookies", %{tangled_port: tangled_port} do - {:ok, pid} = - Session.start_link( - handle: "bot.test", - password: "test-password", - tangled_url: "http://127.0.0.1:#{tangled_port}", - name: :"session_test_#{tangled_port}" - ) - - result = Session.get_cookies(pid) - assert {:ok, cookies} = result - assert String.contains?(cookies, "appview-session-v2=") - end - - test "cookies are cached on second call", %{tangled_port: tangled_port} do + test "successful login returns cookies and caches them", %{tangled_port: tangled_port} do {:ok, pid} = Session.start_link( handle: "bot.test", @@ -39,12 +25,12 @@ defmodule Atvouch.Tangled.SessionTest do ) {:ok, cookies1} = Session.get_cookies(pid) + assert String.contains?(cookies1, "appview-session-v2=") # Drain messages from first login drain_messages() {:ok, cookies2} = Session.get_cookies(pid) - assert cookies1 == cookies2 # Should NOT have received another login attempt diff --git a/appview/test/atvouch/xrpc_get_routes_test.exs b/appview/test/atvouch/xrpc_get_routes_test.exs index 6a5a28a..5072770 100644 --- a/appview/test/atvouch/xrpc_get_routes_test.exs +++ b/appview/test/atvouch/xrpc_get_routes_test.exs @@ -40,21 +40,8 @@ defmodule Atvouch.XrpcGetRoutesTest do end describe "GET /xrpc/dev.atvouch.graph.getRoutes" do - test "returns 401 without authentication" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getRoutes?target=did:plc:bob") - |> Atvouch.Router.call(@opts) - - assert conn.status == 401 - end - - test "returns 401 with invalid token" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getRoutes?target=did:plc:bob") - |> put_req_header("authorization", "Bearer bad-token") - |> Atvouch.Router.call(@opts) - - assert conn.status == 401 + test "requires authentication" do + assert_requires_auth("/xrpc/dev.atvouch.graph.getRoutes?target=did:plc:bob", @opts) end test "returns 400 when target parameter is missing" do diff --git a/appview/test/atvouch/xrpc_vouches_test.exs b/appview/test/atvouch/xrpc_vouches_test.exs index 0ae8a67..5b5bb52 100644 --- a/appview/test/atvouch/xrpc_vouches_test.exs +++ b/appview/test/atvouch/xrpc_vouches_test.exs @@ -78,21 +78,8 @@ defmodule Atvouch.XrpcVouchesTest do assert body["vouches"] == [] end - test "returns 401 without authentication" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getCurrentUserVouches") - |> Atvouch.Router.call(@opts) - - assert conn.status == 401 - end - - test "returns 401 with invalid token" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getCurrentUserVouches") - |> put_req_header("authorization", "Bearer bad-token") - |> Atvouch.Router.call(@opts) - - assert conn.status == 401 + test "requires authentication" do + assert_requires_auth("/xrpc/dev.atvouch.graph.getCurrentUserVouches", @opts) end test "returns pagination data and behaves with limit" do @@ -152,31 +139,11 @@ defmodule Atvouch.XrpcVouchesTest do refute body["cursor"] end - test "returns 400 with invalid cursor" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getCurrentUserVouches?cursor=notanumber") - |> put_req_header("authorization", "Bearer valid-token:did:plc:alice") - |> Atvouch.Router.call(@opts) - - assert conn.status == 400 - end - - test "returns 400 with limit over 1000" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getCurrentUserVouches?limit=1001") - |> put_req_header("authorization", "Bearer valid-token:did:plc:alice") - |> Atvouch.Router.call(@opts) - - assert conn.status == 400 - end - - test "returns 400 with limit under 1" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getCurrentUserVouches?limit=0") - |> put_req_header("authorization", "Bearer valid-token:did:plc:alice") - |> Atvouch.Router.call(@opts) - - assert conn.status == 400 + test "validates pagination parameters" do + assert_validates_pagination_params( + "/xrpc/dev.atvouch.graph.getCurrentUserVouches", @opts, + auth_did: "did:plc:alice" + ) end end @@ -231,21 +198,8 @@ defmodule Atvouch.XrpcVouchesTest do assert vouch["targetDid"] == "did:plc:carol" end - test "returns 401 without authentication" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getRemoteVouches") - |> Atvouch.Router.call(@opts) - - assert conn.status == 401 - end - - test "returns 401 with invalid token" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getRemoteVouches") - |> put_req_header("authorization", "Bearer bad-token") - |> Atvouch.Router.call(@opts) - - assert conn.status == 401 + test "requires authentication" do + assert_requires_auth("/xrpc/dev.atvouch.graph.getRemoteVouches", @opts) end test "returns total count" do @@ -335,31 +289,11 @@ defmodule Atvouch.XrpcVouchesTest do refute body["cursor"] end - test "returns 400 with invalid cursor" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getRemoteVouches?cursor=notanumber") - |> put_req_header("authorization", "Bearer valid-token:did:plc:alice") - |> Atvouch.Router.call(@opts) - - assert conn.status == 400 - end - - test "returns 400 with limit over 1000" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getRemoteVouches?limit=1001") - |> put_req_header("authorization", "Bearer valid-token:did:plc:alice") - |> Atvouch.Router.call(@opts) - - assert conn.status == 400 - end - - test "returns 400 with limit under 1" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getRemoteVouches?limit=0") - |> put_req_header("authorization", "Bearer valid-token:did:plc:alice") - |> Atvouch.Router.call(@opts) - - assert conn.status == 400 + test "validates pagination parameters" do + assert_validates_pagination_params( + "/xrpc/dev.atvouch.graph.getRemoteVouches", @opts, + auth_did: "did:plc:alice" + ) end end @@ -384,16 +318,6 @@ defmodule Atvouch.XrpcVouchesTest do ] end - test "returns total count of vouches" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getEntireGraph") - |> Atvouch.Router.call(@opts) - - assert conn.status == 200 - body = Jason.decode!(conn.resp_body) - assert body["total"] == 3 - end - test "total count is consistent across paginated requests" do conn = conn(:get, "/xrpc/dev.atvouch.graph.getEntireGraph?limit=1") @@ -478,28 +402,8 @@ defmodule Atvouch.XrpcVouchesTest do assert length(body["vouches"]) == 3 end - test "returns 400 with invalid cursor" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getEntireGraph?cursor=notanumber") - |> Atvouch.Router.call(@opts) - - assert conn.status == 400 - end - - test "returns 400 with limit over 1000" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getEntireGraph?limit=1001") - |> Atvouch.Router.call(@opts) - - assert conn.status == 400 - end - - test "returns 400 with limit under 1" do - conn = - conn(:get, "/xrpc/dev.atvouch.graph.getEntireGraph?limit=0") - |> Atvouch.Router.call(@opts) - - assert conn.status == 400 + test "validates pagination parameters" do + assert_validates_pagination_params("/xrpc/dev.atvouch.graph.getEntireGraph", @opts) end end end diff --git a/appview/test/support/test_helpers.ex b/appview/test/support/test_helpers.ex index bf5ba9f..7808e14 100644 --- a/appview/test/support/test_helpers.ex +++ b/appview/test/support/test_helpers.ex @@ -219,6 +219,47 @@ defmodule Atvouch.Test.Helpers do } end + # --- Auth & Pagination Assertions --- + + def assert_requires_auth(path, router_opts) do + import ExUnit.Assertions + import Plug.Test + import Plug.Conn + + conn_no_auth = conn(:get, path) |> Atvouch.Router.call(router_opts) + assert conn_no_auth.status == 401, "expected 401 without auth for #{path}" + + conn_bad_token = + conn(:get, path) + |> put_req_header("authorization", "Bearer bad-token") + |> Atvouch.Router.call(router_opts) + + assert conn_bad_token.status == 401, "expected 401 with invalid token for #{path}" + end + + def assert_validates_pagination_params(path, router_opts, opts \\ []) do + import ExUnit.Assertions + import Plug.Test + import Plug.Conn + + auth_did = Keyword.get(opts, :auth_did) + sep = if String.contains?(path, "?"), do: "&", else: "?" + + make_conn = fn url -> + c = conn(:get, url) + if auth_did, do: put_req_header(c, "authorization", "Bearer valid-token:#{auth_did}"), else: c + end + + conn1 = make_conn.("#{path}#{sep}cursor=notanumber") |> Atvouch.Router.call(router_opts) + assert conn1.status == 400, "expected 400 for invalid cursor on #{path}" + + conn2 = make_conn.("#{path}#{sep}limit=1001") |> Atvouch.Router.call(router_opts) + assert conn2.status == 400, "expected 400 for limit over 1000 on #{path}" + + conn3 = make_conn.("#{path}#{sep}limit=0") |> Atvouch.Router.call(router_opts) + assert conn3.status == 400, "expected 400 for limit under 1 on #{path}" + end + # --- Drain Messages --- def drain_messages(timeout \\ 100) do