Recipe catalog v2: - Recipe gagne visibility (PERSONAL/HOUSE/PUBLIC), authorId, authorHouseId - Favoris par utilisateur (RecipeFavorite), régimes associés (RecipeDiet) - Aliments "pas aimés" par utilisateur (UserProfileDislikedIngredient), distinct des allergies médicales - API: GET /recipes?tab=favoris|perso|foyer|publique avec contrôle d'accès complet, POST/DELETE /recipes/:id/favorite, édition/suppression réservées à l'auteur (403 NOT_RECIPE_AUTHOR), GET/PATCH /profile/disliked-ingredients - Frontend: vue maître-détail (onglets + tableau + panneau détail), formulaire enrichi (visibilité, régimes), section préférences pour les aliments pas aimés Catalogue d'ingrédients de référence: - Extension du seed de 39 à ~430 ingrédients (viandes, poissons/fruits de mer, légumes, fruits, féculents, condiments/sauces, épices/herbes, pains à sandwich, cuisines italienne/asiatique/mexicaine/maghrébine, liquides et boissons de cuisine, bouillons/fonds) - Chaque ingrédient lié à ses allergènes UE (IngredientAllergy) — les 14 allergènes réglementaires restent tous couverts - Seeding optimisé en requêtes groupées (createMany/diff ciblé) plutôt qu'un upsert par ligne, pour garder resetDatabase() rapide en test Tests: 102 tests Mocha + 32 scénarios BDD, tous verts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
60 lines
2.6 KiB
TypeScript
60 lines
2.6 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { Given, Then, When } from "@cucumber/cucumber";
|
|
import { prisma } from "../../src/db/prisma.js";
|
|
import { TEST_REFERENCE_DATE } from "../../test-support/reference-date.js";
|
|
import type { CustomWorld } from "../support/world.js";
|
|
|
|
/** `GET /planning` takes `?date=` explicitly — this scenario wording ("the current planning") maps to the fixed test "today" (see `TEST_REFERENCE_DATE`). */
|
|
When("I request the current planning", async function (this: CustomWorld) {
|
|
this.response = await this.agent
|
|
.get("/planning")
|
|
.query({ date: TEST_REFERENCE_DATE.toISODate() });
|
|
});
|
|
|
|
Then("the current planning response should be empty", function (this: CustomWorld) {
|
|
assert.equal(this.response.body, null);
|
|
});
|
|
|
|
// Creates the planning/recipe rows directly via Prisma rather than through
|
|
// the API — there's no "create a planning" endpoint yet (see
|
|
// specs/batch-cooking-architecture.md, "Calcul batch-cooking" is still
|
|
// TODO), so this is the only way to get a household into a state where it
|
|
// has one. A household is no longer created implicitly at signup, so this
|
|
// step creates one via `POST /house` first — the scenario never names it
|
|
// explicitly, its name doesn't matter here.
|
|
Given(
|
|
"my household has a planning covering today with recipe {string} on {string} for {string}",
|
|
async function (this: CustomWorld, recipeName: string, weekDay: string, meal: string) {
|
|
const houseRes = await this.agent.post("/house").send({ name: "Foyer de test" });
|
|
const houseId: number = houseRes.body.id;
|
|
|
|
const recipe = await prisma.recipe.create({
|
|
data: { name: recipeName, authorId: houseRes.body.adminId },
|
|
});
|
|
const planning = await prisma.planning.create({
|
|
data: {
|
|
houseId,
|
|
startDate: TEST_REFERENCE_DATE.minus({ days: 2 }).toJSDate(),
|
|
finishDate: TEST_REFERENCE_DATE.plus({ days: 2 }).toJSDate(),
|
|
},
|
|
});
|
|
await prisma.planningItem.create({
|
|
data: { planningId: planning.id, weekDay, meal, recipeId: recipe.id },
|
|
});
|
|
},
|
|
);
|
|
|
|
Then(
|
|
"the current planning response should include recipe {string} on {string} for {string}",
|
|
function (this: CustomWorld, recipeName: string, weekDay: string, meal: string) {
|
|
const items = this.response.body.items as Array<{
|
|
weekDay: string;
|
|
meal: string;
|
|
recipe: { name: string };
|
|
}>;
|
|
const item = items.find((i) => i.recipe.name === recipeName);
|
|
assert.ok(item, `expected an item with recipe "${recipeName}", got ${JSON.stringify(items)}`);
|
|
assert.equal(item.weekDay, weekDay);
|
|
assert.equal(item.meal, meal);
|
|
},
|
|
);
|