- household.cy.ts scindé en preferences.cy.ts (régime/allergies) et household-settings.cy.ts (nom, créer/rejoindre/membres/suppression/ quitter, avec et sans droits admin) - onboarding.cy.ts réordonné (régime → foyer → allergènes), avec les cas skip / créer / rejoindre à l'étape foyer - account.cy.ts: identité, suppression de compte (erreur de mot de passe, succès, annulation) - sidebar.cy.ts: menu Paramètres (3 liens) et menu compte (Mon compte, déconnexion), redirection /foyer → /parametres/foyer - auth.cy.ts/home-planning.cy.ts: adaptés au nouveau menu compte et au premier écran d'onboarding (régime, plus foyer)
185 lines
6.3 KiB
TypeScript
185 lines
6.3 KiB
TypeScript
// Mocks the API via cy.intercept — see auth.cy.ts for the rationale.
|
|
|
|
const adminProfile = {
|
|
id: 1,
|
|
firstName: "Alice",
|
|
lastName: "Martin",
|
|
email: "alice@example.com",
|
|
tokenVersion: 0,
|
|
houseId: null as number | null,
|
|
dietId: null,
|
|
};
|
|
|
|
const houseWithTwoMembers = {
|
|
id: 1,
|
|
name: "Chez Alice",
|
|
adminId: 1,
|
|
inviteCode: "ABCD2345",
|
|
members: [
|
|
{ id: 1, firstName: "Alice", lastName: "Martin" },
|
|
{ id: 2, firstName: "Bob", lastName: "Dupont" },
|
|
],
|
|
};
|
|
|
|
describe("Household settings (/parametres/foyer) — no household yet", () => {
|
|
beforeEach(() => {
|
|
cy.intercept("GET", "**/auth/me", { statusCode: 200, body: adminProfile });
|
|
cy.intercept("GET", "**/house/current", { statusCode: 200, body: null });
|
|
});
|
|
|
|
it("offers to create or join a household", () => {
|
|
cy.visit("/parametres/foyer");
|
|
|
|
cy.contains("Créer un foyer").should("be.visible");
|
|
cy.contains("Rejoindre un foyer").should("be.visible");
|
|
});
|
|
|
|
it("creates a household", () => {
|
|
const createdHouse = {
|
|
id: 1,
|
|
name: "Chez Alice",
|
|
adminId: 1,
|
|
inviteCode: "ABCD2345",
|
|
members: [{ id: 1, firstName: "Alice", lastName: "Martin" }],
|
|
};
|
|
// The page reloads `GET /house/current` right after creating succeeds —
|
|
// see the "deletes the household" test above for the same pattern.
|
|
let created = false;
|
|
cy.intercept("GET", "**/house/current", (req) => {
|
|
req.reply({ statusCode: 200, body: created ? createdHouse : null });
|
|
});
|
|
cy.intercept("POST", "**/house", (req) => {
|
|
created = true;
|
|
req.reply({ statusCode: 201, body: createdHouse });
|
|
}).as("createHouse");
|
|
|
|
cy.visit("/parametres/foyer");
|
|
cy.get("#houseName").type("Chez Alice");
|
|
cy.contains("button", "Créer").click();
|
|
|
|
cy.wait("@createHouse").its("request.body").should("deep.equal", { name: "Chez Alice" });
|
|
cy.contains("ABCD2345").should("be.visible");
|
|
});
|
|
|
|
it("joins a household by invite code", () => {
|
|
let joined = false;
|
|
cy.intercept("GET", "**/house/current", (req) => {
|
|
req.reply({ statusCode: 200, body: joined ? houseWithTwoMembers : null });
|
|
});
|
|
cy.intercept("POST", "**/house/join", (req) => {
|
|
joined = true;
|
|
req.reply({ statusCode: 200, body: houseWithTwoMembers });
|
|
}).as("joinHouse");
|
|
|
|
cy.visit("/parametres/foyer");
|
|
cy.get("#inviteCode").type("abcd2345");
|
|
cy.contains("button", "Rejoindre").click();
|
|
|
|
cy.wait("@joinHouse").its("request.body").should("deep.equal", { inviteCode: "ABCD2345" });
|
|
cy.contains("Bob Dupont").should("be.visible");
|
|
});
|
|
});
|
|
|
|
describe("Household settings (/parametres/foyer) — as the admin", () => {
|
|
beforeEach(() => {
|
|
cy.intercept("GET", "**/auth/me", { statusCode: 200, body: { ...adminProfile, houseId: 1 } });
|
|
cy.intercept("GET", "**/house/current", { statusCode: 200, body: houseWithTwoMembers });
|
|
});
|
|
|
|
it("shows the household's name, invite code, and members with an admin badge", () => {
|
|
cy.visit("/parametres/foyer");
|
|
|
|
cy.get("#houseName").should("have.value", "Chez Alice");
|
|
cy.contains("ABCD2345").should("be.visible");
|
|
cy.contains("Bob Dupont").should("be.visible");
|
|
cy.contains("Alice Martin").parent().contains("Admin");
|
|
});
|
|
|
|
it("autosaves the household name", () => {
|
|
cy.intercept("PATCH", "**/house/current", {
|
|
statusCode: 200,
|
|
body: { ...houseWithTwoMembers, name: "Chez les Martin" },
|
|
}).as("renameHouse");
|
|
|
|
cy.visit("/parametres/foyer");
|
|
cy.get("#houseName").clear();
|
|
cy.get("#houseName").type("Chez les Martin");
|
|
|
|
cy.wait("@renameHouse").its("request.body").should("deep.equal", { name: "Chez les Martin" });
|
|
cy.contains("Enregistré ✓").should("be.visible");
|
|
});
|
|
|
|
it("removes a member", () => {
|
|
// Same reasoning as the "deletes the household" test below — the page
|
|
// reloads `GET /house/current` right after the removal succeeds.
|
|
let memberRemoved = false;
|
|
cy.intercept("GET", "**/house/current", (req) => {
|
|
const body = memberRemoved
|
|
? { ...houseWithTwoMembers, members: [houseWithTwoMembers.members[0]] }
|
|
: houseWithTwoMembers;
|
|
req.reply({ statusCode: 200, body });
|
|
});
|
|
cy.intercept("DELETE", "**/house/members/2", (req) => {
|
|
memberRemoved = true;
|
|
req.reply({
|
|
statusCode: 200,
|
|
body: { ...houseWithTwoMembers, members: [houseWithTwoMembers.members[0]] },
|
|
});
|
|
}).as("removeMember");
|
|
|
|
cy.visit("/parametres/foyer");
|
|
cy.contains("li", "Bob Dupont").contains("button", "Retirer").click();
|
|
|
|
cy.wait("@removeMember");
|
|
cy.contains("Bob Dupont").should("not.exist");
|
|
});
|
|
|
|
it("deletes the household after confirming", () => {
|
|
// The page reloads `GET /house/current` right after the delete
|
|
// succeeds — this intercept needs to answer differently before/after
|
|
// that DELETE, hence the shared mutable flag rather than two static
|
|
// `cy.intercept` calls (the later one would just win for every request,
|
|
// including the initial page load).
|
|
let houseDeleted = false;
|
|
cy.intercept("GET", "**/house/current", (req) => {
|
|
req.reply({ statusCode: 200, body: houseDeleted ? null : houseWithTwoMembers });
|
|
});
|
|
cy.intercept("DELETE", "**/house/current", (req) => {
|
|
houseDeleted = true;
|
|
req.reply({ statusCode: 204 });
|
|
}).as("deleteHouse");
|
|
|
|
cy.visit("/parametres/foyer");
|
|
cy.contains("button", "Supprimer le foyer").click();
|
|
cy.contains("button", "Confirmer la suppression").click();
|
|
|
|
cy.wait("@deleteHouse");
|
|
cy.contains("Créer un foyer").should("be.visible");
|
|
});
|
|
});
|
|
|
|
describe("Household settings (/parametres/foyer) — as a non-admin member", () => {
|
|
beforeEach(() => {
|
|
cy.intercept("GET", "**/auth/me", {
|
|
statusCode: 200,
|
|
body: { ...adminProfile, id: 2, firstName: "Bob", lastName: "Dupont", houseId: 1 },
|
|
});
|
|
cy.intercept("GET", "**/house/current", { statusCode: 200, body: houseWithTwoMembers });
|
|
});
|
|
|
|
it("offers to leave the household instead of deleting it", () => {
|
|
cy.visit("/parametres/foyer");
|
|
|
|
cy.contains("button", "Quitter le foyer").should("be.visible");
|
|
cy.contains("button", "Supprimer le foyer").should("not.exist");
|
|
});
|
|
|
|
it("leaves the household", () => {
|
|
cy.intercept("POST", "**/house/leave", { statusCode: 204 }).as("leaveHouse");
|
|
|
|
cy.visit("/parametres/foyer");
|
|
cy.contains("button", "Quitter le foyer").click();
|
|
|
|
cy.wait("@leaveHouse");
|
|
});
|
|
});
|