fix(web-tests): résout les steps Cucumber manquants dans recipe-sources.feature
La CI a révélé que la résolution des steps Cucumber n'est pas globale sur tout cypress/e2e/ comme je le pensais — seuls le fichier/dossier de même nom que la .feature et cypress/support/step_definitions/ sont cherchés (voir le message d'erreur de la CI). recipes.ts vit directement dans cypress/e2e/ (pas dans step_definitions/), donc ses steps ne résolvaient que pour recipes.feature — recipe-sources.feature qui les réutilisait plantait avec "Step implementation missing". - Les steps génériques réellement partagés entre les deux features (heading du panneau détail, technique surlignée, tooltip) migrent vers common.steps.ts (step_definitions/, cherché globalement) plutôt que d'être dupliqués une deuxième fois. - Les steps propres à un fixture précis (recipe 2's detail, disliked ingredients, catalogue vide) sont redéclarés localement dans recipe-sources.ts avec leurs propres données minimales — même précédent que recipes.cy.ts, qui duplique déjà indépendamment le fixture omeletteDetail plutôt que de dépendre de recipes.ts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
b5a12cf489
commit
a860363438
4 changed files with 76 additions and 27 deletions
|
|
@ -10,7 +10,7 @@ Feature: Browsing external recipe sources
|
||||||
And the planning request returns nothing
|
And the planning request returns nothing
|
||||||
|
|
||||||
Scenario: Prompts to enable a source when the household hasn't enabled any
|
Scenario: Prompts to enable a source when the household hasn't enabled any
|
||||||
Given the recipe catalog contains "Omelette"
|
Given the recipe catalog contains nothing
|
||||||
And the sources reference list has options
|
And the sources reference list has options
|
||||||
And the household's enabled sources are empty
|
And the household's enabled sources are empty
|
||||||
When I visit "/recettes"
|
When I visit "/recettes"
|
||||||
|
|
@ -18,7 +18,7 @@ Feature: Browsing external recipe sources
|
||||||
Then I should see "Aucune source n'est activée"
|
Then I should see "Aucune source n'est activée"
|
||||||
|
|
||||||
Scenario: Browses an enabled source, distinguishing already-imported items from new ones
|
Scenario: Browses an enabled source, distinguishing already-imported items from new ones
|
||||||
Given the recipe catalog contains "Omelette"
|
Given the recipe catalog contains nothing
|
||||||
And the sources reference list has options
|
And the sources reference list has options
|
||||||
And the household has enabled TheMealDB
|
And the household has enabled TheMealDB
|
||||||
And browsing TheMealDB returns some items
|
And browsing TheMealDB returns some items
|
||||||
|
|
@ -34,7 +34,7 @@ Feature: Browsing external recipe sources
|
||||||
And the recipe detail panel heading should be "Omelette"
|
And the recipe detail panel heading should be "Omelette"
|
||||||
|
|
||||||
Scenario: Previews a not-yet-imported item, highlighting its detected techniques
|
Scenario: Previews a not-yet-imported item, highlighting its detected techniques
|
||||||
Given the recipe catalog contains "Omelette"
|
Given the recipe catalog contains nothing
|
||||||
And the sources reference list has options
|
And the sources reference list has options
|
||||||
And the household has enabled TheMealDB
|
And the household has enabled TheMealDB
|
||||||
And browsing TheMealDB returns some items
|
And browsing TheMealDB returns some items
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,53 @@ import { Given, Then, When } from "@badeball/cypress-cucumber-preprocessor";
|
||||||
// .github/workflows/ci.yml); apps/api's own Mocha suite covers real API
|
// .github/workflows/ci.yml); apps/api's own Mocha suite covers real API
|
||||||
// behavior against a real database (see test/sources.test.ts).
|
// behavior against a real database (see test/sources.test.ts).
|
||||||
//
|
//
|
||||||
// "the sources reference list has options" (theMealDb id 1, marmiton id 2)
|
// "the sources reference list has options"/"the household's enabled
|
||||||
// and "recipe 2's detail is available" are shared with reference-data.steps.ts
|
// sources are empty" resolve from cypress/support/step_definitions/ (the
|
||||||
// / recipes.ts respectively — Cucumber step matching is global across every
|
// preprocessor's step-lookup is *not* global across cypress/e2e/ — only a
|
||||||
// step-definition file, not scoped per feature.
|
// feature's own same-named file/directory plus that shared folder are
|
||||||
|
// searched, see its error message when a step isn't found). recipes.ts
|
||||||
|
// sits directly in cypress/e2e/ (not that shared folder), so its own
|
||||||
|
// "the disliked ingredients list is empty"/"the recipe catalog
|
||||||
|
// contains"/"recipe 2's detail is available" are scoped to recipes.feature
|
||||||
|
// only — this file redeclares its own minimal equivalents rather than
|
||||||
|
// relocating shared infra, the same "each spec's own self-contained
|
||||||
|
// fixtures" precedent recipes.cy.ts already sets alongside recipes.ts.
|
||||||
|
|
||||||
|
Given("the disliked ingredients list is empty", () => {
|
||||||
|
cy.intercept("GET", "**/profile/disliked-ingredients", { statusCode: 200, body: [] });
|
||||||
|
});
|
||||||
|
|
||||||
|
Given("the recipe catalog contains nothing", () => {
|
||||||
|
cy.intercept("GET", /\/recipes\?/, { statusCode: 200, body: [] });
|
||||||
|
});
|
||||||
|
|
||||||
|
Given("recipe 2's detail is available", () => {
|
||||||
|
cy.intercept("GET", "**/recipes/2", {
|
||||||
|
statusCode: 200,
|
||||||
|
body: {
|
||||||
|
id: 2,
|
||||||
|
name: "Omelette",
|
||||||
|
description: null,
|
||||||
|
picture: null,
|
||||||
|
portions: 2,
|
||||||
|
authorId: 1,
|
||||||
|
visibility: "PERSONAL",
|
||||||
|
allergens: [],
|
||||||
|
diets: [],
|
||||||
|
isFavorite: false,
|
||||||
|
ingredients: [],
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
description: "Cuire à la poêle.",
|
||||||
|
picture: null,
|
||||||
|
order: 1,
|
||||||
|
techSteps: [{ techStep: { id: 1, key: "cook" }, start: 0, end: 5 }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Given("the household has enabled TheMealDB", () => {
|
Given("the household has enabled TheMealDB", () => {
|
||||||
cy.intercept("GET", "**/house/current/sources", { statusCode: 200, body: [1] });
|
cy.intercept("GET", "**/house/current/sources", { statusCode: 200, body: [1] });
|
||||||
|
|
|
||||||
|
|
@ -80,10 +80,6 @@ Then("the recipe {string} should not be marked as favorite", (name: string) => {
|
||||||
cy.contains(".recipe-table__name", name).find(".recipe-table__fav-mark").should("not.exist");
|
cy.contains(".recipe-table__name", name).find(".recipe-table__fav-mark").should("not.exist");
|
||||||
});
|
});
|
||||||
|
|
||||||
Then("the recipe detail panel heading should be {string}", (text: string) => {
|
|
||||||
cy.get(".recipe-detail-panel").contains("h2", text).should("be.visible");
|
|
||||||
});
|
|
||||||
|
|
||||||
When("I click the favorite star", () => {
|
When("I click the favorite star", () => {
|
||||||
cy.get(".favorite-star-button").click();
|
cy.get(".favorite-star-button").click();
|
||||||
});
|
});
|
||||||
|
|
@ -111,19 +107,3 @@ Then("the delete request should have been made", () => {
|
||||||
Then("the URL should match the recipes list", () => {
|
Then("the URL should match the recipes list", () => {
|
||||||
cy.url().should("match", /\/recettes\/?$/);
|
cy.url().should("match", /\/recettes\/?$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
Then("I should see the highlighted technique {string}", (text: string) => {
|
|
||||||
// The steps section sits below the panel's header/photo/description, off
|
|
||||||
// the fold of `.app-content`'s own scroll (see layout.cy.ts) — a bare
|
|
||||||
// `.should("be.visible")` doesn't auto-scroll, same fix as
|
|
||||||
// household-settings.feature's sources-section scenario.
|
|
||||||
cy.contains(".step-tech-step", text).scrollIntoView().should("be.visible");
|
|
||||||
});
|
|
||||||
|
|
||||||
When("I focus the highlighted technique {string}", (text: string) => {
|
|
||||||
cy.contains(".step-tech-step", text).focus();
|
|
||||||
});
|
|
||||||
|
|
||||||
Then("the tooltip should show {string}", (label: string) => {
|
|
||||||
cy.get(".tooltip__bubble").contains(label).should("be.visible");
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,32 @@ When("I scroll to the section {string}", (legend: string) => {
|
||||||
cy.contains("legend", legend).scrollIntoView();
|
cy.contains("legend", legend).scrollIntoView();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// `.recipe-detail-panel` is used by both a saved recipe's real detail
|
||||||
|
// (RecipeDetailPanel) and an unsaved source item's read-only preview
|
||||||
|
// (SourceItemPreviewPanel) — recipes.feature and recipe-sources.feature
|
||||||
|
// both need this.
|
||||||
|
Then("the recipe detail panel heading should be {string}", (text: string) => {
|
||||||
|
cy.get(".recipe-detail-panel").contains("h2", text).should("be.visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
// `.step-tech-step`/`.tooltip__bubble` come from StepDescription/Tooltip
|
||||||
|
// (components/ui/), rendered by both of those same two panels — same
|
||||||
|
// reasoning as the detail-panel-heading step above.
|
||||||
|
Then("I should see the highlighted technique {string}", (text: string) => {
|
||||||
|
// The steps section can sit below the panel's header/photo/description,
|
||||||
|
// off the fold of `.app-content`'s own scroll (see layout.cy.ts) — a
|
||||||
|
// bare `.should("be.visible")` doesn't auto-scroll.
|
||||||
|
cy.contains(".step-tech-step", text).scrollIntoView().should("be.visible");
|
||||||
|
});
|
||||||
|
|
||||||
|
When("I focus the highlighted technique {string}", (text: string) => {
|
||||||
|
cy.contains(".step-tech-step", text).focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
Then("the tooltip should show {string}", (label: string) => {
|
||||||
|
cy.get(".tooltip__bubble").contains(label).should("be.visible");
|
||||||
|
});
|
||||||
|
|
||||||
Then("the checkbox {string} should be checked", (label: string) => {
|
Then("the checkbox {string} should be checked", (label: string) => {
|
||||||
cy.contains("label", label).find("input[type=checkbox]").should("be.checked");
|
cy.contains("label", label).find("input[type=checkbox]").should("be.checked");
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue