fix(web): fix cross-feature step discovery and slash-alternation bug
La CI de la refonte précédente (commitaaace15) a échoué : la découverte par défaut du préprocesseur ne charge, pour un fichier `foo.feature`, QUE `foo.ts` (co-localisé, même basename) et `cypress/support/step_definitions/**` — pas les autres `.ts` du dossier `cypress/e2e/`. onboarding.feature référençait donc des steps qui ne vivaient que dans preferences.ts, household-settings.ts et auth.ts, introuvables lors de son propre run. Déplace les steps réellement partagés entre plusieurs .feature vers cypress/support/step_definitions/ (chargé pour toutes les features) : - reference-data.steps.ts : mocks des listes de référence régimes/ allergies (options ou vides) — partagé entre auth.feature et onboarding.feature - household-mutations.steps.ts : création/adhésion à un foyer et leurs assertions — partagé entre household-settings.feature et onboarding.feature - profile-mutations.steps.ts : sélection du régime, mise à jour des allergies et leur assertion — partagé entre preferences.feature et onboarding.feature Les définitions d'origine sont retirées de auth.ts/household- settings.ts/onboarding.ts/preferences.ts pour éviter un step "Ambiguous" (chargé deux fois pour la feature qui les définissait déjà elle-même). Corrige aussi un second bug distinct révélé par la même CI : "the ingredient/diet catalog is available" (recipe-form.feature) contient un "/" non échappé — en syntaxe Cucumber Expression, "/" hors d'un paramètre {..} signifie une alternative de texte ("ingredient" OU "diet catalog is available"), jamais le caractère littéral. Le texte du .feature ne pouvait donc jamais matcher. Renommé sans "/" : "the ingredient and diet catalog is available". Le script de vérification statique utilisé pour valideraaace15avant push donnait une fausse confiance : il regroupait tous les steps de tous les fichiers comme disponibles globalement pour chaque feature, sans respecter ce scoping réel. Réécrit pour ne charger, par feature, que son fichier co-localisé + step_definitions/ — et pour détecter les patterns contenant un "/" non échappé. Résultat : toujours 246 steps, 0 non résolu, 0 ambigu, 0 pattern à slash non échappé, cette fois avec un modèle de résolution fidèle au comportement réel du préprocesseur.
This commit is contained in:
parent
aaace15b51
commit
37cf6d4dcd
9 changed files with 125 additions and 90 deletions
|
|
@ -26,10 +26,6 @@ Given("the signup request will fail because the email is already used", () => {
|
|||
}).as("signup");
|
||||
});
|
||||
|
||||
Given("the diets reference list is empty", () => {
|
||||
cy.intercept("GET", "**/reference/diets", { statusCode: 200, body: [] });
|
||||
});
|
||||
|
||||
When("I sign up with:", (dataTable: DataTable) => {
|
||||
const { firstName, lastName, email, password } = dataTable.rowsHash();
|
||||
cy.visit("/signup");
|
||||
|
|
|
|||
|
|
@ -15,40 +15,9 @@ 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");
|
||||
});
|
||||
// Creating/joining a household, and asserting on those two requests, is
|
||||
// shared with onboarding.feature's household step — see
|
||||
// cypress/support/step_definitions/household-mutations.steps.ts.
|
||||
|
||||
Given("renaming the household will succeed", () => {
|
||||
cy.intercept("PATCH", "**/house/current", {
|
||||
|
|
@ -88,17 +57,6 @@ When("I click {string} for the member {string}", (action: string, member: string
|
|||
cy.contains("li", member).contains("button", action).click();
|
||||
});
|
||||
|
||||
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 });
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,30 +10,6 @@ const signupResponse = {
|
|||
dietId: null,
|
||||
};
|
||||
|
||||
Given("the diets reference list has options", () => {
|
||||
cy.intercept("GET", "**/reference/diets", {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{ id: 1, key: "omnivore" },
|
||||
{ id: 2, key: "vegetarian" },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
Given("the allergies reference list has options", () => {
|
||||
cy.intercept("GET", "**/reference/allergies", {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{ id: 1, key: "peanuts", kind: "ALLERGY" },
|
||||
{ id: 2, key: "gluten", kind: "INTOLERANCE" },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
Given("the allergies reference list is empty", () => {
|
||||
cy.intercept("GET", "**/reference/allergies", { statusCode: 200, body: [] });
|
||||
});
|
||||
|
||||
// Signs up and lands on the wizard's first step (regime) — shared setup for
|
||||
// every scenario in this feature, mirroring `signupAndReachOnboarding` from
|
||||
// the pre-conversion spec.
|
||||
|
|
|
|||
|
|
@ -26,21 +26,9 @@ Given("the dietary preferences reference data is ready", () => {
|
|||
cy.intercept("GET", "**/profile/disliked-ingredients", { statusCode: 200, body: [] });
|
||||
});
|
||||
|
||||
Given("selecting the diet will succeed", () => {
|
||||
cy.intercept("PATCH", "**/profile/diet", { statusCode: 200, body: { dietId: 1 } }).as(
|
||||
"updateDiet",
|
||||
);
|
||||
});
|
||||
|
||||
Then("the diet update request should have been made with diet id {int}", (dietId: number) => {
|
||||
cy.wait("@updateDiet").its("request.body").should("deep.equal", { dietId });
|
||||
});
|
||||
|
||||
Given("updating allergies will succeed", () => {
|
||||
cy.intercept("PATCH", "**/profile/allergies", { statusCode: 200, body: [2, 1] }).as(
|
||||
"updateAllergies",
|
||||
);
|
||||
});
|
||||
// Selecting the diet, updating allergies, and asserting on the diet update
|
||||
// request are shared with onboarding.feature's regime/allergies steps — see
|
||||
// cypress/support/step_definitions/profile-mutations.steps.ts.
|
||||
|
||||
Then(
|
||||
"the allergies update request should have been made with allergy ids {int} and {int}",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Feature: Recipe form — associating ingredients
|
|||
Background:
|
||||
Given I am signed in as "Alice" "Martin"
|
||||
And my household id is 1
|
||||
And the ingredient/diet catalog is available
|
||||
And the ingredient and diet catalog is available
|
||||
|
||||
Scenario: Adds an ingredient from the picker, fills its quantity/unit, and creates the recipe
|
||||
Given creating the recipe will succeed and return id 42
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ const diets = [
|
|||
{ id: 2, key: "vegetarian" },
|
||||
];
|
||||
|
||||
Given("the ingredient/diet catalog is available", () => {
|
||||
Given("the ingredient and diet catalog is available", () => {
|
||||
cy.intercept("GET", "**/reference/ingredients", { statusCode: 200, body: [tomato, egg, carrot] });
|
||||
cy.intercept("GET", "**/reference/diets", { statusCode: 200, body: diets });
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
import { Given, Then } from "@badeball/cypress-cucumber-preprocessor";
|
||||
|
||||
// Shared across household-settings.feature (dedicated create/join scenarios)
|
||||
// and onboarding.feature (household step of the wizard) — both need to mock
|
||||
// the create/join mutations and their up-to-date `GET /house/current`
|
||||
// follow-up the same way.
|
||||
|
||||
const houseWithTwoMembers = {
|
||||
id: 1,
|
||||
name: "Chez Alice",
|
||||
adminId: 1,
|
||||
inviteCode: "ABCD2345",
|
||||
members: [
|
||||
{ id: 1, firstName: "Alice", lastName: "Martin" },
|
||||
{ id: 2, firstName: "Bob", lastName: "Dupont" },
|
||||
],
|
||||
};
|
||||
|
||||
// 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");
|
||||
});
|
||||
|
||||
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 });
|
||||
},
|
||||
);
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { Given, Then } from "@badeball/cypress-cucumber-preprocessor";
|
||||
|
||||
// Shared across preferences.feature (dedicated autosave scenarios) and
|
||||
// onboarding.feature (regime/allergies steps of the wizard) — both need the
|
||||
// same diet/allergies PATCH mocks and their request-body assertions.
|
||||
|
||||
Given("selecting the diet will succeed", () => {
|
||||
cy.intercept("PATCH", "**/profile/diet", { statusCode: 200, body: { dietId: 1 } }).as(
|
||||
"updateDiet",
|
||||
);
|
||||
});
|
||||
|
||||
Then("the diet update request should have been made with diet id {int}", (dietId: number) => {
|
||||
cy.wait("@updateDiet").its("request.body").should("deep.equal", { dietId });
|
||||
});
|
||||
|
||||
Given("updating allergies will succeed", () => {
|
||||
cy.intercept("PATCH", "**/profile/allergies", { statusCode: 200, body: [2, 1] }).as(
|
||||
"updateAllergies",
|
||||
);
|
||||
});
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import { Given } from "@badeball/cypress-cucumber-preprocessor";
|
||||
|
||||
// Shared across auth.feature (signup) and onboarding.feature (wizard) — both
|
||||
// need the diets/allergies reference lists mocked before reaching a step
|
||||
// that reads them, in either their "has options" or "is empty" shape.
|
||||
|
||||
Given("the diets reference list has options", () => {
|
||||
cy.intercept("GET", "**/reference/diets", {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{ id: 1, key: "omnivore" },
|
||||
{ id: 2, key: "vegetarian" },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
Given("the diets reference list is empty", () => {
|
||||
cy.intercept("GET", "**/reference/diets", { statusCode: 200, body: [] });
|
||||
});
|
||||
|
||||
Given("the allergies reference list has options", () => {
|
||||
cy.intercept("GET", "**/reference/allergies", {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{ id: 1, key: "peanuts", kind: "ALLERGY" },
|
||||
{ id: 2, key: "gluten", kind: "INTOLERANCE" },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
Given("the allergies reference list is empty", () => {
|
||||
cy.intercept("GET", "**/reference/allergies", { statusCode: 200, body: [] });
|
||||
});
|
||||
Loading…
Reference in a new issue