diff --git a/apps/web/cypress/e2e/cooking-session-page.cy.ts b/apps/web/cypress/e2e/cooking-session-page.cy.ts index 22ac292..f3312c0 100644 --- a/apps/web/cypress/e2e/cooking-session-page.cy.ts +++ b/apps/web/cypress/e2e/cooking-session-page.cy.ts @@ -186,6 +186,28 @@ function setupPlanFixture() { }; } +/** + * Minimal `RecipeView` detail for one of `planFixture()`'s recipes — just + * enough (name/portions/one step) to prove the right recipe's own detail + * rendered inline, not a full catalog-style fixture. + */ +function recipeDetail(id: number, name: string, portions: number, stepDescription: string) { + return { + id, + name, + description: null, + picture: null, + portions, + authorId: 1, + visibility: "PERSONAL", + allergens: [], + diets: [], + isFavorite: false, + ingredients: [], + steps: [{ id: 1, description: stepDescription, picture: null, order: 1, techSteps: [] }], + }; +} + describe("Cooking session page", () => { beforeEach(() => { cy.viewport(1400, 900); @@ -287,25 +309,59 @@ describe("Cooking session page", () => { cy.get(".cooking-stepper__node").first().should("have.class", "cooking-stepper__node--done"); }); - it("lists the week's recipes on the Recettes tab, each linking to its own page", () => { + it("lists the week's recipes on the Recettes tab, each showing its portions", () => { cy.intercept("GET", /\/cooking-session\?/, { statusCode: 200, body: planFixture() }); cy.visit("/cuisiner?date=2026-08-17"); cy.contains(".cooking-session-page__tab", "Recettes").click(); cy.get(".cooking-recipes__item").should("have.length", 2); - cy.contains(".cooking-recipes__item", "Soupe à l'oignon") - .find("a") - .should("have.attr", "href", "/recettes/1"); - cy.contains(".cooking-recipes__item", "Tarte à l'oignon") - .should("contain.text", "6 portions") - .find("a") - .should("have.attr", "href", "/recettes/2"); + cy.contains(".cooking-recipes__item", "Soupe à l'oignon").should("be.visible"); + cy.contains(".cooking-recipes__item", "Tarte à l'oignon").should("contain.text", "6 portions"); // The stepper isn't part of this tab. cy.get(".cooking-stepper").should("not.exist"); }); + it("expands a recipe's detail inline on the Recettes tab instead of navigating away", () => { + cy.intercept("GET", /\/cooking-session\?/, { statusCode: 200, body: planFixture() }); + cy.intercept("GET", "**/recipes/1", { + statusCode: 200, + body: recipeDetail(1, "Soupe à l'oignon", 4, "Émincer les oignons."), + }).as("getSoupe"); + cy.intercept("GET", "**/recipes/2", { + statusCode: 200, + body: recipeDetail(2, "Tarte à l'oignon", 6, "Étaler la pâte."), + }).as("getTarte"); + cy.visit("/cuisiner?date=2026-08-17"); + cy.contains(".cooking-session-page__tab", "Recettes").click(); + + // Nothing unfolded yet, and no more link out to the catalog page — + // clicking a row is what unfolds it now. + cy.get(".cooking-recipes").find("a").should("not.exist"); + cy.get(".cooking-recipes__detail").should("not.exist"); + + cy.contains(".cooking-recipes__row", "Soupe à l'oignon").click(); + cy.wait("@getSoupe"); + cy.location("pathname").should("eq", "/cuisiner"); // no navigation happened + cy.get(".cooking-recipes__detail .recipe-detail-panel").within(() => { + cy.contains("h2", "Soupe à l'oignon").should("be.visible"); + cy.contains("Émincer les oignons.").should("be.visible"); + }); + + // Only one recipe unfolds at a time — opening Tarte's closes Soupe's. + cy.contains(".cooking-recipes__row", "Tarte à l'oignon").click(); + cy.wait("@getTarte"); + cy.get(".cooking-recipes__detail").should("have.length", 1); + cy.get(".cooking-recipes__detail .recipe-detail-panel") + .should("contain.text", "Étaler la pâte.") + .and("not.contain.text", "Émincer"); + + // Clicking the open one again collapses it back. + cy.contains(".cooking-recipes__row", "Tarte à l'oignon").click(); + cy.get(".cooking-recipes__detail").should("not.exist"); + }); + it("renders a merged-setup preheat with its temperature and the oven-conflict note", () => { cy.intercept("GET", /\/cooking-session\?/, { statusCode: 200, body: setupPlanFixture() }); cy.visit("/cuisiner?date=2026-08-17"); diff --git a/apps/web/cypress/e2e/cooking-session.feature b/apps/web/cypress/e2e/cooking-session.feature index 13a09ee..892d6c3 100644 --- a/apps/web/cypress/e2e/cooking-session.feature +++ b/apps/web/cypress/e2e/cooking-session.feature @@ -52,8 +52,16 @@ Feature: Start cooking an optimized plan When I visit "/cuisiner?date=2026-08-17" And I open the "Recettes" cooking tab Then I should see "Soupe à l'oignon" - And the recipe "Soupe à l'oignon" should link to "/recettes/1" - And the recipe "Tarte à l'oignon" should link to "/recettes/2" + + Scenario: Clicking a recipe on the Recettes tab unfolds it instead of navigating away + Given the planning for this week has recipes "Soupe à l'oignon" and "Tarte à l'oignon" + And the cooking plan for "2026-08-17" has a mise en place then a cooking step + And recipe 1's detail is available + When I visit "/cuisiner?date=2026-08-17" + And I open the "Recettes" cooking tab + And I click the recipe "Soupe à l'oignon" + Then the recipe detail "Soupe à l'oignon" should be expanded + And the URL should include "/cuisiner" Scenario: Two recipes preheat the oven to different temperatures Given the planning for this week has recipes "Gratin" and "Rôti" diff --git a/apps/web/cypress/e2e/cooking-session.ts b/apps/web/cypress/e2e/cooking-session.ts index a6d493f..3040b38 100644 --- a/apps/web/cypress/e2e/cooking-session.ts +++ b/apps/web/cypress/e2e/cooking-session.ts @@ -249,6 +249,39 @@ Then("the current cooking step should be {string}", (position: string) => { cy.contains(".cooking-plan__position", position).should("be.visible"); }); -Then("the recipe {string} should link to {string}", (name: string, href: string) => { - cy.contains(".cooking-recipes__item", name).find("a").should("have.attr", "href", href); +Given("recipe 1's detail is available", () => { + // Minimal `RecipeView` — just enough (name + one step) to prove the + // right recipe's own detail unfolded inline. + cy.intercept("GET", "**/recipes/1", { + statusCode: 200, + body: { + id: 1, + name: "Soupe à l'oignon", + description: null, + picture: null, + portions: 4, + authorId: 1, + visibility: "PERSONAL", + allergens: [], + diets: [], + isFavorite: false, + ingredients: [], + steps: [ + { id: 1, description: "Émincer les oignons.", picture: null, order: 1, techSteps: [] }, + ], + }, + }); +}); + +// The task card is a `