batchCooking/apps/web/cypress/e2e/leftovers-basket.cy.ts
Nicolas a3701acae4
Some checks failed
CI / build-android (push) Blocked by required conditions
CI / lint (push) Successful in 3m18s
CI / intent-service-test (push) Successful in 4m8s
CI / build (push) Successful in 3m42s
CI / test (push) Failing after 10m11s
CI / e2e (push) Has been cancelled
fix(planning): popovers flottants surs sur mobile
Ticket #87 du chantier UI mobile & tablette. LeftoversBasket et
WeekNavigator's CalendarPopover etaient tous les deux des popovers a
largeur fixe (18-20rem), ancres right: 0, sans aucune gestion de bord
d'ecran - sur un telephone etroit ils pouvaient deborder hors du
viewport. Les deux sont declenches depuis l'en-tete du planning, un
ecran central de l'usage quotidien - tres probablement la cause
concrete derriere le retour terrain "je n'ai pas acces a tous les
boutons" sur mobile qui a lance ce chantier.

Les deux basculent desormais sur BottomSheet (ticket #91) sous le
breakpoint phone via useIsMobileViewport() - meme contenu, juste une
autre enveloppe (le popover flottant + son ecouteur de clic exterieur
manuel restent inchanges sur desktop). Le clic-exterieur devient un
no-op propre sur mobile plutot qu'un ecouteur qui ne fait jamais rien
(le ref ne s'attache a rien dans la branche BottomSheet).

Nouvelle cle i18n common.calendar.title ("Choisir une semaine") pour
le titre de la feuille - pas de raccourci en decoupant une autre cle
interpolee.

Verifie en local : tsc -b --force, biome check, build de prod, suite
Cypress e2e complete (142/142, 2 nouveaux tests phone dans
leftovers-basket.cy.ts et planning-page.cy.ts) et composants (63/63).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 12:48:39 +02:00

127 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Layout-mode spec for the planning header's leftovers basket — mocks
// `GET /planning` (this job has no live backend; apps/api's Mocha suite
// covers the real endpoints). Exercises the popover open/close, an
// outside click, and the "Jeter" button firing `PATCH .../discard-leftover`.
const authenticatedProfile = {
id: 1,
firstName: "Alice",
lastName: "Martin",
email: "alice@example.com",
tokenVersion: 0,
houseId: 1,
dietId: null,
};
/**
* A week with one fresh item that cooked 12 for 10 requested (pool of 2)
* and one leftovers item serving 1 of that pool — so the basket should
* offer 1 line with 1 portion still available.
*/
const planningWithLeftovers = {
id: 1,
startDate: "2026-08-17T00:00:00.000Z",
finishDate: "2026-08-23T00:00:00.000Z",
items: [
{
id: 1,
weekDay: "lundi",
meal: "diner",
portions: 12,
portionsRequested: 10,
discardedPortions: 0,
sourceItem: null,
recipe: { id: 1, name: "Lasagnes" },
},
{
id: 2,
weekDay: "mardi",
meal: "dejeuner",
portions: 1,
portionsRequested: 1,
discardedPortions: 0,
sourceItem: { id: 1 },
recipe: { id: 1, name: "Lasagnes" },
},
],
};
describe("Leftovers basket", () => {
beforeEach(() => {
cy.viewport(1600, 900);
cy.clock(new Date("2026-08-17T09:00:00Z"), ["Date"]);
cy.intercept("GET", "**/auth/me", { statusCode: 200, body: authenticatedProfile });
});
it("lists a week's available leftovers, opens and closes on an outside click", () => {
cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: planningWithLeftovers });
cy.visit("/");
// Count badge = 1 fresh item with a remaining pool.
cy.get(".leftovers-basket__count").should("have.text", "1");
cy.get(".leftovers-basket__toggle").click();
cy.contains(".leftovers-basket__heading", "Restes disponibles").should("be.visible");
cy.contains(".leftovers-basket__line", "Lasagnes")
.should("contain.text", "Lundi")
.and("contain.text", "1 en restes");
// Clicking away from the popover closes it.
cy.get("h1").click();
cy.get(".leftovers-basket__popover").should("not.exist");
});
it("shows an empty state when nothing is left over", () => {
cy.intercept("GET", /\/planning\?/, {
statusCode: 200,
body: {
...planningWithLeftovers,
items: [{ ...planningWithLeftovers.items[0], portions: 10, portionsRequested: 10 }],
},
});
cy.visit("/");
cy.get(".leftovers-basket__count").should("not.exist");
cy.get(".leftovers-basket__toggle").click();
cy.contains(".leftovers-basket__empty", "Aucun reste cette semaine.").should("be.visible");
});
it("throws away a leftover pool via PATCH and drops it from the list", () => {
cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: planningWithLeftovers });
cy.intercept("PATCH", "**/planning/items/1/discard-leftover", {
statusCode: 200,
body: {
...planningWithLeftovers.items[0],
discardedPortions: 1,
},
}).as("discard");
cy.visit("/");
cy.get(".leftovers-basket__toggle").click();
cy.contains(".leftovers-basket__line", "Lasagnes").find(".leftovers-basket__discard").click();
cy.wait("@discard");
// Pool was 1, now fully discarded -> the line is gone, the popover is empty.
cy.contains(".leftovers-basket__empty", "Aucun reste cette semaine.").should("be.visible");
cy.get(".leftovers-basket__count").should("not.exist");
});
it("opens inside a bottom sheet on a phone instead of the anchored popover", () => {
// Literal 390×844 rather than `cy.setViewport("phone")` (ticket #83) —
// that command doesn't exist on this ticket's own base yet; matches its
// PHONE_VIEWPORT value on purpose, worth switching to the real import
// once both have landed on `main`.
cy.viewport(390, 844);
cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: planningWithLeftovers });
cy.visit("/");
cy.get(".leftovers-basket__toggle").click();
cy.get(".leftovers-basket__popover").should("not.exist");
cy.get(".bottom-sheet").should("be.visible");
cy.contains(".bottom-sheet", "Restes disponibles").should("be.visible");
cy.contains(".bottom-sheet .leftovers-basket__line", "Lasagnes").should("be.visible");
cy.get(".bottom-sheet__close").click();
cy.get(".bottom-sheet").should("not.exist");
});
});