S6: i18n-paritet, provenans + eval, copy-skanning, fabricerade-minnes-eval
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
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.");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user