reference-seed-data.ts reste rédigé en français (c'est juste le libellé
d'autoring, jamais stocké/exposé), mais la clé stable (`Diet.key`/
`Category.key`/`Ingredient.key`) qu'on en dérive doit elle-même être un
identifiant anglais, indépendant de la langue d'autoring — pas juste le
même texte français passé à slugify().
- apps/api/src/db/catalog-en-keys.ts : dictionnaire écrit à la main
(label français -> clé anglaise) pour les 5 régimes, 14 allergènes et
437 ingrédients ; getEnglishKey() lève une erreur explicite si un
nouvel élément n'a pas encore d'entrée plutôt que de retomber sur un
slug français silencieux.
- scripts/validate-catalog-en-keys.ts : vérifie que chaque diet/allergène/
ingrédient de reference-seed-data.ts a une entrée, et que les clés
anglaises résultantes sont uniques (437/437, 14/14, 5/5 — zéro manquant,
zéro collision).
- reference-seed-data.ts et scripts/generate-catalog-i18n.ts utilisent
désormais getEnglishKey() au lieu de slugify(nom français).
- Nouvelle migration (20260818193000_catalog_keys_to_english) qui
remappe les lignes déjà seedées avec un slug français (par la migration
précédente) vers leur clé anglaise définitive.
- apps/web/src/locales/fr/translation.json régénéré : catalog.* est
maintenant indexé par clé anglaise ("vegetarian", "eggs",
"ground_beef"...), toujours avec le libellé français en valeur.
- Tests/step-definitions mis à jour (getEnglishKey() au lieu de
slugify()) ; 102 tests Mocha + 32 scénarios Cucumber passent contre la
base migrée. Vérifié aussi en direct via GET /reference/diets et
/reference/allergies.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
81 lines
2.9 KiB
TypeScript
81 lines
2.9 KiB
TypeScript
import { expect } from "chai";
|
|
import request from "supertest";
|
|
import { createApp } from "../src/app.js";
|
|
import { prisma } from "../src/db/prisma.js";
|
|
import { resetDatabase } from "../test-support/reset-db.js";
|
|
import { getEnglishKey } from "../src/db/catalog-en-keys.js";
|
|
|
|
describe("Reference data", () => {
|
|
const app = createApp();
|
|
|
|
beforeEach(async () => {
|
|
await resetDatabase();
|
|
});
|
|
|
|
after(async () => {
|
|
await prisma.$disconnect();
|
|
});
|
|
|
|
describe("GET /reference/diets", () => {
|
|
it("returns the seeded regimes, no session required", async () => {
|
|
const res = await request(app).get("/reference/diets");
|
|
|
|
expect(res.status).to.equal(200);
|
|
expect(res.body).to.have.length(5);
|
|
expect(res.body.map((d: { key: string }) => d.key)).to.include(getEnglishKey("Végétarien"));
|
|
expect(res.body[0]).to.have.keys(["id", "key"]);
|
|
});
|
|
});
|
|
|
|
describe("GET /reference/allergies", () => {
|
|
it("returns the seeded allergens with their key resolved, no session required", async () => {
|
|
const res = await request(app).get("/reference/allergies");
|
|
|
|
expect(res.status).to.equal(200);
|
|
expect(res.body).to.have.length(14);
|
|
expect(res.body.map((a: { key: string }) => a.key)).to.include(getEnglishKey("Arachides"));
|
|
expect(res.body[0]).to.have.keys(["id", "key", "kind"]);
|
|
});
|
|
|
|
it("classifies Gluten and Sulfites as intolerances, the rest as allergies", async () => {
|
|
const res = await request(app).get("/reference/allergies");
|
|
|
|
const byKey = (name: string) =>
|
|
res.body.find((a: { key: string }) => a.key === getEnglishKey(name));
|
|
expect(byKey("Gluten").kind).to.equal("INTOLERANCE");
|
|
expect(byKey("Sulfites").kind).to.equal("INTOLERANCE");
|
|
expect(byKey("Arachides").kind).to.equal("ALLERGY");
|
|
expect(res.body.filter((a: { kind: string }) => a.kind === "INTOLERANCE")).to.have.length(2);
|
|
});
|
|
});
|
|
|
|
describe("GET /reference/ingredients", () => {
|
|
it("returns the seeded ingredients, no session required", async () => {
|
|
const res = await request(app).get("/reference/ingredients");
|
|
|
|
expect(res.status).to.equal(200);
|
|
expect(res.body.length).to.be.greaterThan(0);
|
|
expect(res.body.map((i: { key: string }) => i.key)).to.include(getEnglishKey("Tomate"));
|
|
expect(res.body[0]).to.have.keys([
|
|
"id",
|
|
"key",
|
|
"icon",
|
|
"category",
|
|
"subcategory",
|
|
"allergens",
|
|
"diets",
|
|
]);
|
|
});
|
|
|
|
it("resolves each ingredient's linked allergens, empty for one with none", async () => {
|
|
const res = await request(app).get("/reference/ingredients");
|
|
|
|
const byKey = (name: string) =>
|
|
res.body.find((i: { key: string }) => i.key === getEnglishKey(name));
|
|
expect(byKey("Œuf").allergens.map((a: { key: string }) => a.key)).to.include(
|
|
getEnglishKey("Œufs"),
|
|
);
|
|
expect(byKey("Tomate").allergens).to.deep.equal([]);
|
|
});
|
|
});
|
|
});
|