Tests: couverture Cypress pour les préférences utilisateur (step 4/4)

- 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é
This commit is contained in:
Nicolas 2026-08-17 15:56:36 +02:00
parent 4bdc9c0470
commit a8d897dfab
4 changed files with 72 additions and 7 deletions

View file

@ -76,7 +76,7 @@ describe("Signup", () => {
describe("Login", () => { describe("Login", () => {
it("logs in and lands on the home page", () => { it("logs in and lands on the home page", () => {
cy.intercept("GET", "**/auth/me", { statusCode: 401 }); 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", { cy.intercept("POST", "**/auth/login", {
statusCode: 200, statusCode: 200,
body: { body: {
@ -130,7 +130,7 @@ describe("Already authenticated", () => {
dietId: null, dietId: null,
}, },
}); });
cy.intercept("GET", "**/planning/current", { statusCode: 200, body: null }); cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: null });
cy.visit("/login"); cy.visit("/login");
cy.url().should("not.include", "/login"); cy.url().should("not.include", "/login");
@ -150,7 +150,7 @@ describe("Already authenticated", () => {
dietId: null, 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.intercept("POST", "**/auth/logout", { statusCode: 204 }).as("logout");
cy.visit("/"); cy.visit("/");

View file

@ -16,7 +16,7 @@ const signupResponse = {
function signupAndReachOnboarding() { function signupAndReachOnboarding() {
cy.intercept("GET", "**/auth/me", { statusCode: 401 }); cy.intercept("GET", "**/auth/me", { statusCode: 401 });
cy.intercept("POST", "**/auth/signup", { statusCode: 201, body: signupResponse }).as("signup"); 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.visit("/signup");
cy.get("#firstName").type("Alice"); cy.get("#firstName").type("Alice");

View file

@ -13,7 +13,9 @@ const authenticatedProfile = {
describe("Sidebar — settings menu and account menu", () => { describe("Sidebar — settings menu and account menu", () => {
beforeEach(() => { beforeEach(() => {
cy.intercept("GET", "**/auth/me", { statusCode: 200, body: authenticatedProfile }); 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", () => { 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"); 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.visit("/");
cy.contains("a", "Compte").should("not.exist"); cy.contains("a", "Compte").should("not.exist");
cy.contains("button", "Paramètres").click(); cy.contains("button", "Paramètres").click();
cy.contains("a", "Compte").should("have.attr", "href", "/parametres/compte"); 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", "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", () => { it("opens the account menu from the greeting and links to Mon compte", () => {

View file

@ -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");
});
});