import { describe, it, expect } from "vitest"; import { buildPreferenceMap, scoreCandidate, rankForYou } from "../for-you-ranking"; describe("buildPreferenceMap", () => { it("counts tags and true dietary-tag keys across liked recipes", () => { const map = buildPreferenceMap([ { tags: ["spicy", "quick"], dietaryTags: { vegan: true, glutenFree: false } }, { tags: ["spicy"], dietaryTags: null }, ]); expect(map.get("spicy")).toBe(2); expect(map.get("quick")).toBe(1); expect(map.get("vegan")).toBe(1); expect(map.get("glutenFree")).toBeUndefined(); }); it("returns an empty map for no liked recipes", () => { expect(buildPreferenceMap([]).size).toBe(0); }); }); describe("scoreCandidate", () => { it("sums preference weights for overlapping tags", () => { const prefs = new Map([["spicy", 3], ["vegan", 1]]); const score = scoreCandidate({ tags: ["spicy"], dietaryTags: { vegan: true } }, prefs); expect(score).toBe(4); }); it("scores 0 when nothing overlaps", () => { const prefs = new Map([["spicy", 3]]); expect(scoreCandidate({ tags: ["sweet"], dietaryTags: null }, prefs)).toBe(0); }); }); describe("rankForYou", () => { const base = { dietaryTags: null }; it("sorts by score descending", () => { const prefs = new Map([["spicy", 5]]); const candidates = [ { id: "a", tags: ["sweet"], createdAt: new Date("2024-01-01"), ...base }, { id: "b", tags: ["spicy"], createdAt: new Date("2024-01-01"), ...base }, ]; const ranked = rankForYou(candidates, prefs); expect(ranked.map((r) => r.id)).toEqual(["b", "a"]); }); it("breaks ties by recency", () => { const prefs = new Map(); const candidates = [ { id: "old", tags: [], createdAt: new Date("2024-01-01"), ...base }, { id: "new", tags: [], createdAt: new Date("2024-06-01"), ...base }, ]; const ranked = rankForYou(candidates, prefs); expect(ranked.map((r) => r.id)).toEqual(["new", "old"]); }); });