test: add recommendation rationale coverage
This commit is contained in:
@@ -74,6 +74,47 @@ func TestScoreRecommendationCandidateRewardsProfileOverlap(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestScoreRecommendationCandidateBuildsRationaleFromProfileMatches(t *testing.T) {
|
||||
now := time.Date(2026, time.June, 4, 12, 0, 0, 0, time.UTC)
|
||||
profile := userTasteProfile{
|
||||
genres: map[int]float64{1: 2.0},
|
||||
themes: map[int]float64{10: 1.5},
|
||||
studios: map[int]float64{20: 1.0},
|
||||
demographics: map[int]float64{30: 1.0},
|
||||
}
|
||||
|
||||
candidate := scoreRecommendationCandidate(now, profile, jikan.Anime{
|
||||
MalID: 10,
|
||||
Genres: []jikan.NamedEntity{{MalID: 1, Name: "Action"}},
|
||||
Themes: []jikan.NamedEntity{{MalID: 10, Name: "School"}},
|
||||
Studios: []jikan.NamedEntity{{MalID: 20, Name: "Production I.G"}},
|
||||
Demographics: []jikan.NamedEntity{{MalID: 30, Name: "Shounen"}},
|
||||
}, 5.0, 0)
|
||||
|
||||
want := []string{"Action", "School", "Production I.G", "Shounen"}
|
||||
if !slices.Equal(candidate.rationale, want) {
|
||||
t.Fatalf("expected profile match rationale %v, got %v", want, candidate.rationale)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScoreRecommendationCandidateOmitsRationaleWhenSignalsAreWeak(t *testing.T) {
|
||||
now := time.Date(2026, time.June, 4, 12, 0, 0, 0, time.UTC)
|
||||
profile := userTasteProfile{
|
||||
genres: map[int]float64{1: 2.0},
|
||||
themes: map[int]float64{},
|
||||
studios: map[int]float64{},
|
||||
demographics: map[int]float64{},
|
||||
}
|
||||
|
||||
candidate := scoreRecommendationCandidate(now, profile, jikan.Anime{
|
||||
MalID: 10,
|
||||
}, 5.0, 0)
|
||||
|
||||
if len(candidate.rationale) != 0 {
|
||||
t.Fatalf("expected no rationale for weak signals, got %v", candidate.rationale)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildTasteProfileUsesSeedWeights(t *testing.T) {
|
||||
now := time.Date(2026, time.June, 4, 12, 0, 0, 0, time.UTC)
|
||||
|
||||
|
||||
@@ -107,6 +107,37 @@ func TestRenderWithNonStringFragment(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTopPicksTemplateRendersRecommendationRationale(t *testing.T) {
|
||||
r, err := ProvideRenderer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = r.ExecuteFragment(&buf, "top_picks.gohtml", "content", map[string]any{
|
||||
"Animes": []domain.Anime{
|
||||
{
|
||||
Anime: jikan.Anime{
|
||||
MalID: 1,
|
||||
Title: "Haikyuu!!",
|
||||
},
|
||||
RecommendationRationale: []string{"Sports", "Production I.G"},
|
||||
},
|
||||
},
|
||||
"WatchlistMap": map[int64]bool{},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("ExecuteFragment error: %v", err)
|
||||
}
|
||||
|
||||
body := buf.String()
|
||||
for _, want := range []string{"Why this was picked", "Sports", "Production I.G"} {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Fatalf("top picks template missing %q in output:\n%s", want, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWatchTemplateEscapesJSONDataAttributes(t *testing.T) {
|
||||
r, err := ProvideRenderer()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user