From 42a51b9539ed5364bf5e54a4332471047667e3fb Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Thu, 5 Mar 2026 14:52:58 +0000 Subject: [PATCH] Add test coverage for ScrobbleLive Index and Show --- .../live/scrobble_live/index_test.exs | 155 ++++++++++++++++++ .../live/scrobble_live/show_test.exs | 136 +++++++++++++++ 2 files changed, 291 insertions(+) create mode 100644 test/music_library_web/live/scrobble_live/index_test.exs create mode 100644 test/music_library_web/live/scrobble_live/show_test.exs diff --git a/test/music_library_web/live/scrobble_live/index_test.exs b/test/music_library_web/live/scrobble_live/index_test.exs new file mode 100644 index 00000000..49a1425b --- /dev/null +++ b/test/music_library_web/live/scrobble_live/index_test.exs @@ -0,0 +1,155 @@ +defmodule MusicLibraryWeb.ScrobbleLive.IndexTest do + use MusicLibraryWeb.ConnCase + + import Phoenix.LiveViewTest, only: [render: 1, render_submit: 1, render_click: 3, form: 3] + + alias MusicBrainz.Fixtures.ReleaseGroup + + defp stub_search_results(_) do + Req.Test.stub(MusicBrainz.API, fn conn -> + case conn.request_path do + "/ws/2/release-group" -> + Req.Test.json(conn, ReleaseGroup.release_group_search_results()) + + "/ws/2/release" -> + Req.Test.json(conn, ReleaseGroup.release_group_releases(:marbles)) + + _ -> + Req.Test.json(conn, %{}) + end + end) + + :ok + end + + defp stub_empty_search_results(_) do + Req.Test.stub(MusicBrainz.API, fn conn -> + case conn.request_path do + "/ws/2/release-group" -> + Req.Test.json(conn, %{"count" => 0, "release-groups" => []}) + + _ -> + Req.Test.json(conn, %{}) + end + end) + + :ok + end + + describe "Index" do + setup [:stub_search_results] + + test "renders search page with form", %{conn: conn} do + conn + |> visit(~p"/scrobble") + |> assert_has("form[phx-submit='search']") + end + + test "shows connect Last.fm button when not authenticated", %{conn: conn} do + conn + |> visit(~p"/scrobble") + |> assert_has("a", text: "Connect your Last.fm account") + end + + test "search with results shows release groups", %{conn: conn} do + session = visit(conn, ~p"/scrobble") + + session + |> unwrap(fn view -> + view + |> form("form[phx-submit='search']", %{query: "marbles"}) + |> render_submit() + + # Process the {:perform_search, query} message + render(view) + end) + |> assert_has("h3", text: "Release Groups") + |> assert_has("p", text: "Marbles") + end + + test "search with empty query does not trigger search", %{conn: conn} do + session = visit(conn, ~p"/scrobble") + + session + |> unwrap(fn view -> + view + |> form("form[phx-submit='search']", %{query: ""}) + |> render_submit() + end) + |> refute_has("h3", text: "Release Groups") + end + + test "select release group shows releases", %{conn: conn} do + release_group_id = ReleaseGroup.release_group_id(:marbles) + + session = visit(conn, ~p"/scrobble") + + session + |> unwrap(fn view -> + view + |> form("form[phx-submit='search']", %{query: "marbles"}) + |> render_submit() + + # Process search results + render(view) + + # Click on a release group + view + |> render_click("select_release_group", %{ + "release_group_id" => release_group_id + }) + + # Process the {:fetch_releases, release_group} message + render(view) + end) + |> assert_has("h3", text: "Releases for") + |> assert_has("button", text: "Back") + end + + test "clear selection goes back to release groups", %{conn: conn} do + release_group_id = ReleaseGroup.release_group_id(:marbles) + + session = visit(conn, ~p"/scrobble") + + session + |> unwrap(fn view -> + view + |> form("form[phx-submit='search']", %{query: "marbles"}) + |> render_submit() + + render(view) + + view + |> render_click("select_release_group", %{ + "release_group_id" => release_group_id + }) + + render(view) + + # Click back button + view + |> render_click("clear_selection", %{}) + end) + |> assert_has("h3", text: "Release Groups") + |> refute_has("h3", text: "Releases for") + end + end + + describe "Index with no results" do + setup [:stub_empty_search_results] + + test "shows no results message", %{conn: conn} do + session = visit(conn, ~p"/scrobble") + + session + |> unwrap(fn view -> + view + |> form("form[phx-submit='search']", %{query: "nonexistent"}) + |> render_submit() + + render(view) + end) + |> assert_has("p", text: "No release groups found") + end + end +end diff --git a/test/music_library_web/live/scrobble_live/show_test.exs b/test/music_library_web/live/scrobble_live/show_test.exs new file mode 100644 index 00000000..3a6e3e34 --- /dev/null +++ b/test/music_library_web/live/scrobble_live/show_test.exs @@ -0,0 +1,136 @@ +defmodule MusicLibraryWeb.ScrobbleLive.ShowTest do + use MusicLibraryWeb.ConnCase + + import Phoenix.LiveViewTest, only: [render_click: 3] + + alias MusicBrainz.Fixtures.Release, as: ReleaseFixtures + alias MusicLibrary.Secrets + + @release_id ReleaseFixtures.release_id(:marbles) + + defp stub_musicbrainz_release(_) do + Req.Test.stub(MusicBrainz.API, fn conn -> + case conn.request_path do + "/ws/2/release/" <> _id -> + Req.Test.json(conn, ReleaseFixtures.release_with_media(:marbles)) + + _ -> + Req.Test.json(conn, %{}) + end + end) + + :ok + end + + defp stub_musicbrainz_release_error(_) do + Req.Test.stub(MusicBrainz.API, fn conn -> + Plug.Conn.send_resp(conn, 404, "Not Found") + end) + + :ok + end + + defp stub_lastfm_scrobble(_) do + Req.Test.stub(LastFm.API, fn conn -> + Req.Test.json(conn, %{"scrobbles" => %{"@attr" => %{"accepted" => 1}}}) + end) + + :ok + end + + defp store_lastfm_session_key(_) do + Secrets.store("last_fm_session_key", "test_session_key") + :ok + end + + describe "Show" do + setup [:stub_musicbrainz_release] + + test "renders release details", %{conn: conn} do + conn + |> visit(~p"/scrobble/#{@release_id}") + |> assert_has("h2", text: "Marbles") + |> assert_has("a", text: "Back to search") + end + + test "shows Last.fm not connected alert when no session key", %{conn: conn} do + conn + |> visit(~p"/scrobble/#{@release_id}") + |> assert_has("div", text: "You need to connect your Last.fm account") + end + + test "displays tracks", %{conn: conn} do + conn + |> visit(~p"/scrobble/#{@release_id}") + |> assert_has("h3", text: "Tracks") + end + end + + describe "Show with Last.fm connected" do + setup [:stub_musicbrainz_release, :stub_lastfm_scrobble, :store_lastfm_session_key] + + test "does not show Last.fm not connected alert", %{conn: conn} do + conn + |> visit(~p"/scrobble/#{@release_id}") + |> refute_has("[data-part='title']", text: "Last.fm not connected") + end + + test "scrobble full release", %{conn: conn} do + session = visit(conn, ~p"/scrobble/#{@release_id}") + + session + |> unwrap(fn view -> + render_click(view, "scrobble_release", %{}) + end) + |> assert_has("#toast-group", text: "Release scrobbled successfully") + end + + test "scrobble single medium", %{conn: conn} do + session = visit(conn, ~p"/scrobble/#{@release_id}") + + session + |> unwrap(fn view -> + render_click(view, "scrobble_medium", %{"medium_number" => "1"}) + end) + |> assert_has("#toast-group", text: "Disc scrobbled successfully") + end + + test "toggle track selection", %{conn: conn} do + session = visit(conn, ~p"/scrobble/#{@release_id}") + + # Get a track ID from the rendered page, then toggle it + session + |> unwrap(fn view -> + # Toggle a track on + render_click(view, "toggle_track", %{"track-id" => "some-track-id"}) + end) + end + + test "scrobble selected tracks", %{conn: conn} do + release_data = ReleaseFixtures.release_with_media(:marbles) + first_track = release_data["media"] |> List.first() |> Map.get("tracks") |> List.first() + track_id = first_track["id"] + + session = visit(conn, ~p"/scrobble/#{@release_id}") + + session + |> unwrap(fn view -> + # Select a track first + render_click(view, "toggle_track", %{"track-id" => track_id}) + # Then scrobble selected + render_click(view, "scrobble_selected_tracks", %{}) + end) + |> assert_has("#toast-group", text: "Selected tracks scrobbled successfully") + end + end + + describe "Show with failed release fetch" do + setup [:stub_musicbrainz_release_error] + + test "redirects to scrobble index with error", %{conn: conn} do + conn + |> visit(~p"/scrobble/#{@release_id}") + |> assert_path(~p"/scrobble") + end + end +end