Promote Collection to proper namespace

This commit is contained in:
Claudio Ortolina
2024-11-20 15:26:31 +00:00
parent c465db4981
commit b8f3bb9b2c
9 changed files with 50 additions and 50 deletions
@@ -0,0 +1,354 @@
defmodule MusicLibraryWeb.CollectionLive.IndexTest do
use MusicLibraryWeb.ConnCase
import Phoenix.LiveViewTest
import MusicLibrary.RecordsFixtures
import MusicLibrary.ReleaseGroupsFixtures
import Mox
alias MusicLibrary.Records.Record
alias MusicBrainz.APIBehaviourMock
setup :verify_on_exit!
@default_records_page_size 100
@total_records @default_records_page_size + 10
defp fill_collection(_) do
records = Enum.map(1..@total_records, fn _ -> record_fixture() end)
%{collection: records}
end
defp fill_wishlist(_) do
records = Enum.map(1..@total_records, fn _ -> record_fixture(%{purchased_at: nil}) end)
%{wishlist: records}
end
defp escape(string) do
string
|> Phoenix.HTML.html_escape()
|> Phoenix.HTML.safe_to_string()
end
describe "Collection" do
setup [:fill_collection, :fill_wishlist]
test "does not show wishlist records", %{
conn: conn,
wishlist: wishlist_records
} do
{:ok, index_live, _html} = live(conn, ~p"/records")
for record <- wishlist_records do
refute has_element?(index_live, "#records-#{record.id}")
end
end
test "shows purchased records", %{conn: conn, collection: records} do
{:ok, index_live, html} = live(conn, ~p"/records")
assert html =~ "Collection"
{present, absent} =
Enum.split_with(records, fn record ->
html =~ record.id
end)
assert length(present) == @default_records_page_size
assert length(absent) == @total_records - @default_records_page_size
for record <- present do
record_row =
index_live
|> with_target("#records-#{record.id}")
record_row_html = record_row |> render()
assert record_row_html =~ escape(record.title)
assert record_row_html =~ to_string(record.release)
assert record_row_html =~ Record.format_long_label(record.format)
assert record_row_html =~ Record.type_long_label(record.type)
assert record_row_html =~ record.release
assert record_row_html =~ ~p"/covers/#{record.id}?vsn=#{record.cover_hash}"
for artist <- record.artists do
assert record_row_html =~ escape(artist.name)
end
end
end
end
describe "Search and pagination" do
setup [:fill_collection]
test "uses query string params", %{conn: conn, collection: records} do
{:ok, page_2_live, page_2_html} = live(conn, ~p"/records?page=2&page_size=25")
{page_2_present, page_2_absent} =
Enum.split_with(records, fn record ->
page_2_html =~ record.id
end)
assert length(page_2_present) == 25
assert length(page_2_absent) == @total_records - 25
page_2_pagination = page_2_live |> with_target("#pagination")
refute has_element?(page_2_pagination, "a", "2")
assert has_element?(page_2_pagination, "a", "1")
assert has_element?(page_2_pagination, "a", "3")
assert has_element?(page_2_pagination, "a", "4")
assert has_element?(page_2_pagination, "a", "5")
{:ok, page_3_live, page_3_html} = live(conn, ~p"/records?page=3&page_size=25")
{page_3_present, page_3_absent} =
Enum.split_with(records, fn record ->
page_3_html =~ record.id
end)
assert length(page_3_present) == 25
assert length(page_3_absent) == @total_records - 25
page_3_pagination = page_3_live |> with_target("#pagination")
refute has_element?(page_3_pagination, "a", "3")
assert has_element?(page_3_pagination, "a", "1")
assert has_element?(page_3_pagination, "a", "2")
assert has_element?(page_3_pagination, "a", "4")
assert has_element?(page_3_pagination, "a", "5")
# All records in page 3 were not present in page 2
assert page_3_present -- page_2_absent == []
# All records in page 2 are not present in page 3
assert page_2_present -- page_3_absent == []
end
end
describe "Tagged search" do
setup [:fill_collection]
test "supports raw queries", %{conn: conn, collection: records} do
[record | _rest] = records
qs = [query: record.title]
{:ok, index_live, _html} = live(conn, ~p"/records?#{qs}")
record_row =
index_live
|> with_target("#records-#{record.id}")
record_row_html = record_row |> render()
assert record_row_html =~ escape(record.title)
assert record_row_html =~ to_string(record.release)
assert record_row_html =~ Record.format_long_label(record.format)
assert record_row_html =~ Record.type_long_label(record.type)
assert record_row_html =~ record.release
assert record_row_html =~ ~p"/covers/#{record.id}?vsn=#{record.cover_hash}"
for artist <- record.artists do
assert record_row_html =~ escape(artist.name)
end
end
test "supports filters", %{conn: conn, collection: records} do
{artist_with_most_records, _records_count} =
records
|> Enum.frequencies_by(fn r ->
[artist] = r.artists
artist.name
end)
|> Enum.max_by(fn {_artist, count} -> count end)
{present, absent} =
Enum.split_with(records, fn r ->
[artist] = r.artists
artist.name == artist_with_most_records
end)
qs = [
query: ~s(artist:"#{artist_with_most_records}"),
page_size: @default_records_page_size
]
{:ok, index_live, _html} = live(conn, ~p"/records?#{qs}")
for record <- present do
record_row =
index_live
|> with_target("#records-#{record.id}")
record_row_html = record_row |> render()
assert record_row_html =~ escape(record.title)
assert record_row_html =~ to_string(record.release)
assert record_row_html =~ Record.format_long_label(record.format)
assert record_row_html =~ Record.type_long_label(record.type)
assert record_row_html =~ record.release
assert record_row_html =~ ~p"/covers/#{record.id}?vsn=#{record.cover_hash}"
for artist <- record.artists do
assert record_row_html =~ escape(artist.name)
end
end
for record <- absent do
refute has_element?(index_live, "#records-#{record.id}")
end
end
end
describe "Updating record metadata" do
test "can navigate to the record edit form", %{conn: conn} do
record = record_fixture()
{:ok, index_live, _html} = live(conn, ~p"/records")
assert index_live
|> element("#records-#{record.id} a", "Edit")
|> render_click() =~ "Edit"
assert_patch(index_live, ~p"/records/#{record}/edit")
assert index_live |> render() =~ "Edit"
end
test "can change the record cover", %{conn: conn} do
record = record_fixture(cover_data: File.read!(marbles_cover_fixture()))
{:ok, form_live, html} = live(conn, ~p"/records/#{record.id}/edit")
assert html =~ ~p"/covers/#{record.id}?vsn=#{record.cover_hash}"
cover_metadata = cover_metadata(raven_cover_fixture())
cover_input = file_input(form_live, "#record-form", :cover_data, [cover_metadata])
assert render_upload(cover_input, cover_metadata.name) =~ "100%"
list_html = form_live |> element("#record-form") |> render_submit()
assert list_html =~ "Record updated successfully"
# We trigger another render to force the list view to update
# and display the new cover
list_html = form_live |> render()
updated_cover = MusicLibrary.Records.get_cover(record.id)
assert updated_cover.cover_hash !== record.cover_hash
assert list_html =~ ~p"/covers/#{record.id}?vsn=#{updated_cover.cover_hash}"
end
defp cover_metadata(path) do
stat = File.stat!(path)
%{
last_modified:
stat.mtime
|> NaiveDateTime.from_erl!()
|> DateTime.from_naive!("Etc/UTC")
|> DateTime.to_unix(),
name: Path.basename(path),
content: File.read!(path),
size: stat.size,
type: "image/jpeg"
}
end
end
describe "Importing a new record" do
test "it shows the import modal", %{conn: conn} do
{:ok, index_live, _html} = live(conn, ~p"/records")
import_dialog =
index_live
|> element("a", "Import")
|> render_click()
assert import_dialog =~ "Search for a record on MusicBrainz"
assert import_dialog =~ "No results"
assert_patch(index_live, ~p"/records/import")
end
test "it imports a record when selected", %{conn: conn} do
{:ok, import_live, _html} = live(conn, ~p"/records/import")
mock_results = release_group_search_results()
expect(APIBehaviourMock, :search_release_group, fn "Marillion Marbles",
limit: 10,
offset: 0 ->
{:ok, mock_results}
end)
assert import_live
|> element("#import_form")
|> render_change(%{mb_query: "Marillion Marbles"})
updated_list = import_live |> render()
for result <- mock_results do
assert updated_list =~ result.title
assert updated_list =~ Record.format_release(result.release)
assert updated_list =~ result.artists
end
first_result = hd(mock_results)
first_result_id = first_result.id
release_group = release_group()
expect(APIBehaviourMock, :get_release_group, fn ^first_result_id ->
{:ok, release_group}
end)
cover_data = File.read!(marbles_cover_fixture())
expect(APIBehaviourMock, :get_cover_art, fn {:musicbrainz_id, ^first_result_id} ->
{:ok, cover_data}
end)
import_live
|> element("#musicbrainz_#{first_result_id} a", "CD")
|> render_click()
[record] = MusicLibrary.Repo.all(MusicLibrary.Records.Record)
assert record.musicbrainz_id == first_result_id
assert record.title == "Marbles"
assert record.release == "2004-05-03"
assert record.format == :cd
assert record.musicbrainz_data == release_group
assert record.genres == [
"alternative rock",
"art rock",
"baroque pop",
"pop rock",
"progressive rock",
"psychedelic pop",
"rock"
]
assert record.cover_hash ==
"599407DDF69907D4A60FE13CCAA824D25CF08DC124FD6AA3E8E7ECD98C885FFE"
assert record.cover_data == cover_data
assert record.inserted_at !== nil
assert record.updated_at !== nil
assert record.purchased_at !== nil
[marillion] = record.artists
assert %MusicLibrary.Records.Record.Artist{
id: _,
name: "Marillion",
sort_name: "Marillion",
disambiguation: "British progressive rock band",
musicbrainz_id: "1932f5b6-0b7b-4050-b1df-833ca89e5f44"
} = marillion
assert_redirect(import_live, ~p"/records/#{record.id}")
end
end
end
@@ -0,0 +1,52 @@
defmodule MusicLibraryWeb.CollectionLive.ShowTest do
use MusicLibraryWeb.ConnCase
import Phoenix.LiveViewTest
import MusicLibrary.RecordsFixtures
alias MusicLibrary.Records.Record
defp escape(string) do
string
|> Phoenix.HTML.html_escape()
|> Phoenix.HTML.safe_to_string()
end
defp human_datetime(dt) do
"#{dt.day}/#{dt.month}/#{dt.year}"
end
describe "Edit record from show page" do
test "can navigate to the record edit form", %{conn: conn} do
record = record_fixture()
{:ok, show_live, _html} = live(conn, ~p"/records/#{record.id}")
assert show_live
|> element("a", "Edit")
|> render_click() =~ "Edit"
assert_patch(show_live, ~p"/records/#{record}/show/edit")
end
end
describe "Show record" do
test "it includes all needed information", %{conn: conn} do
record = record_fixture()
{:ok, _show_live, html} = live(conn, ~p"/records/#{record.id}")
assert html =~ escape(record.title)
assert html =~ to_string(record.release)
assert html =~ Record.format_long_label(record.format)
assert html =~ record.release
assert html =~ ~p"/covers/#{record.id}?vsn=#{record.cover_hash}"
assert html =~ human_datetime(record.purchased_at)
assert html =~ human_datetime(record.inserted_at)
assert html =~ human_datetime(record.updated_at)
for artist <- record.artists do
assert html =~ escape(artist.name)
end
end
end
end