# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: public.spec.js >> Public website >> menu page shows imported items with prices, search and categories
- Location: tests\e2e\public.spec.js:23:3

# Error details

```
Error: expect(locator).toBeVisible() failed

Locator: getByText('Americano').first()
Expected: visible
Timeout: 10000ms
Error: element(s) not found

Call log:
  - Expect "toBeVisible" with timeout 10000ms
  - waiting for getByText('Americano').first()

```

```yaml
- banner:
  - link "Kathmandu Momo logo Kathmandu Momo":
    - /url: /
    - img "Kathmandu Momo logo"
    - text: Kathmandu Momo
  - navigation "Primary":
    - link "Home":
      - /url: /
    - link "Menu":
      - /url: /menu
    - link "About":
      - /url: /about
    - link "Gallery":
      - /url: /gallery
    - link "Contact":
      - /url: /contact
  - link "Call":
    - /url: tel:+9779849216081
  - link "WhatsApp":
    - /url: https://wa.me/9779849216081?text=Hello%20Kathmandu%20Momo!%20I'd%20like%20to%20place%20an%20order.
- main:
  - heading "Our Menu" [level=1]
  - paragraph: 36 dishes across 7 categories — biryani, momo, sekuwa, coffee, snacks and fast food, served fresh at our counter in Surkhet.
  - searchbox "Search the menu"
  - tablist "Menu categories":
    - tab "All" [selected]
    - tab "Snacks"
    - tab "Soups"
    - tab "Mains"
    - tab "Noodles & Rice"
    - tab "Breads"
    - tab "Beverages"
    - tab "Desserts"
  - region "Snacks":
    - heading "Snacks" [level=2]
    - text: 8 items
    - article:
      - img "Chicken Momos (8pcs)"
      - heading "Chicken Momos (8pcs)" [level=3]
      - paragraph: Steamed chicken dumplings served with spicy sesame chutney
      - text: Rs. 220
      - button "Add Chicken Momos (8pcs)": Add
    - article:
      - img "Chicken Tikka"
      - heading "Chicken Tikka" [level=3]
      - paragraph: Tender chicken pieces marinated in yoghurt and hot spices
      - text: Rs. 320
      - button "Add Chicken Tikka": Add
    - article:
      - img "Chicken Wings"
      - heading "Chicken Wings" [level=3]
      - paragraph: Crispy fried chicken wings tossed in dry spices
      - text: Rs. 250
      - button "Add Chicken Wings": Add
    - article:
      - img "French Fries"
      - heading "French Fries" [level=3]
      - paragraph: Classic golden potato fries served with ketchup
      - text: Rs. 120
      - button "Add French Fries": Add
    - article:
      - img "Onion Rings"
      - heading "Onion Rings" [level=3]
      - paragraph: Deep fried battered onion rings, crisp and golden
      - text: Rs. 140
      - button "Add Onion Rings": Add
    - article:
      - img "Paneer Tikka"
      - heading "Paneer Tikka" [level=3]
      - paragraph: Marinated cottage cheese cubes grilled to perfection
      - text: Rs. 280
      - button "Add Paneer Tikka": Add
    - article:
      - img "Veg Momos (8pcs)"
      - heading "Veg Momos (8pcs)" [level=3]
      - paragraph: Nepali style steamed vegetable dumplings served with chutney
      - text: Rs. 150
      - button "Add Veg Momos (8pcs)": Add
    - article:
      - img "Vegetable Samosa"
      - heading "Vegetable Samosa" [level=3]
      - paragraph: Crispy pastry filled with spiced potatoes and peas
      - text: Rs. 120
      - button "Add Vegetable Samosa": Add
  - region "Soups":
    - heading "Soups" [level=2]
    - text: 3 items
    - article:
      - img "Hot & Sour Soup"
      - heading "Hot & Sour Soup" [level=3]
      - paragraph: Tangy and spicy thick vegetable soup
      - text: Rs. 130
      - button "Add Hot & Sour Soup": Add
    - article:
      - img "Mushroom Soup"
      - heading "Mushroom Soup" [level=3]
      - paragraph: Freshly pureed button mushroom soup with cream
      - text: Rs. 140
      - button "Add Mushroom Soup": Add
    - article:
      - img "Tomato Soup"
      - heading "Tomato Soup" [level=3]
      - paragraph: Creamy tomato soup flavored with garlic and herbs
      - text: Rs. 110
      - button "Add Tomato Soup": Add
  - region "Mains":
    - heading "Mains" [level=2]
    - text: 6 items
    - article:
      - img "Butter Chicken"
      - heading "Butter Chicken" [level=3]
      - paragraph: Boneless tandoori chicken cooked in smooth tomato-butter gravy
      - text: Rs. 450
      - button "Add Butter Chicken": Add
    - article:
      - text: Chicken Biryani
      - heading "Chicken Biryani" [level=3]
      - paragraph: Fragrant basmati rice layered with spiced chicken and herbs
      - text: Rs. 350
      - button "Add Chicken Biryani": Add
    - article:
      - text: Chicken Curry
      - heading "Chicken Curry" [level=3]
      - paragraph: Traditional homestyle chicken curry cooked with ground spices
      - text: Rs. 380
      - button "Add Chicken Curry": Add
    - article:
      - text: Dal Makhni
      - heading "Dal Makhni" [level=3]
      - paragraph: Slow cooked black lentils and kidney beans with butter and cream
      - text: Rs. 240
      - button "Add Dal Makhni": Add
    - article:
      - text: Paneer Butter Masala
      - heading "Paneer Butter Masala" [level=3]
      - paragraph: Paneer cubes in a rich, creamy onion-tomato gravy
      - text: Rs. 320
      - button "Add Paneer Butter Masala": Add
    - article:
      - text: Veg Thali
      - heading "Veg Thali" [level=3]
      - paragraph: Traditional platter with rice, dal, veg curry, pickle, and papad
      - text: Rs. 280
      - button "Add Veg Thali": Add
  - region "Noodles & Rice":
    - heading "Noodles & Rice" [level=2]
    - text: 6 items
    - article:
      - text: Chicken Chowmein
      - heading "Chicken Chowmein" [level=3]
      - paragraph: Wok-tossed noodles with shredded chicken and vegetables
      - text: Rs. 210
      - button "Add Chicken Chowmein": Add
    - article:
      - text: Jeera Rice
      - heading "Jeera Rice" [level=3]
      - paragraph: Fragrant rice tempered with cumin seeds and ghee
      - text: Rs. 120
      - button "Add Jeera Rice": Add
    - article:
      - text: Steam Rice
      - heading "Steam Rice" [level=3]
      - paragraph: Steamed premium basmati rice
      - text: Rs. 100
      - button "Add Steam Rice": Add
    - article:
      - text: Thukpa
      - heading "Thukpa" [level=3]
      - paragraph: Warm Sherpa style noodle soup with seasonal vegetables
      - text: Rs. 180
      - button "Add Thukpa": Add
    - article:
      - text: Veg Chowmein
      - heading "Veg Chowmein" [level=3]
      - paragraph: Stir-fried noodles with crisp vegetables and soy sauce
      - text: Rs. 160
      - button "Add Veg Chowmein": Add
    - article:
      - text: Veg Fried Rice
      - heading "Veg Fried Rice" [level=3]
      - paragraph: Wok-tossed rice with finely chopped vegetables and seasoning
      - text: Rs. 180
      - button "Add Veg Fried Rice": Add
  - region "Breads":
    - heading "Breads" [level=2]
    - text: 3 items
    - article:
      - text: Butter Naan
      - heading "Butter Naan" [level=3]
      - paragraph: Soft leavened clay oven bread topped with butter
      - text: Rs. 60
      - button "Add Butter Naan": Add
    - article:
      - text: Garlic Naan
      - heading "Garlic Naan" [level=3]
      - paragraph: Clay oven bread flavored with garlic and butter
      - text: Rs. 80
      - button "Add Garlic Naan": Add
    - article:
      - text: Plain Roti
      - heading "Plain Roti" [level=3]
      - paragraph: Traditional whole wheat flatbread baked in tandoor
      - text: Rs. 30
      - button "Add Plain Roti": Add
  - region "Beverages":
    - heading "Beverages" [level=2]
    - text: 6 items
    - article:
      - text: Coffee
      - heading "Coffee" [level=3]
      - paragraph: Hot brewed milk coffee
      - text: Rs. 80
      - button "Add Coffee": Add
    - article:
      - text: Coke
      - heading "Coke" [level=3]
      - paragraph: Chilled bottle of Coca-Cola
      - text: Rs. 60
      - button "Add Coke": Add
    - article:
      - text: Cold Coffee
      - heading "Cold Coffee" [level=3]
      - paragraph: Chilled blended milk coffee served with ice cream
      - text: Rs. 120
      - button "Add Cold Coffee": Add
    - article:
      - text: Fresh Lemonade
      - heading "Fresh Lemonade" [level=3]
      - paragraph: Freshly squeezed lemon juice with sugar syrup and water
      - text: Rs. 70
      - button "Add Fresh Lemonade": Add
    - article:
      - text: Masala Tea
      - heading "Masala Tea" [level=3]
      - paragraph: Traditional spiced milk tea brewed with cardamom and ginger
      - text: Rs. 50
      - button "Add Masala Tea": Add
    - article:
      - text: Sweet Lassi
      - heading "Sweet Lassi" [level=3]
      - paragraph: Sweetened refreshing yoghurt drink
      - text: Rs. 100
      - button "Add Sweet Lassi": Add
  - region "Desserts":
    - heading "Desserts" [level=2]
    - text: 4 items
    - article:
      - img "Gulab Jamun"
      - heading "Gulab Jamun" [level=3]
      - paragraph: Soft fried dough balls soaked in sweet sugar syrup
      - text: Rs. 90
      - button "Add Gulab Jamun": Add
    - article:
      - img "Ice Cream Scoop"
      - heading "Ice Cream Scoop" [level=3]
      - paragraph: Single scoop of vanilla, strawberry or chocolate ice cream
      - text: Rs. 90
      - button "Add Ice Cream Scoop": Add
    - article:
      - img "Kheer"
      - heading "Kheer" [level=3]
      - paragraph: Traditional slow-cooked sweet rice pudding with cardamom and nuts
      - text: Rs. 110
      - button "Add Kheer": Add
    - article:
      - img "Rasgulla"
      - heading "Rasgulla" [level=3]
      - paragraph: Spongy cottage cheese balls soaked in light sugar syrup
      - text: Rs. 80
      - button "Add Rasgulla": Add
- contentinfo:
  - text: Kathmandu Momo
  - paragraph: Momo, Nepali kitchen & café in Birendranagar, Surkhet.
  - heading "Explore" [level=3]
  - link "Home":
    - /url: /
  - link "Menu":
    - /url: /menu
  - link "About":
    - /url: /about
  - link "Gallery":
    - /url: /gallery
  - link "Contact":
    - /url: /contact
  - heading "Contact" [level=3]
  - link "+977 984-9216081":
    - /url: tel:+9779849216081
  - link:
    - /url: "mailto:"
  - link "Birendranagar, Surkhet, Karnali Province, Nepal":
    - /url: https://www.google.com/maps/search/?api=1&query=Kathmandu%20Momo%2C%20Birendranagar%2C%20Surkhet%2C%20Karnali%20Province%2C%20Nepal&center=28.5981066696641,81.61978015808363
  - heading "Follow" [level=3]
  - link "Facebook":
    - /url: ""
  - link "TikTok":
    - /url: ""
  - link "WhatsApp":
    - /url: https://wa.me/9779849216081?text=Hello%20Kathmandu%20Momo!%20I'd%20like%20to%20place%20an%20order.
  - text: © 2026 Kathmandu Momo. All rights reserved.
- alert
```

