ML-188: guard PubSub record updates during edit mode
Add live_action guard to handle_info({:update, record}) in both
CollectionLive.Show and WishlistLive.Show. When the user is editing,
background worker updates are skipped and a warning toast is shown
instead of overwriting the socket. Normal show-mode updates and
mismatched-ID no-ops are unchanged.
6 tests added covering all three code paths.
This commit is contained in:
@@ -7,6 +7,7 @@ defmodule MusicLibraryWeb.CollectionLive.ShowTest do
|
||||
alias MusicBrainz.Fixtures
|
||||
alias MusicLibrary.Assets.Transform
|
||||
alias MusicLibrary.Records.Record
|
||||
alias Phoenix.PubSub
|
||||
|
||||
describe "Edit record from show page" do
|
||||
test "can navigate to the record edit form", %{conn: conn} do
|
||||
@@ -68,6 +69,93 @@ defmodule MusicLibraryWeb.CollectionLive.ShowTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "handle_info({:update, record}) with live_action guard" do
|
||||
test "updates record when showing (live_action is :show)", %{conn: conn} do
|
||||
record = record()
|
||||
|
||||
release_response = Fixtures.Release.release(:marbles)
|
||||
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Req.Test.json(conn, release_response)
|
||||
end)
|
||||
|
||||
updated_record = %{record | title: "Background Updated Title"}
|
||||
|
||||
session =
|
||||
conn
|
||||
|> visit(~p"/collection/#{record.id}")
|
||||
|> render_async()
|
||||
|
||||
PubSub.broadcast(
|
||||
MusicLibrary.PubSub,
|
||||
"records:#{record.id}",
|
||||
{:update, updated_record}
|
||||
)
|
||||
|
||||
session
|
||||
|> assert_has("*", text: "Background Updated Title", timeout: 200)
|
||||
|> assert_has("#toast-group", text: "Record updated in the background")
|
||||
end
|
||||
|
||||
test "skips update when editing and shows warning toast", %{conn: conn} do
|
||||
record = record()
|
||||
|
||||
release_response = Fixtures.Release.release(:marbles)
|
||||
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Req.Test.json(conn, release_response)
|
||||
end)
|
||||
|
||||
updated_record = %{record | title: "Should Not Appear"}
|
||||
|
||||
session =
|
||||
conn
|
||||
|> visit(~p"/collection/#{record.id}")
|
||||
|> render_async()
|
||||
|> click_link("Edit")
|
||||
|
||||
PubSub.broadcast(
|
||||
MusicLibrary.PubSub,
|
||||
"records:#{record.id}",
|
||||
{:update, updated_record}
|
||||
)
|
||||
|
||||
session
|
||||
|> refute_has("h2", text: "Should Not Appear")
|
||||
|> assert_has(
|
||||
"#toast-group",
|
||||
text:
|
||||
"Record was updated in the background. Your edits may be stale — save and re-open to see the latest data."
|
||||
)
|
||||
end
|
||||
|
||||
test "no-ops when broadcasted record has mismatched ID", %{conn: conn} do
|
||||
record = record()
|
||||
other_record = record()
|
||||
|
||||
release_response = Fixtures.Release.release(:marbles)
|
||||
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Req.Test.json(conn, release_response)
|
||||
end)
|
||||
|
||||
session =
|
||||
conn
|
||||
|> visit(~p"/collection/#{record.id}")
|
||||
|> render_async()
|
||||
|
||||
PubSub.broadcast(
|
||||
MusicLibrary.PubSub,
|
||||
"records:#{record.id}",
|
||||
{:update, other_record}
|
||||
)
|
||||
|
||||
session
|
||||
|> assert_has("h2", text: escape(record.title))
|
||||
|> refute_has("#toast-group", text: "Record updated in the background")
|
||||
end
|
||||
end
|
||||
|
||||
describe "Side panel" do
|
||||
test "shows a record's tracks", %{conn: conn} do
|
||||
record = record()
|
||||
|
||||
@@ -6,6 +6,7 @@ defmodule MusicLibraryWeb.WishlistLive.ShowTest do
|
||||
|
||||
alias MusicLibrary.Assets.Transform
|
||||
alias MusicLibrary.Records.Record
|
||||
alias Phoenix.PubSub
|
||||
|
||||
describe "Edit record from show page" do
|
||||
test "can navigate to the record edit form", %{conn: conn} do
|
||||
@@ -51,4 +52,68 @@ defmodule MusicLibraryWeb.WishlistLive.ShowTest do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "handle_info({:update, record}) with live_action guard" do
|
||||
test "updates record when showing (live_action is :show)", %{conn: conn} do
|
||||
record = record(purchased_at: nil)
|
||||
updated_record = %{record | title: "Background Updated Title"}
|
||||
|
||||
session =
|
||||
conn
|
||||
|> visit(~p"/wishlist/#{record.id}")
|
||||
|
||||
PubSub.broadcast(
|
||||
MusicLibrary.PubSub,
|
||||
"records:#{record.id}",
|
||||
{:update, updated_record}
|
||||
)
|
||||
|
||||
session
|
||||
|> assert_has("*", text: "Background Updated Title", timeout: 200)
|
||||
|> assert_has("#toast-group", text: "Record updated in the background")
|
||||
end
|
||||
|
||||
test "skips update when editing and shows warning toast", %{conn: conn} do
|
||||
record = record(purchased_at: nil)
|
||||
updated_record = %{record | title: "Should Not Appear"}
|
||||
|
||||
session =
|
||||
conn
|
||||
|> visit(~p"/wishlist/#{record.id}")
|
||||
|> click_link("Edit")
|
||||
|
||||
PubSub.broadcast(
|
||||
MusicLibrary.PubSub,
|
||||
"records:#{record.id}",
|
||||
{:update, updated_record}
|
||||
)
|
||||
|
||||
session
|
||||
|> refute_has("h2", text: "Should Not Appear")
|
||||
|> assert_has(
|
||||
"#toast-group",
|
||||
text:
|
||||
"Record was updated in the background. Your edits may be stale — save and re-open to see the latest data."
|
||||
)
|
||||
end
|
||||
|
||||
test "no-ops when broadcasted record has mismatched ID", %{conn: conn} do
|
||||
record = record(purchased_at: nil)
|
||||
other_record = record(purchased_at: nil)
|
||||
|
||||
session =
|
||||
conn
|
||||
|> visit(~p"/wishlist/#{record.id}")
|
||||
|
||||
PubSub.broadcast(
|
||||
MusicLibrary.PubSub,
|
||||
"records:#{record.id}",
|
||||
{:update, other_record}
|
||||
)
|
||||
|
||||
session
|
||||
|> assert_has("h2", text: escape(record.title))
|
||||
|> refute_has("#toast-group", text: "Record updated in the background")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user