add e2e tests for lists and meals
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import { expect } from "@playwright/test";
|
||||
import { test } from "../fixtures";
|
||||
import { registerAndLogin, createList, addItem } from "../helpers";
|
||||
|
||||
test("a user can create a list", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
|
||||
await createList(page, "Weekly shop");
|
||||
|
||||
await expect(page.locator("h1")).toContainText("Weekly shop");
|
||||
await expect(page.locator(".empty-items")).toBeVisible();
|
||||
});
|
||||
|
||||
test("a user can add an item with a quantity", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createList(page, "Weekly shop");
|
||||
|
||||
await addItem(page, "Apple", "2");
|
||||
|
||||
// Quantity renders in parens to the left of the name.
|
||||
const row = page.locator(".item-row").filter({ hasText: "Apple" });
|
||||
await expect(row.locator(".item-qty")).toHaveText("(2)");
|
||||
await expect(row.locator("strong")).toHaveText("Apple");
|
||||
});
|
||||
|
||||
test("a user can check off an item", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createList(page, "Weekly shop");
|
||||
await addItem(page, "Apple");
|
||||
|
||||
const row = page.locator(".item-row").filter({ hasText: "Apple" });
|
||||
await row.locator(".check-button").click();
|
||||
|
||||
await expect(row).toHaveClass(/is-checked/);
|
||||
});
|
||||
|
||||
test("a user can edit an item via the actions modal", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createList(page, "Weekly shop");
|
||||
await addItem(page, "Apple", "2");
|
||||
|
||||
const row = page.locator(".item-row").filter({ hasText: "Apple" });
|
||||
await row.locator(".item-actions-button").click();
|
||||
|
||||
const dialog = row.locator("dialog.item-modal");
|
||||
await expect(dialog).toBeVisible();
|
||||
await dialog.locator('[id^="item-edit-name"]').fill("Banana");
|
||||
await dialog.locator('[id^="item-edit-quantity"]').fill("6");
|
||||
await dialog.locator('[id^="item-edit-save"]').click();
|
||||
|
||||
const updated = page.locator(".item-row").filter({ hasText: "Banana" });
|
||||
await expect(updated).toBeVisible();
|
||||
await expect(updated.locator(".item-qty")).toHaveText("(6)");
|
||||
});
|
||||
|
||||
test("a user can delete an item via the actions modal", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createList(page, "Weekly shop");
|
||||
await addItem(page, "Apple");
|
||||
|
||||
const row = page.locator(".item-row").filter({ hasText: "Apple" });
|
||||
await row.locator(".item-actions-button").click();
|
||||
|
||||
const dialog = row.locator("dialog.item-modal");
|
||||
await expect(dialog).toBeVisible();
|
||||
await dialog.locator('[id^="item-edit-delete"]').click();
|
||||
|
||||
await expect(page.locator(".item-row").filter({ hasText: "Apple" })).toHaveCount(0);
|
||||
await expect(page.locator(".empty-items")).toBeVisible();
|
||||
});
|
||||
|
||||
test("a user can add a category", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createList(page, "Weekly shop");
|
||||
|
||||
await page.fill("#category-name", "Bakery");
|
||||
await page.click("#add-category-button");
|
||||
|
||||
await expect(page.locator(".category-chip").filter({ hasText: "Bakery" })).toBeVisible();
|
||||
});
|
||||
+81
-14
@@ -1,21 +1,88 @@
|
||||
import { expect } from "@playwright/test";
|
||||
import { test } from "../fixtures";
|
||||
import { registerAndLogin } from "../helpers";
|
||||
import { registerAndLogin, createMeal, addIngredient } from "../helpers";
|
||||
|
||||
test("a user can create a meal", async ({ page }) => {
|
||||
test("a user can add an ingredient to a meal", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createMeal(page, "Spaghetti Bolognese", "");
|
||||
|
||||
await page.goto("/meals/new");
|
||||
await page.fill("#meal-name", "Spaghetti Bolognese");
|
||||
await page.fill("#meal-description", "## Ingredients\n\nA classic weeknight dinner.");
|
||||
await page.click('button:has-text("Save meal")');
|
||||
await addIngredient(page, "Penne", "500g");
|
||||
|
||||
// Lands on the meal detail page and renders the markdown description.
|
||||
await expect(page).toHaveURL(/\/meals\/\d+/);
|
||||
await expect(page.locator("h1")).toContainText("Spaghetti Bolognese");
|
||||
await expect(page.locator(".markdown h2")).toContainText("Ingredients");
|
||||
|
||||
// The meal appears on the meals index.
|
||||
await page.goto("/meals");
|
||||
await expect(page.locator(".list-card")).toContainText("Spaghetti Bolognese");
|
||||
const row = page.locator(".ingredient-list").filter({ hasText: "Penne" });
|
||||
await expect(row.locator(".item-qty")).toHaveText("(500g)");
|
||||
await expect(row.locator("strong")).toHaveText("Penne");
|
||||
});
|
||||
|
||||
test("a user can edit a meal name and description via the modal", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createMeal(page, "Spaghetti Bolognese", "A classic.");
|
||||
|
||||
await page.click('button:has-text("Edit")');
|
||||
const dialog = page.locator("dialog#meal-edit-modal");
|
||||
await expect(dialog).toBeVisible();
|
||||
await dialog.locator("#meal-edit-name").fill("Pasta al Pomodoro");
|
||||
await dialog.locator("#meal-edit-description").fill("## Ingredients\n\nA simple tomato sauce.");
|
||||
await dialog.locator("#meal-edit-save").click();
|
||||
|
||||
await expect(page.locator("h1")).toContainText("Pasta al Pomodoro");
|
||||
await expect(page.locator(".markdown h2")).toContainText("Ingredients");
|
||||
});
|
||||
|
||||
test("a user can delete a meal", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createMeal(page, "Spaghetti Bolognese", "");
|
||||
|
||||
await page.click('button:has-text("Delete")');
|
||||
await expect(page).toHaveURL(/\/meals$/);
|
||||
await expect(page.locator(".list-card").filter({ hasText: "Spaghetti Bolognese" })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("a user can edit an ingredient via the actions modal", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createMeal(page, "Spaghetti Bolognese", "");
|
||||
await addIngredient(page, "Penne", "500g");
|
||||
|
||||
const row = page.locator(".ingredient-list").filter({ hasText: "Penne" });
|
||||
await row.locator(".item-actions-button").click();
|
||||
|
||||
const dialog = row.locator("dialog.item-modal");
|
||||
await expect(dialog).toBeVisible();
|
||||
await dialog.locator('[id^="ingredient-edit-name"]').fill("Rigatoni");
|
||||
await dialog.locator('[id^="ingredient-edit-quantity"]').fill("400g");
|
||||
await dialog.locator('[id^="ingredient-edit-save"]').click();
|
||||
|
||||
const updated = page.locator(".ingredient-list").filter({ hasText: "Rigatoni" });
|
||||
await expect(updated).toBeVisible();
|
||||
await expect(updated.locator(".item-qty")).toHaveText("(400g)");
|
||||
});
|
||||
|
||||
test("a user can delete an ingredient via the actions modal", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createMeal(page, "Spaghetti Bolognese", "");
|
||||
await addIngredient(page, "Penne");
|
||||
|
||||
const row = page.locator(".ingredient-list").filter({ hasText: "Penne" });
|
||||
await row.locator(".item-actions-button").click();
|
||||
|
||||
const dialog = row.locator("dialog.item-modal");
|
||||
await expect(dialog).toBeVisible();
|
||||
await dialog.locator('[id^="ingredient-edit-delete"]').click();
|
||||
|
||||
await expect(page.locator(".ingredient-list").filter({ hasText: "Penne" })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("ingredients are grouped under their categories", async ({ page }) => {
|
||||
await registerAndLogin(page, "alice@example.com");
|
||||
await createMeal(page, "Spaghetti Bolognese", "");
|
||||
|
||||
// Add an ingredient in the default "Produce" category.
|
||||
await page.fill("#ingredient-name", "Tomato");
|
||||
await page.selectOption("#ingredient-category", { label: "Produce" });
|
||||
await page.click("#add-ingredient-button");
|
||||
|
||||
// Add one without a category.
|
||||
await addIngredient(page, "Penne");
|
||||
|
||||
await expect(page.locator(".category-heading").filter({ hasText: "Produce" })).toBeVisible();
|
||||
await expect(page.locator(".category-heading").filter({ hasText: "Uncategorized" })).toBeVisible();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user