defmodule BerrypodWeb.FaviconControllerTest do use BerrypodWeb.ConnCase, async: false alias Berrypod.Media # Minimal valid PNG (1x1 transparent) @test_png <<137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, 10, 73, 68, 65, 84, 120, 156, 98, 0, 0, 0, 2, 0, 1, 226, 33, 188, 51, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130>> @test_svg ~s() defp create_source_image do {:ok, image} = Media.upload_image(%{ image_type: "icon", filename: "icon.svg", content_type: "image/svg+xml", file_size: byte_size(@test_svg), data: @test_svg }) image end defp create_favicon_variants(_context) do image = create_source_image() {:ok, variants} = Media.store_favicon_variants(%{ source_image_id: image.id, png_32: @test_png, png_180: @test_png, png_192: @test_png, png_512: @test_png, svg: @test_svg }) %{variants: variants} end describe "favicon routes with variants" do setup [:create_favicon_variants] test "serves favicon SVG", %{conn: conn} do conn = get(conn, ~p"/favicon.svg") assert response_content_type(conn, :xml) =~ "image/svg+xml" assert conn.status == 200 assert conn.resp_body =~ "> = conn.resp_body end test "serves apple touch icon", %{conn: conn} do conn = get(conn, ~p"/apple-touch-icon.png") assert conn.status == 200 assert response_content_type(conn, :png) =~ "image/png" end test "serves 192px icon", %{conn: conn} do conn = get(conn, ~p"/icon-192.png") assert conn.status == 200 assert response_content_type(conn, :png) =~ "image/png" end test "serves 512px icon", %{conn: conn} do conn = get(conn, ~p"/icon-512.png") assert conn.status == 200 assert response_content_type(conn, :png) =~ "image/png" end test "returns 304 for matching ETag", %{conn: conn} do conn1 = get(conn, ~p"/favicon-32x32.png") [etag] = get_resp_header(conn1, "etag") conn2 = conn |> put_req_header("if-none-match", etag) |> get(~p"/favicon-32x32.png") assert conn2.status == 304 end end describe "favicon routes without variants" do test "returns 404 for favicon SVG", %{conn: conn} do conn = get(conn, ~p"/favicon.svg") assert conn.status == 404 end test "returns 404 for PNG variants", %{conn: conn} do assert get(conn, ~p"/favicon-32x32.png").status == 404 assert get(conn, ~p"/apple-touch-icon.png").status == 404 assert get(conn, ~p"/icon-192.png").status == 404 assert get(conn, ~p"/icon-512.png").status == 404 end end describe "webmanifest" do test "returns valid JSON manifest", %{conn: conn} do conn = get(conn, ~p"/site.webmanifest") assert conn.status == 200 assert response_content_type(conn, :json) =~ "application/manifest+json" manifest = json_response(conn, 200) assert manifest["name"] == "Store Name" assert manifest["display"] == "minimal-ui" assert manifest["start_url"] == "/" assert is_binary(manifest["theme_color"]) assert is_binary(manifest["background_color"]) assert length(manifest["icons"]) == 2 end test "manifest icons have correct sizes", %{conn: conn} do manifest = json_response(get(conn, ~p"/site.webmanifest"), 200) icons = manifest["icons"] assert Enum.any?(icons, &(&1["sizes"] == "192x192")) assert Enum.any?(icons, &(&1["sizes"] == "512x512")) end test "manifest uses short name from settings", %{conn: conn} do manifest = json_response(get(conn, ~p"/site.webmanifest"), 200) # Default: truncated site_name (no favicon_short_name set) assert is_binary(manifest["short_name"]) assert String.length(manifest["short_name"]) <= 12 end end end