import { describe, it, expect } from "vitest"; import { prisma } from "@/lib/db"; import { GET } from "./route"; describe("discover feed API", () => { it("groups pending suggestions into artist rows with their albums, highest score first", async () => { await prisma.discoverySuggestion.createMany({ data: [ { kind: "artist", artistMbid: "a1", artistName: "Low", score: 0.2, seedCount: 1, sources: ["listenbrainz"], secondaryTypes: [], dedupeKey: "artist:a1:" }, { kind: "artist", artistMbid: "a2", artistName: "High", score: 0.9, seedCount: 2, sources: ["listenbrainz"], secondaryTypes: [], dedupeKey: "artist:a2:" }, { kind: "album", artistMbid: "a2", artistName: "High", rgMbid: "rg-new", album: "Latest", firstReleaseDate: "2022-01-01", albumReason: "newest", score: 0.9, seedCount: 2, sources: ["listenbrainz"], secondaryTypes: [], dedupeKey: "album:a2:rg-new" }, { kind: "album", artistMbid: "a2", artistName: "High", rgMbid: "rg-hit", album: "Big Hit", firstReleaseDate: "2018-01-01", albumReason: "popular", score: 0.9, seedCount: 2, sources: ["listenbrainz"], secondaryTypes: [], dedupeKey: "album:a2:rg-hit" }, { kind: "artist", artistMbid: "a3", artistName: "Gone", score: 5, seedCount: 1, sources: ["listenbrainz"], secondaryTypes: [], status: "dismissed", dedupeKey: "artist:a3:" }, ], }); const body = await (await GET()).json(); expect(body.rows.map((r: { artistName: string }) => r.artistName)).toEqual(["High", "Low"]); // dismissed excluded, score desc const high = body.rows[0]; expect(high).toMatchObject({ id: expect.any(String), artistMbid: "a2", seedCount: 2 }); // albums sorted newest-first, each carrying its reason expect(high.albums.map((a: { album: string; albumReason: string }) => [a.album, a.albumReason])) .toEqual([["Latest", "newest"], ["Big Hit", "popular"]]); expect(body.rows[1].albums).toEqual([]); // "Low" has no album suggestions }); it("yields a row for an album whose artist has no pending artist suggestion", async () => { await prisma.discoverySuggestion.create({ data: { kind: "album", artistMbid: "orphan", artistName: "Orphan Band", rgMbid: "rgX", album: "Stray", albumReason: "newest", score: 0.4, seedCount: 1, sources: ["lastfm"], secondaryTypes: [], dedupeKey: "album:orphan:rgX" }, }); const body = await (await GET()).json(); expect(body.rows).toHaveLength(1); expect(body.rows[0]).toMatchObject({ id: null, artistName: "Orphan Band" }); expect(body.rows[0].albums[0].album).toBe("Stray"); }); it("annotates rows with the followed-artist seeds that surfaced them", async () => { await prisma.watchedArtist.createMany({ data: [{ mbid: "seed-am", name: "Arctic Monkeys" }, { mbid: "seed-cp", name: "Coldplay" }], }); await prisma.discoverySuggestion.create({ data: { kind: "artist", artistMbid: "cand1", artistName: "The Strokes", score: 0.9, seedCount: 2, sources: ["listenbrainz"], secondaryTypes: [], dedupeKey: "artist:cand1:" }, }); await prisma.discoverySeedContribution.createMany({ data: [ { candidateMbid: "cand1", candidateName: "The Strokes", seedMbid: "seed-am", score: 0.6, sources: ["listenbrainz"] }, { candidateMbid: "cand1", candidateName: "The Strokes", seedMbid: "seed-cp", score: 0.3, sources: ["listenbrainz"] }, { candidateMbid: "cand1", candidateName: "The Strokes", seedMbid: "gone", score: 0.9, sources: ["listenbrainz"] }, ], }); const body = await (await GET()).json(); expect(body.rows[0].seeds).toEqual(["Arctic Monkeys", "Coldplay"]); // score desc, unfollowed dropped }); });