import { Given, Then, When } from "@badeball/cypress-cucumber-preprocessor"; // Mocks the API via cy.intercept — this job doesn't run a live backend (see // .github/workflows/ci.yml); apps/api's own Mocha suite covers real API // behavior against a real database (see test/sources.test.ts). // // "the sources reference list has options"/"the household's enabled // sources are empty" resolve from cypress/support/step_definitions/ (the // preprocessor's step-lookup is *not* global across cypress/e2e/ — only a // 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", () => { cy.intercept("GET", "**/house/current/sources", { statusCode: 200, body: [1] }); }); Given("browsing TheMealDB returns some items", () => { cy.intercept("GET", "**/sources/theMealDb/browse*", { statusCode: 200, body: { items: [ { externalId: "52795", title: "Chicken Handi", picture: null, url: "https://www.themealdb.com/meal/52795", alreadyImported: true, recipeId: 2, }, { externalId: "9999", title: "Fish Pie", picture: null, url: "https://www.themealdb.com/meal/9999", alreadyImported: false, recipeId: null, }, ], nextCursor: null, }, }); }); Given("previewing TheMealDB item {string} is available", (externalId: string) => { cy.intercept("GET", `**/sources/theMealDb/preview/${externalId}`, { statusCode: 200, body: { sourceKey: "theMealDb", externalId, name: "Fish Pie", description: null, picture: null, portions: 4, sourceUrl: "https://www.themealdb.com/meal/9999", ingredients: [ { rawText: "1 onion", quantity: 1, ingredient: { id: 1, key: "onion", icon: "VEGETABLE", category: "freshProduce", subcategory: "vegetables", reproducible: false, allergens: [], diets: [], }, unit: null, }, { rawText: "some mystery paste", quantity: null, ingredient: null, unit: null }, ], steps: [ { description: "Cuire à la poêle.", picture: null, techSteps: [{ techStep: { id: 1, key: "cook" }, start: 0, end: 5 }], }, ], }, }); }); Then("I should see the source item {string}", (title: string) => { cy.contains(".recipe-table__name", title).should("be.visible"); }); When("I click the source item {string}", (title: string) => { cy.contains(".recipe-table__name", title).click(); }); Then("the source item {string} should be marked as already imported", (title: string) => { cy.contains("tr", title).find(".source-item-table__imported-badge").should("be.visible"); }); // ImportRecipePage (the review screen) loads its own ingredient/diet/unit // catalogs the same way RecipeFormPage does — "onion" matches the resolved // line in "previewing TheMealDB item ... is available" above, "salt" is // what "some mystery paste" (unresolved in that same fixture) gets // corrected to in the review-and-import scenario. Given("the ingredient and diet catalog is available for import", () => { cy.intercept("GET", "**/reference/ingredients", { statusCode: 200, body: [ { id: 1, key: "onion", icon: "VEGETABLE", category: "freshProduce", subcategory: "vegetables", allergens: [], diets: [], }, { id: 2, key: "salt", icon: "SPICE", category: "condimentsAndSpices", subcategory: "spices", allergens: [], diets: [], }, ], }); cy.intercept("GET", "**/reference/diets", { statusCode: 200, body: [{ id: 1, key: "omnivore" }], }); cy.intercept("GET", "**/reference/units", { statusCode: 200, body: [{ id: 1, key: "piece", type: "COUNT", toBaseFactor: 1 }], }); }); Given("importing the previewed item will succeed and return id {int}", (id: number) => { cy.intercept("POST", "**/sources/theMealDb/import/9999", { statusCode: 201, body: { id } }).as( "importRecipe", ); }); When("I choose an ingredient for the unresolved line {string}", (rawText: string) => { cy.contains(".import-recipe__unresolved-row", rawText) .contains("button", "Choisir un ingrédient") .click(); }); Then("the unresolved ingredients section should no longer be shown", () => { cy.get(".import-recipe__unresolved").should("not.exist"); }); Then( "the import request should have included ingredient {int} with quantity {int} and unitId {int}", (ingredientId: number, quantity: number, unitId: number) => { cy.wait("@importRecipe") .its("request.body.ingredients") .should("include.deep.members", [{ ingredientId, quantity, unitId }]); }, );