From a8d897dfab1e8261b2d6ab2992ddd8ace00a7c46 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Mon, 17 Aug 2026 15:56:36 +0200 Subject: [PATCH] =?UTF-8?q?Tests:=20couverture=20Cypress=20pour=20les=20pr?= =?UTF-8?q?=C3=A9f=C3=A9rences=20utilisateur=20(step=204/4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - user-preferences.cy.ts: défaut SYSTEM, thème sauvegardé restitué et appliqué au document, autosave sans bouton "Enregistrer" - sidebar.cy.ts: 4 pages de paramètres (libellé "Préférences alimentaires" renommé + nouvelle entrée "Préférences utilisateur") - auth.cy.ts/onboarding.cy.ts: corrige un intercept **/planning/current périmé (route supprimée dans la PR précédente) — masqué jusqu'ici car aucune assertion n'en dépendait directement, mais provoquait un appel réseau non mocké --- apps/web/cypress/e2e/auth.cy.ts | 6 +-- apps/web/cypress/e2e/onboarding.cy.ts | 2 +- apps/web/cypress/e2e/sidebar.cy.ts | 17 +++++-- apps/web/cypress/e2e/user-preferences.cy.ts | 54 +++++++++++++++++++++ 4 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 apps/web/cypress/e2e/user-preferences.cy.ts diff --git a/apps/web/cypress/e2e/auth.cy.ts b/apps/web/cypress/e2e/auth.cy.ts index 9be4fde..e0baebd 100644 --- a/apps/web/cypress/e2e/auth.cy.ts +++ b/apps/web/cypress/e2e/auth.cy.ts @@ -76,7 +76,7 @@ describe("Signup", () => { describe("Login", () => { it("logs in and lands on the home page", () => { cy.intercept("GET", "**/auth/me", { statusCode: 401 }); - cy.intercept("GET", "**/planning/current", { statusCode: 200, body: null }); + cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: null }); cy.intercept("POST", "**/auth/login", { statusCode: 200, body: { @@ -130,7 +130,7 @@ describe("Already authenticated", () => { dietId: null, }, }); - cy.intercept("GET", "**/planning/current", { statusCode: 200, body: null }); + cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: null }); cy.visit("/login"); cy.url().should("not.include", "/login"); @@ -150,7 +150,7 @@ describe("Already authenticated", () => { dietId: null, }, }); - cy.intercept("GET", "**/planning/current", { statusCode: 200, body: null }); + cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: null }); cy.intercept("POST", "**/auth/logout", { statusCode: 204 }).as("logout"); cy.visit("/"); diff --git a/apps/web/cypress/e2e/onboarding.cy.ts b/apps/web/cypress/e2e/onboarding.cy.ts index 8906290..c8cf368 100644 --- a/apps/web/cypress/e2e/onboarding.cy.ts +++ b/apps/web/cypress/e2e/onboarding.cy.ts @@ -16,7 +16,7 @@ const signupResponse = { function signupAndReachOnboarding() { cy.intercept("GET", "**/auth/me", { statusCode: 401 }); cy.intercept("POST", "**/auth/signup", { statusCode: 201, body: signupResponse }).as("signup"); - cy.intercept("GET", "**/planning/current", { statusCode: 200, body: null }); + cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: null }); cy.visit("/signup"); cy.get("#firstName").type("Alice"); diff --git a/apps/web/cypress/e2e/sidebar.cy.ts b/apps/web/cypress/e2e/sidebar.cy.ts index 07295d2..a7d20ab 100644 --- a/apps/web/cypress/e2e/sidebar.cy.ts +++ b/apps/web/cypress/e2e/sidebar.cy.ts @@ -13,7 +13,9 @@ const authenticatedProfile = { describe("Sidebar — settings menu and account menu", () => { beforeEach(() => { cy.intercept("GET", "**/auth/me", { statusCode: 200, body: authenticatedProfile }); - cy.intercept("GET", "**/planning/current", { statusCode: 200, body: null }); + // Not "**/planning*" — that glob also matches the Vite dev request for + // planning-page.scss (see planning-page.cy.ts for the same gotcha). + cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: null }); }); it("no longer lists Foyer in the main nav", () => { @@ -21,15 +23,24 @@ describe("Sidebar — settings menu and account menu", () => { cy.get(".app-sidebar__nav a").should("not.contain", "Foyer"); }); - it("reveals the three settings pages behind the Paramètres toggle", () => { + it("reveals the four settings pages behind the Paramètres toggle", () => { cy.visit("/"); cy.contains("a", "Compte").should("not.exist"); cy.contains("button", "Paramètres").click(); cy.contains("a", "Compte").should("have.attr", "href", "/parametres/compte"); - cy.contains("a", "Préférences").should("have.attr", "href", "/parametres/preferences"); + cy.contains("a", "Préférences alimentaires").should( + "have.attr", + "href", + "/parametres/preferences", + ); cy.contains("a", "Foyer").should("have.attr", "href", "/parametres/foyer"); + cy.contains("a", "Préférences utilisateur").should( + "have.attr", + "href", + "/parametres/preferences-utilisateur", + ); }); it("opens the account menu from the greeting and links to Mon compte", () => { diff --git a/apps/web/cypress/e2e/user-preferences.cy.ts b/apps/web/cypress/e2e/user-preferences.cy.ts new file mode 100644 index 0000000..0c09b1c --- /dev/null +++ b/apps/web/cypress/e2e/user-preferences.cy.ts @@ -0,0 +1,54 @@ +// 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: null, + dietId: null, +}; + +describe("User preferences (/parametres/preferences-utilisateur)", () => { + beforeEach(() => { + cy.intercept("GET", "**/auth/me", { statusCode: 200, body: authenticatedProfile }); + }); + + it("shows SYSTEM selected by default", () => { + cy.intercept("GET", "**/preferences", { statusCode: 200, body: { theme: "SYSTEM" } }); + + cy.visit("/parametres/preferences-utilisateur"); + + cy.contains("label", "Système").find("input[type=radio]").should("be.checked"); + cy.contains("label", "Clair").find("input[type=radio]").should("not.be.checked"); + cy.contains("label", "Sombre").find("input[type=radio]").should("not.be.checked"); + // SYSTEM never sets an override — the OS/browser preference decides. + cy.get("html").should("not.have.attr", "data-theme"); + }); + + it("shows the previously saved theme selected, and applies it to the document", () => { + cy.intercept("GET", "**/preferences", { statusCode: 200, body: { theme: "DARK" } }); + + cy.visit("/parametres/preferences-utilisateur"); + + cy.contains("label", "Sombre").find("input[type=radio]").should("be.checked"); + cy.get("html").should("have.attr", "data-theme", "dark"); + }); + + it("switching theme autosaves and applies immediately, no explicit save button", () => { + cy.intercept("GET", "**/preferences", { statusCode: 200, body: { theme: "SYSTEM" } }); + cy.intercept("PATCH", "**/preferences", { statusCode: 200, body: { theme: "LIGHT" } }).as( + "updatePreferences", + ); + + cy.visit("/parametres/preferences-utilisateur"); + cy.contains("button", "Enregistrer").should("not.exist"); + + cy.contains("label", "Clair").click(); + + cy.wait("@updatePreferences").its("request.body").should("deep.equal", { theme: "LIGHT" }); + cy.contains("Enregistré ✓").should("be.visible"); + cy.get("html").should("have.attr", "data-theme", "light"); + }); +});