diff --git a/e2e/helpers.ts b/e2e/helpers.ts index 21ec532..43265a6 100644 --- a/e2e/helpers.ts +++ b/e2e/helpers.ts @@ -21,6 +21,7 @@ export async function createMeal(page: Page, name: string, description: string) /** Creates a list and lands on its page. */ export async function createList(page: Page, name: string) { + await page.goto("/lists"); await page.fill("#list-name", name); await page.click('button:has-text("Create list")'); await expect(page).toHaveURL(/\/lists\/\d+/); @@ -45,3 +46,15 @@ export async function addIngredient(page: Page, name: string, quantity = "") { await page.click("#add-ingredient-button"); await expect(page.locator(".ingredient-list").filter({ hasText: name })).toBeVisible(); } + +/** Creates a meal and adds the given ingredients to it. */ +export async function createMealWithIngredients( + page: Page, + name: string, + ingredients: Array<{ name: string; quantity?: string }>, +) { + await createMeal(page, name, ""); + for (const ingredient of ingredients) { + await addIngredient(page, ingredient.name, ingredient.quantity ?? ""); + } +} diff --git a/e2e/tests/add-meal.spec.ts b/e2e/tests/add-meal.spec.ts new file mode 100644 index 0000000..d1963c0 --- /dev/null +++ b/e2e/tests/add-meal.spec.ts @@ -0,0 +1,54 @@ +import { expect } from "@playwright/test"; +import { test } from "../fixtures"; +import { registerAndLogin, createList, createMealWithIngredients } from "../helpers"; + +test("a user can add a meal's ingredients to a list via the picker", async ({ page }) => { + await registerAndLogin(page, "alice@example.com"); + await createMealWithIngredients(page, "Spaghetti Bolognese", [ + { name: "Penne", quantity: "500g" }, + { name: "Tomato", quantity: "2" }, + ]); + await createList(page, "Weekly shop"); + + // Open the add-meal picker. + await page.click(".add-meal-button"); + const picker = page.locator(".meal-picker-backdrop"); + await expect(picker).toBeVisible(); + await expect(picker.locator(".meal-picker-button").filter({ hasText: "Spaghetti Bolognese" })).toBeVisible(); + + // Select the meal. + await picker.locator(".meal-picker-button").filter({ hasText: "Spaghetti Bolognese" }).click(); + + // The picker closes and the meal's ingredients appear as items. + await expect(picker).toHaveCount(0); + await expect(page.locator(".item-row").filter({ hasText: "Penne" })).toBeVisible(); + await expect(page.locator(".item-row").filter({ hasText: "Tomato" })).toBeVisible(); + await expect(page.locator(".item-row").filter({ hasText: "Penne" }).locator(".item-qty")).toHaveText("(500g)"); +}); + +test("the add-meal picker closes via the close button", async ({ page }) => { + await registerAndLogin(page, "alice@example.com"); + await createMealWithIngredients(page, "Spaghetti Bolognese", [{ name: "Penne" }]); + await createList(page, "Weekly shop"); + + await page.click(".add-meal-button"); + const picker = page.locator(".meal-picker-backdrop"); + await expect(picker).toBeVisible(); + + await picker.locator(".meal-picker-close").click(); + await expect(picker).toHaveCount(0); +}); + +test("the add-meal picker closes when clicking outside", async ({ page }) => { + await registerAndLogin(page, "alice@example.com"); + await createMealWithIngredients(page, "Spaghetti Bolognese", [{ name: "Penne" }]); + await createList(page, "Weekly shop"); + + await page.click(".add-meal-button"); + const picker = page.locator(".meal-picker-backdrop"); + await expect(picker).toBeVisible(); + + // Click the backdrop itself (outside the modal card). + await picker.click({ position: { x: 5, y: 5 } }); + await expect(picker).toHaveCount(0); +});