// Mocks the admin API via cy.intercept — no live backend. Covers the // `/admin/didacticiels` CRUD page (issue #44): list, edit-and-save a // scenario's steps in one block PATCH, create a scenario, delete one. const adminBody = { id: 1, email: "ops@example.com", name: "Ops", createdAt: "2026-08-01T00:00:00.000Z", lastLoginAt: "2026-08-28T09:00:00.000Z", }; const TARGETS = [ { key: "nav-planning", description: "Lien « Planning » de la barre latérale" }, { key: "planning-grid", description: "La grille du planning de la semaine" }, { key: "planning-cook-button", description: "Bouton « Cuisiner » de l'en-tête du planning" }, ]; function scenarios() { return [ { id: 1, key: "general", name: "Tour d'orientation", enabled: true, steps: [ { order: 0, route: "/", targetKey: "nav-planning", title: "Bienvenue", content: "Le planning.", }, { order: 1, route: null, targetKey: "planning-grid", title: "La grille", content: "Sept jours.", }, ], }, { id: 2, key: "techStepMetadata", name: "Corriger les techniques", enabled: false, steps: [] }, ]; } describe("Admin — didacticiels CRUD", () => { beforeEach(() => { cy.viewport(1400, 900); cy.intercept("GET", "**/admin/api/auth/me", { statusCode: 200, body: adminBody }); cy.intercept("GET", "**/admin/api/tours", { statusCode: 200, body: scenarios() }).as("list"); cy.intercept("GET", "**/admin/api/tours/targets", { statusCode: 200, body: TARGETS }); }); it("lists every scenario, enabled and disabled, with its step count", () => { cy.visit("/admin/didacticiels"); cy.wait("@list"); cy.contains(".tours-page__list button", "Tour d'orientation").should( "contain.text", "2 étapes", ); cy.contains(".tours-page__list button", "Corriger les techniques").should( "contain.text", "désactivé", ); }); it("edits a scenario's name and steps and saves the whole list in one PATCH", () => { cy.intercept("PATCH", "**/admin/api/tours/1", (req) => { req.reply({ statusCode: 200, body: { ...scenarios()[0], name: req.body.name } }); }).as("save"); cy.visit("/admin/didacticiels"); cy.wait("@list"); cy.contains(".tours-page__list button", "Tour d'orientation").click(); cy.get('[data-testid="scenario-editor"]').within(() => { cy.contains("label", "Nom").find("input").clear().type("Tour d'accueil"); // Reorder: push step 1 down so "La grille" comes first. cy.get(".tours-page__step").first().contains("button", "↓").click(); cy.contains("button", "Enregistrer").click(); }); cy.wait("@save") .its("request.body") .should((body) => { expect(body.name).to.equal("Tour d'accueil"); expect(body.enabled).to.equal(true); expect(body.steps).to.have.length(2); // Reordered: the grid step is now first, nav-planning second. expect(body.steps[0].targetKey).to.equal("planning-grid"); expect(body.steps[1].targetKey).to.equal("nav-planning"); }); }); it("creates a new scenario", () => { cy.intercept("POST", "**/admin/api/tours", (req) => { req.reply({ statusCode: 201, body: { id: 3, key: req.body.key, name: req.body.name, enabled: true, steps: [] }, }); }).as("create"); cy.visit("/admin/didacticiels"); cy.wait("@list"); cy.contains("button", "Nouveau scénario").click(); cy.contains("label", "Clé").find("input").type("shoppingList"); cy.contains("label", "Nom").find("input").type("Tour de la liste de courses"); cy.contains("button", "Créer").click(); cy.wait("@create") .its("request.body") .should("deep.equal", { key: "shoppingList", name: "Tour de la liste de courses" }); }); it("deletes a scenario after confirmation", () => { cy.intercept("DELETE", "**/admin/api/tours/1", { statusCode: 204 }).as("del"); cy.on("window:confirm", () => true); cy.visit("/admin/didacticiels"); cy.wait("@list"); cy.contains(".tours-page__list button", "Tour d'orientation").click(); cy.get('[data-testid="scenario-editor"]').contains("button", "Supprimer le scénario").click(); cy.wait("@del"); }); });