Files
minstrel/internal/notifications/render_test.go
T
bvandeusenandClaude Opus 5.5 854c307834
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m33s
release / android (push) Failing after 1m42s
release / integration (push) Failing after 4m42s
release / Build signed APK (releases and dev) (push) Successful in 4m55s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
feat: notifications say what changed and alert once: a grouped notice names the tracks, grows without re-alerting, and a phone pile lists its titles (M542 #6146-#6151)
- An update to a grouped notice keeps its arrival time and email state, so the
  phone and the email no longer go off again each time it grows.
- Notices carry the names of what changed (newest ten), shown as three and
  "and N more": tracks still missing after the scan's move/replacement fold,
  duplicate groups new to a sweep, songs merged automatically, and the track
  and listener a playback error was for.
- Duplicates found counts only the groups new to that sweep; playback errors
  count reports, not the unresolved total.
- A scan failure says what stopped and links to Admin > Library.
- Android: a pile of more than three alerts lists the newest five titles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:44:19 -04:00

87 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package notifications
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
// render stores p the way Notify does (through Map) and reads it back.
func render(k Kind, p Payload) Rendered {
b, err := json.Marshal(p.Map())
if err != nil {
panic(err)
}
return Render(k, b)
}
func TestRender_EveryKindHasATitleAndALink(t *testing.T) {
for _, k := range Kinds() {
r := Render(k, []byte(`{}`))
require.NotEmpty(t, r.Title, k)
require.NotEqual(t, "Notification", r.Title, "%s falls through to the default", k)
require.NotEmpty(t, r.Link, k)
}
}
func TestRender_RequestCompletedLinksToWhatArrived(t *testing.T) {
require.Equal(t, "/albums/al-1", render(KindRequestCompleted, Payload{Name: "WWW", AlbumID: "al-1", ArtistID: "ar-1"}).Link)
require.Equal(t, "/artists/ar-1", render(KindRequestCompleted, Payload{Name: "Moe Shop", ArtistID: "ar-1"}).Link)
require.Equal(t, "/requests", render(KindRequestCompleted, Payload{Name: "WWW"}).Link)
require.Equal(t, "WWW has arrived.", render(KindRequestCompleted, Payload{Name: "WWW"}).Body)
}
func TestRender_RejectionCarriesTheReasonWhenThereIsOne(t *testing.T) {
require.Equal(t, "WWW was declined.", render(KindRequestRejected, Payload{Name: "WWW"}).Body)
require.Equal(t, "WWW was declined: already owned", render(KindRequestRejected, Payload{Name: "WWW", Reason: "already owned"}).Body)
}
func TestRender_CoalescedCountsReadNaturally(t *testing.T) {
require.Equal(t, "1 track went missing", render(KindTracksMissing, Payload{Count: 1}).Title)
require.Equal(t, "14 tracks went missing", render(KindTracksMissing, Payload{Count: 14}).Title)
require.Equal(t, "Library scan failed", render(KindScanFailed, Payload{Count: 1, Detail: "x"}).Title)
require.Equal(t, "Library scan failed 3 times", render(KindScanFailed, Payload{Count: 3}).Title)
require.Equal(t, "Some tracks went missing", Render(KindTracksMissing, []byte(`{}`)).Title)
}
// M542: a notice says which, not only how many.
func TestRender_NamesWhatChanged(t *testing.T) {
require.Equal(t, "No longer on disk: Weezer – Buddy Holly.",
render(KindTracksMissing, Payload{Count: 1, Items: []string{"Weezer – Buddy Holly"}}).Body)
require.Equal(t, "No longer on disk: A – 1 and B – 2.",
render(KindTracksMissing, Payload{Count: 2, Items: []string{"A – 1", "B – 2"}}).Body)
// Three are named; the rest of the count, not only the rest of the
// stored names, is "more".
require.Equal(t, "Held more than once: A, B, C and 9 more.",
render(KindDuplicatesFound, Payload{Count: 12, Items: []string{"A", "B", "C", "D", "E"}}).Body)
require.Equal(t, "12 new duplicates to review", render(KindDuplicatesFound, Payload{Count: 12}).Title)
require.Equal(t, "Extra copies merged into the one the album keeps: A and B.",
render(KindDuplicatesResolved, Payload{Count: 2, Items: []string{"A", "B"}}).Body)
require.Equal(t, "Failed to play: Weezer – Buddy Holly (alice).",
render(KindPlaybackErrors, Payload{Count: 1, Items: []string{"Weezer – Buddy Holly (alice)"}}).Body)
}
func TestRender_RowsFromBeforeItemsReadAsTheyDid(t *testing.T) {
require.Equal(t, "Their files are no longer where the library expects them.",
render(KindTracksMissing, Payload{Count: 4}).Body)
require.Equal(t, "Merged 8 duplicate copies.",
render(KindDuplicatesResolved, Payload{Count: 716, Detail: "Merged 8 duplicate copies."}).Body)
}
func TestRender_AScanFailureSaysWhatStopped(t *testing.T) {
r := render(KindScanFailed, Payload{Count: 1, Detail: "scan root \"/music\" unavailable"})
require.Equal(t, `The last scan stopped: scan root "/music" unavailable`, r.Body)
require.Equal(t, "/admin/library", r.Link)
}
func TestRender_AnUnreadablePayloadStillRenders(t *testing.T) {
r := Render(KindRequestApproved, []byte(`not json`))
require.Equal(t, "Request approved", r.Title)
require.Equal(t, "Your request is on its way.", r.Body)
}
func TestPayloadMap_DropsEmptyFields(t *testing.T) {
require.Equal(t, map[string]any{"name": "WWW", "count": float64(2)}, Payload{Name: "WWW", Count: 2}.Map())
}