# 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 search filters items
- Location: tests\e2e\public.spec.js:32:3

# Error details

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

Locator: getByRole('heading', { name: /Chicken Sekuwa/i })
Expected: visible
Timeout: 10000ms
Error: element(s) not found

Call log:
  - Expect "toBeVisible" with timeout 10000ms
  - waiting for getByRole('heading', { name: /Chicken Sekuwa/i })

```

```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": sekuwa
  - button "Clear search"
  - paragraph: No dishes match “sekuwa”
  - paragraph: Try a different search, or browse the categories.
- 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();
  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();
      |                                                                          ^ Error: expect(locator).toBeVisible() failed
  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);
  127 |       await expect(page.locator('h1').first()).toBeVisible();
  128 |     }
  129 |   });
  130 | });
  131 | 
```