Les tests e2e (apps/web/cypress/e2e/) étaient de simples specs Cypress (.cy.ts), sans lien avec Cucumber alors qu'apps/api utilise déjà Gherkin pour ses propres tests BDD. Intègre @badeball/cypress-cucumber-preprocessor pour écrire les scénarios utilisateurs en Gherkin des deux côtés, même vocabulaire. - cypress.config.ts : specPattern sur *.feature, wiring du préprocesseur (esbuild bundler + plugin cucumber) - Les 11 fichiers .cy.ts sont remplacés par des paires .feature/.steps.ts (co-localisées, même nom) — conversion complète, comportement équivalent (mêmes intercepts, mêmes assertions) - cypress/support/step_definitions/common.steps.ts : steps partagés entre features (connexion, navigation, assertions génériques de texte/URL/champ) — globaux à toute la suite, réutilisables tels quels - cypress/support/profile.ts : profil du compte "connecté" courant, assemblé au fil de plusieurs Given avant le premier visit/When - README : nouvelle section "Cucumber (apps/web)" (miroir de la section existante pour apps/api), mise à jour des références aux anciens noms de fichiers .cy.ts (déjà obsolètes avant ce changement) Vérification : impossible d'exécuter Cypress dans cet environnement (crash Electron/GPU au lancement, limitation déjà documentée dans le README — reproductible sur main, indépendante de ce changement). À la place : - les 447 steps Gherkin des 11 .feature ont été vérifiés programmatiquement contre les 165 patterns de step enregistrés : 0 non résolu, 0 ambigu - les 11 .feature parsent correctement avec le parser Gherkin officiel (57 scénarios au total) - tous les .steps.ts passent `biome check` (syntaxe + style) sans erreur - CYPRESS_INSTALL_BINARY déjà géré (voir PR précédente) — le binaire est bien présent localement (`cypress verify` OK), donc le blocage est spécifiquement le sandbox GPU de cet environnement, pas l'installation La vraie exécution reste à vérifier via le job `e2e` de la CI GitHub Actions sur cette PR — c'est le chemin déjà documenté dans le README pour cet environnement précis.
120 lines
4 KiB
TypeScript
120 lines
4 KiB
TypeScript
import { Given, Then, When } from "@badeball/cypress-cucumber-preprocessor";
|
|
|
|
const houseWithTwoMembers = {
|
|
id: 1,
|
|
name: "Chez Alice",
|
|
adminId: 1,
|
|
inviteCode: "ABCD2345",
|
|
members: [
|
|
{ id: 1, firstName: "Alice", lastName: "Martin" },
|
|
{ id: 2, firstName: "Bob", lastName: "Dupont" },
|
|
],
|
|
};
|
|
|
|
Given("the household request returns the two-member household", () => {
|
|
cy.intercept("GET", "**/house/current", { statusCode: 200, body: houseWithTwoMembers });
|
|
});
|
|
|
|
// The page reloads `GET /house/current` right after each mutation below
|
|
// succeeds — these intercepts need to answer differently before/after that
|
|
// follow-up GET, hence a shared mutable flag rather than a single static
|
|
// `cy.intercept` (a later static one would just win for every request,
|
|
// including the initial page load).
|
|
|
|
Given("creating a household will succeed", () => {
|
|
const createdHouse = {
|
|
id: 1,
|
|
name: "Chez Alice",
|
|
adminId: 1,
|
|
inviteCode: "ABCD2345",
|
|
members: [{ id: 1, firstName: "Alice", lastName: "Martin" }],
|
|
};
|
|
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");
|
|
});
|
|
|
|
Given("joining a household will succeed", () => {
|
|
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");
|
|
});
|
|
|
|
Given("renaming the household will succeed", () => {
|
|
cy.intercept("PATCH", "**/house/current", {
|
|
statusCode: 200,
|
|
body: { ...houseWithTwoMembers, name: "Chez les Martin" },
|
|
}).as("renameHouse");
|
|
});
|
|
|
|
Given("removing Bob from the household will succeed", () => {
|
|
const householdWithoutBob = { ...houseWithTwoMembers, members: [houseWithTwoMembers.members[0]] };
|
|
let memberRemoved = false;
|
|
cy.intercept("GET", "**/house/current", (req) => {
|
|
req.reply({ statusCode: 200, body: memberRemoved ? householdWithoutBob : houseWithTwoMembers });
|
|
});
|
|
cy.intercept("DELETE", "**/house/members/2", (req) => {
|
|
memberRemoved = true;
|
|
req.reply({ statusCode: 200, body: householdWithoutBob });
|
|
}).as("removeMember");
|
|
});
|
|
|
|
Given("deleting the household will succeed", () => {
|
|
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");
|
|
});
|
|
|
|
Given("leaving the household will succeed", () => {
|
|
cy.intercept("POST", "**/house/leave", { statusCode: 204 }).as("leaveHouse");
|
|
});
|
|
|
|
When("I click {string} for the member {string}", (action: string, member: string) => {
|
|
cy.contains("li", member).contains("button", action).click();
|
|
});
|
|
|
|
Then("{string} should be marked as Admin", (member: string) => {
|
|
cy.contains(member).parent().contains("Admin");
|
|
});
|
|
|
|
Then("the household creation request should have been made with name {string}", (name: string) => {
|
|
cy.wait("@createHouse").its("request.body").should("deep.equal", { name });
|
|
});
|
|
|
|
Then(
|
|
"the household join request should have been made with invite code {string}",
|
|
(code: string) => {
|
|
cy.wait("@joinHouse").its("request.body").should("deep.equal", { inviteCode: code });
|
|
},
|
|
);
|
|
|
|
Then("the household rename request should have been made with name {string}", (name: string) => {
|
|
cy.wait("@renameHouse").its("request.body").should("deep.equal", { name });
|
|
});
|
|
|
|
Then("the member removal request should have been made", () => {
|
|
cy.wait("@removeMember");
|
|
});
|
|
|
|
Then("the household deletion request should have been made", () => {
|
|
cy.wait("@deleteHouse");
|
|
});
|
|
|
|
Then("the household leave request should have been made", () => {
|
|
cy.wait("@leaveHouse");
|
|
});
|