# Test source

```ts
  1   | import { test, expect } from '@playwright/test';
  2   | 
  3   | test.describe('Public website', () => {
  4   |   test('home renders identity, CTAs and contact', async ({ page }) => {
  5   |     const errors = [];
  6   |     page.on('console', (m) => m.type() === 'error' && errors.push(m.text()));
  7   | 
  8   |     await page.goto('/');
  9   |     await expect(page).toHaveTitle(/Kathmandu Momo/i);
  10  |     await expect(page.getByText('Kathmandu Momo').first()).toBeVisible();
  11  | 
  12  |     await expect(page.getByRole('link', { name: /menu/i }).first()).toBeVisible();
  13  | 
  14  |     const wa = page.getByRole('link', { name: /WhatsApp/i }).first();
  15  |     await expect(wa).toHaveAttribute('href', /wa\.me\/9779849216081/);
  16  | 
  17  |     const call = page.locator('a[href^="tel:+9779849216081"]:visible').first();
  18  |     await expect(call).toBeVisible();
  19  | 
  20  |     expect(errors.filter((e) => !/Failed to load resource|404/.test(e)), `console errors: ${errors.join('\n')}`).toEqual([]);
  21  |   });
  22  | 
  23  |   test('menu page shows imported items with prices, search and categories', async ({ page }) => {
  24  |     await page.goto('/menu');
  25  |     await expect(page).toHaveTitle(/Menu \| Kathmandu Momo/i);
> 26  |     await expect(page.getByText('Americano').first()).toBeVisible();
      |                                                       ^ Error: expect(locator).toBeVisible() failed
  27  |     await expect(page.getByText(/Rs\.?\s?120/).first()).toBeVisible();
  28  |     await expect(page.locator('input[type="search"]')).toBeVisible();
  29  |     await expect(page.locator('[role="tab"]').first()).toBeVisible();
  30  |   });
  31  | 
  32  |   test('menu search filters items', async ({ page }) => {
  33  |     await page.goto('/menu');
  34  |     await page.fill('input[type="search"]', 'sekuwa');
  35  |     await expect(page.getByRole('heading', { name: /Chicken Sekuwa/i })).toBeVisible();
  36  |     await expect(page.getByText('Americano')).toHaveCount(0);
  37  |   });
  38  | 
  39  |   test('menu images with a stored source actually load (real dimensions)', async ({ page }) => {
  40  |     await page.goto('/menu');
  41  |     // Trigger native lazy-loading across the whole page.
  42  |     await page.evaluate(async () => {
  43  |       for (let y = 0; y < document.body.scrollHeight; y += 500) {
  44  |         window.scrollTo(0, y);
  45  |         await new Promise((r) => setTimeout(r, 60));
  46  |       }
  47  |       window.scrollTo(0, 0);
  48  |     });
  49  |     await page.waitForTimeout(2000);
  50  |     const stats = await page.evaluate(() => {
  51  |       const imgs = [...document.querySelectorAll('main img')];
  52  |       return {
  53  |         total: imgs.length,
  54  |         loaded: imgs.filter((i) => i.complete && i.naturalWidth > 0).length,
  55  |         broken: imgs.filter((i) => i.complete && i.naturalWidth === 0).length,
  56  |       };
  57  |     });
  58  |     expect(stats.total).toBeGreaterThan(0);
  59  |     expect(stats.loaded).toBeGreaterThan(0);
  60  |     expect(stats.broken).toBe(0);
  61  |   });
  62  | 
  63  |   test('menu images are unique (no photo used twice)', async ({ page }) => {
  64  |     await page.goto('/menu');
  65  |     await page.evaluate(async () => {
  66  |       for (let y = 0; y < document.body.scrollHeight; y += 500) { window.scrollTo(0, y); await new Promise((r) => setTimeout(r, 50)); }
  67  |     });
  68  |     await page.waitForTimeout(1500);
  69  |     const srcs = await page.evaluate(() => [...document.querySelectorAll('main article img')].map((i) => i.getAttribute('src')));
  70  |     const dupes = srcs.filter((s, i) => srcs.indexOf(s) !== i);
  71  |     expect(dupes, `duplicate images: ${[...new Set(dupes)].join(', ')}`).toEqual([]);
  72  |   });
  73  | 
  74  |   test('ordering: add to cart offers WhatsApp + a place-order form', async ({ page }) => {
  75  |     await page.goto('/menu');
  76  |     await page.getByRole('button', { name: /^Add / }).first().click();
  77  |     await page.getByRole('button', { name: /View cart/i }).click();
  78  |     // WhatsApp is generated only after the canonical order has been saved.
  79  |     await expect(page.getByRole('button', { name: /Send via WhatsApp/i })).toBeVisible();
  80  |     // Form fields present
  81  |     await expect(page.getByPlaceholder('Your name *')).toBeVisible();
  82  |     await expect(page.getByPlaceholder('Phone number *')).toBeVisible();
  83  |     await expect(page.getByRole('button', { name: /Place Order/i })).toBeVisible();
  84  |   });
  85  | 
  86  |   test('ordering: placing an order succeeds', async ({ page }) => {
  87  |     await page.goto('/menu');
  88  |     await page.getByRole('button', { name: /^Add / }).first().click();
  89  |     await page.getByRole('button', { name: /View cart/i }).click();
  90  |     await page.getByPlaceholder('Your name *').fill('Playwright Tester');
  91  |     await page.getByPlaceholder('Phone number *').fill('9800000001');
  92  |     await page.getByRole('button', { name: /Place Order/i }).click();
  93  |     await expect(page.getByText(/Order received/i)).toBeVisible({ timeout: 15_000 });
  94  |   });
  95  | 
  96  |   test('no legacy Dim Sum / Sundar branding on active public pages', async ({ page }) => {
  97  |     for (const path of ['/', '/menu', '/about', '/gallery', '/contact']) {
  98  |       await page.goto(path);
  99  |       const body = await page.evaluate(() => document.body.innerText);
  100 |       expect(body, `legacy branding on ${path}`).not.toMatch(/dim\s*sum\s*puri|sundar|bagaicha/i);
  101 |     }
  102 |   });
  103 | 
  104 |   test('no horizontal overflow on mobile home', async ({ page }) => {
  105 |     await page.setViewportSize({ width: 375, height: 812 });
  106 |     await page.goto('/');
  107 |     const overflow = await page.evaluate(
  108 |       () => document.documentElement.scrollWidth > document.documentElement.clientWidth + 1
  109 |     );
  110 |     expect(overflow).toBe(false);
  111 |   });
  112 | 
  113 |   test('staff routes require login when signed out (full-service mode)', async ({ page }) => {
  114 |     for (const route of ['/waiter', '/kitchen', '/cashier']) {
  115 |       await page.goto(route);
  116 |       await expect(page).toHaveURL(/\/login/);
  117 |     }
  118 |   });
  119 | 
  120 |   test('about, gallery and contact pages load', async ({ page }) => {
  121 |     for (const [path, re] of [
  122 |       ['/about', /About \| Kathmandu Momo/i],
  123 |       ['/gallery', /Gallery \| Kathmandu Momo/i],
  124 |       ['/contact', /Contact & location|Contact &amp; location/i],
  125 |     ]) {
  126 |       await page.goto(path);
```