import { describe, expect, it } from "vitest"; import { provenanceTemplateLanguages, whyTemplateLanguages, buildWhy, type RecommendationCandidate, type RecommendationContext, type ProvenanceEntry, } from "../src/index.js"; const EXPECTED_LANGS = [ "sv", "en", "es", "it", "de", "fr", "da", "nb", "fi", "nl", "pl", "pt", ]; const fullCoverage = { coverage: 1, matches: [], missing: [], expiringUsed: [] }; const nutrition = { kcal: 550, proteinG: 45, carbsG: 50, fatG: 18, saturatedFatG: 6, fiberG: 6, sugarG: 4, saltG: 1.5, }; function candidate(overrides: Partial = {}): RecommendationCandidate { return { recipeId: "r1", titleSv: "Kycklinggryta", cuisine: "swedish", tags: [], totalTimeMinutes: 30, nutritionPerPortion: nutrition, estimatedCostMinorPerPortion: 2200, ratingAverage: null, ratingCount: 0, peakSeasons: [], holidayTags: [], spiceLevel: 1, coverage: fullCoverage, ...overrides, }; } const ctx: RecommendationContext = { mealType: "dinner", persons: 4, currentSeason: "summer", activeHolidayTags: [], isWeekday: true, favoriteCuisines: ["swedish"], remainingProteinG: 60, remainingKcal: 800, personalizationEnabled: false, }; describe("S6 i18n-paritet", () => { it("provenansmallarna täcker exakt 12 språk utan dubbletter", () => { const langsByTemplate = provenanceTemplateLanguages(); expect(Object.keys(langsByTemplate).length).toBeGreaterThan(0); for (const [key, langs] of Object.entries(langsByTemplate)) { expect(langs.length, `mall ${key} har dubbletter eller saknar språk`).toBe(EXPECTED_LANGS.length); expect(new Set(langs).size, `mall ${key} har dubbletter`).toBe(EXPECTED_LANGS.length); for (const lang of EXPECTED_LANGS) { expect(langs).toContain(lang); } } }); it("why-mallarna täcker exakt 12 språk utan dubbletter", () => { const langs = whyTemplateLanguages(); expect(langs.length).toBe(EXPECTED_LANGS.length); expect(new Set(langs).size).toBe(EXPECTED_LANGS.length); for (const lang of EXPECTED_LANGS) { expect(langs).toContain(lang); } }); it("buildWhy renderar på rätt språk för varje supporterat språk", () => { const provenance: ProvenanceEntry[] = [ { key: "favoriteCuisine", args: { cuisine: "svensk" } }, ]; for (const lang of EXPECTED_LANGS) { const why = buildWhy(candidate(), { ...ctx, personalizationEnabled: true }, { coverage: 1, expiry: 0, nutritionFit: 0.9, taste: 0.5, rating: 0.5, season: 0, holiday: 0, time: 0, budget: 0, variety: 0.5, weather: 0.5, craving: 0.5, memoryFit: 1, tasteFit: 0, cookingAssumptionFit: 0 }, provenance, `${lang}-XX`); expect(why.length, `tom why för ${lang}`).toBeGreaterThan(0); // Ingen why får falla tillbaka på svenska fallback om språket finns. if (lang !== "sv") { expect(why).not.toBe("En balanserad rätt som passar er profil."); } } }); });