114 lines
3.2 KiB
TypeScript
114 lines
3.2 KiB
TypeScript
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> = {}): 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.");
|
|
}
|
|
}
|
|
});
|
|
});
|