Retour fonctionnel : allergies et intolérances doivent être distinguées dans l'UI, et /foyer doit sauvegarder à la volée plutôt que via des boutons "Enregistrer". - AllergySelect prend un `legend` en prop au lieu d'un libellé interne fixe — le même composant est rendu deux fois par chaque page consommatrice (HouseholdPage, OnboardingAllergensPage), une fois par `kind` (ALLERGY / INTOLERANCE), la sélection restant une seule liste d'IDs partagée. - HouseholdPage : suppression des boutons "Enregistrer", autosave déclenché depuis le handler onChange de chaque champ (jamais un useEffect générique sur la valeur — se déclencherait aussi au chargement initial, sans distinction propre "chargé" vs "modifié"). Nom du foyer et allergènes/intolérances debouncés (600ms/500ms), régime sauvegardé immédiatement (sélection discrète). Validation client (nom vide) empêche l'autosave plutôt que de déclencher un aller-retour API voué à l'échec. - i18n : household.form.allergiesLabel devient "Allergies" (au lieu de "Allergies & intolérances"), nouvelle clé intolerancesLabel, save/ saved remplacés par saving/saved (plus de bouton à libeller). - Cypress (household.cy.ts réécrit, onboarding.cy.ts mis à jour) + specs/frontend-architecture.md + README.md. Vérifié dans le navigateur : wizard d'inscription affiche bien les deux groupes (12 allergies / 2 intolérances) ; /foyer sans aucun bouton, chaque section sauvegarde automatiquement (vérifié en base après édition du nom du foyer et du régime) ; compte de test nettoyé. Clôt le retour fonctionnel sur la feature profil/foyer/régime/ allergènes (8 commits au total sur cette PR).
101 lines
3.3 KiB
TypeScript
101 lines
3.3 KiB
TypeScript
// Mocks the API via cy.intercept — see auth.cy.ts for the rationale.
|
|
|
|
const authenticatedProfile = {
|
|
id: 1,
|
|
firstName: "Alice",
|
|
lastName: "Martin",
|
|
email: "alice@example.com",
|
|
tokenVersion: 0,
|
|
houseId: 1,
|
|
dietId: 2,
|
|
};
|
|
|
|
describe("Household & profile settings (/foyer) — hot saving", () => {
|
|
beforeEach(() => {
|
|
cy.intercept("GET", "**/auth/me", { statusCode: 200, body: authenticatedProfile });
|
|
cy.intercept("GET", "**/house/current", {
|
|
statusCode: 200,
|
|
body: { id: 1, name: "Chez Alice" },
|
|
});
|
|
cy.intercept("GET", "**/reference/diets", {
|
|
statusCode: 200,
|
|
body: [
|
|
{ id: 1, name: "Omnivore" },
|
|
{ id: 2, name: "Végétarien" },
|
|
],
|
|
});
|
|
cy.intercept("GET", "**/reference/allergies", {
|
|
statusCode: 200,
|
|
body: [
|
|
{ id: 1, name: "Arachides", kind: "ALLERGY" },
|
|
{ id: 2, name: "Gluten", kind: "INTOLERANCE" },
|
|
],
|
|
});
|
|
cy.intercept("GET", "**/profile/allergies", { statusCode: 200, body: [2] });
|
|
});
|
|
|
|
it("loads the current household name, regime, and shows allergies/intolerances as two groups", () => {
|
|
cy.visit("/foyer");
|
|
|
|
cy.get("#houseName").should("have.value", "Chez Alice");
|
|
cy.get("#diet").should("have.value", "2");
|
|
cy.contains("legend", "Allergies").should("be.visible");
|
|
cy.contains("legend", "Intolérances").should("be.visible");
|
|
cy.contains("label", "Gluten").find("input[type=checkbox]").should("be.checked");
|
|
cy.contains("label", "Arachides").find("input[type=checkbox]").should("not.be.checked");
|
|
});
|
|
|
|
it("has no explicit save button anywhere on the page", () => {
|
|
cy.visit("/foyer");
|
|
cy.contains("button", "Enregistrer").should("not.exist");
|
|
});
|
|
|
|
it("autosaves the household name a short pause after typing, no button click", () => {
|
|
cy.intercept("PATCH", "**/house/current", {
|
|
statusCode: 200,
|
|
body: { id: 1, name: "Chez les Martin" },
|
|
}).as("renameHouse");
|
|
|
|
cy.visit("/foyer");
|
|
cy.get("#houseName").clear();
|
|
cy.get("#houseName").type("Chez les Martin");
|
|
|
|
cy.wait("@renameHouse").its("request.body").should("deep.equal", { name: "Chez les Martin" });
|
|
cy.contains("Enregistré ✓").should("be.visible");
|
|
});
|
|
|
|
it("does not autosave an empty household name — shows a validation message instead", () => {
|
|
cy.intercept("PATCH", "**/house/current").as("renameHouse");
|
|
|
|
cy.visit("/foyer");
|
|
cy.get("#houseName").clear();
|
|
|
|
cy.contains("Le nom du foyer est requis").should("be.visible");
|
|
cy.get("@renameHouse.all").should("have.length", 0);
|
|
});
|
|
|
|
it("autosaves the regime as soon as it's selected", () => {
|
|
cy.intercept("PATCH", "**/profile/diet", {
|
|
statusCode: 200,
|
|
body: { ...authenticatedProfile, dietId: 1 },
|
|
}).as("updateDiet");
|
|
|
|
cy.visit("/foyer");
|
|
cy.get("#diet").select("Omnivore");
|
|
|
|
cy.wait("@updateDiet").its("request.body").should("deep.equal", { dietId: 1 });
|
|
});
|
|
|
|
it("autosaves allergies and intolerances together after checking boxes", () => {
|
|
cy.intercept("PATCH", "**/profile/allergies", { statusCode: 200, body: [2, 1] }).as(
|
|
"updateAllergies",
|
|
);
|
|
|
|
cy.visit("/foyer");
|
|
cy.contains("label", "Arachides").find("input[type=checkbox]").check();
|
|
|
|
cy.wait("@updateAllergies")
|
|
.its("request.body")
|
|
.should("deep.equal", { allergyIds: [2, 1] });
|
|
});
|
|
});
|