// Mocks the API via cy.intercept — this job doesn't run a live backend (see // .github/workflows/ci.yml); apps/api's own Mocha suite covers real // `POST /contact` behavior against a real database. The Gherkin journey // (fill + send + confirmation) lives in contact.feature — this file only // covers the page's initial render and its guards. const authenticatedProfile = { id: 1, firstName: "Alice", lastName: "Martin", email: "alice@example.com", tokenVersion: 0, houseId: null, dietId: null, }; describe("Contact page (/parametres/contact)", () => { it("redirects to /login when signed out (RequireAuth)", () => { cy.intercept("GET", "**/auth/me", { statusCode: 401 }); cy.visit("/parametres/contact"); cy.url().should("include", "/login"); }); describe("signed in", () => { beforeEach(() => { cy.intercept("GET", "**/auth/me", { statusCode: 200, body: authenticatedProfile }); }); it("renders the form: a type select defaulting to Bug, a message box, a submit button", () => { cy.visit("/parametres/contact"); cy.contains("h1", "Nous contacter").should("be.visible"); cy.get("#contactType option").should("have.length", 3); cy.get("#contactType").should("have.value", "bug"); cy.get("#contactMessage").should("be.visible"); cy.contains("button", "Envoyer").should("not.be.disabled"); }); it("shows a translated error label, never the raw server message, when the submit fails", () => { cy.intercept("POST", "**/contact", { statusCode: 500, body: { code: 5000, message: "raw internal boom" }, }).as("submitContact"); cy.visit("/parametres/contact"); cy.get("#contactMessage").type( "Ceci est un message de test suffisamment long pour être valide.", ); cy.contains("button", "Envoyer").click(); cy.wait("@submitContact"); cy.get(".field-error").should("be.visible"); cy.contains("raw internal boom").should("not.exist"); }); }); });