# 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: shopping.spec.ts >> user sees quantity suggestions in shopping list
- Location: tests/shopping.spec.ts:175:5

# Error details

```
Error: expect(received).toEqual(expected) // deep equality

- Expected  - 1
+ Received  + 0

  Array [
    "500 г",
-   "500 мл",
  ]
```

# Page snapshot

```yaml
- generic [ref=e4]:
  - main "Список покупок" [ref=e5]:
    - generic [ref=e6]:
      - button "0" [ref=e7]:
        - generic [ref=e8]:
          - img [ref=e9]
          - generic [ref=e11]: "0"
      - button "add" [ref=e12]:
        - img [ref=e14]
    - dialog "В корзине":
      - generic [ref=e19]:
        - generic [ref=e21]:
          - generic [ref=e22]:
            - img [ref=e23]
            - img [ref=e26]
          - generic [ref=e28]: 7 из 7 куплено
        - list [ref=e30]:
          - listitem "Морковь" [ref=e31]:
            - button "Морковь" [ref=e32] [cursor=pointer]
            - generic:
              - img
              - generic:
                - generic: Морковь
              - button "Указать кол-во" [ref=e33] [cursor=pointer]:
                - img [ref=e34]
                - generic [ref=e36]: Указать кол-во
          - listitem "Перец чёрный" [ref=e37]:
            - button "Перец чёрный" [ref=e38] [cursor=pointer]
            - generic:
              - img
              - generic:
                - generic: Перец чёрный
                - generic: 1 рецепт
              - button "10 г" [ref=e39] [cursor=pointer]:
                - generic [ref=e40]: 10 г
                - img [ref=e41]
          - listitem "Соль" [ref=e43]:
            - button "Соль" [ref=e44] [cursor=pointer]
            - generic:
              - img
              - generic:
                - generic: Соль
                - generic: 1 рецепт
              - button "500 г" [ref=e45] [cursor=pointer]:
                - generic [ref=e46]: 500 г
                - img [ref=e47]
          - listitem "Помидоры" [ref=e49]:
            - button "Помидоры" [ref=e50] [cursor=pointer]
            - generic:
              - img
              - generic:
                - generic: Помидоры
                - generic: 1 рецепт • 200 г
              - button "200 г" [ref=e51] [cursor=pointer]:
                - generic [ref=e52]: 200 г
                - img [ref=e53]
          - listitem "Молоко" [ref=e55]:
            - button "Молоко" [ref=e56] [cursor=pointer]
            - generic:
              - img
              - generic:
                - generic: Молоко
                - generic: 1 рецепт • 500 мл
              - button "500 г" [active] [ref=e57] [cursor=pointer]:
                - generic [ref=e58]: 500 г
                - img [ref=e59]
          - listitem "Яйцо куриное" [ref=e61]:
            - button "Яйцо куриное" [ref=e62] [cursor=pointer]
            - generic:
              - img
              - generic:
                - generic: Яйцо куриное
                - generic: 1 рецепт • 2 шт
              - button "8 шт" [ref=e63] [cursor=pointer]:
                - generic [ref=e64]: 8 шт
                - img [ref=e65]
          - listitem "Говядина" [ref=e67]:
            - button "Говядина" [ref=e68] [cursor=pointer]
            - generic:
              - img
              - generic:
                - generic: Говядина
                - generic: 1 рецепт • 300 г
              - button "300 г" [ref=e69] [cursor=pointer]:
                - generic [ref=e70]: 300 г
                - img [ref=e71]
        - button "Завершить покупки" [ref=e74]:
          - generic [ref=e76]: Завершить покупки
  - navigation [ref=e77]:
    - button "Рецепты" [ref=e78] [cursor=pointer]:
      - img [ref=e79]
    - button "Журнал" [ref=e81] [cursor=pointer]:
      - img [ref=e82]
    - button "Есть дома" [ref=e84] [cursor=pointer]:
      - img [ref=e85]
    - button "Покупки" [ref=e87] [cursor=pointer]:
      - img [ref=e88]
    - button "Профиль" [ref=e90] [cursor=pointer]:
      - img [ref=e91]
```

# Test source

```ts
  273 |   // Говядина - recipe needs 600г (2x300g), previously bought 300г
  274 |   // 300г is below required amount so not auto-applied
  275 |   await markShoppingItemCompleted(page, "Говядина");
  276 |   expect(await getCompletedQuantity(page, "Говядина")).toBeUndefined();
  277 |   // Buy a larger, distinct amount so round 3 has two unique history entries
  278 |   await specifyCompletedQuantity(page, "Говядина", "Граммы", 500);
  279 |   expect(await getCompletedQuantity(page, "Говядина")).toBe("500 г");
  280 | 
  281 |   // Яйцо куриное - recipe needs 4шт (2x2), previously bought 10шт
  282 |   // 10шт >= 4шт so suggestion is auto-applied
  283 |   await markShoppingItemCompleted(page, "Яйцо куриное");
  284 |   expect(await getCompletedQuantity(page, "Яйцо куриное")).toBe("10 шт");
  285 |   // Override the auto-applied value to add a distinct history entry
  286 |   await specifyCompletedQuantity(page, "Яйцо куриное", "Штуки", 8);
  287 |   expect(await getCompletedQuantity(page, "Яйцо куриное")).toBe("8 шт");
  288 | 
  289 |   // Молоко - recipe needs 1000мл (2x500ml), previously bought 500г (different unit!)
  290 |   // Cross-unit comparison can't prove sufficiency, so not auto-applied
  291 |   await markShoppingItemCompleted(page, "Молоко");
  292 |   expect(await getCompletedQuantity(page, "Молоко")).toBeUndefined();
  293 |   // This time buy in the recipe's unit so the suggestion survives round 3
  294 |   await specifyCompletedQuantity(page, "Молоко", "Миллилитры", 500);
  295 |   expect(await getCompletedQuantity(page, "Молоко")).toBe("500 мл");
  296 | 
  297 |   // Помидоры - recipe needs 400г (2x200g), previously bought 200г
  298 |   // 200г is below required amount so not auto-applied
  299 |   await markShoppingItemCompleted(page, "Помидоры");
  300 |   expect(await getCompletedQuantity(page, "Помидоры")).toBeUndefined();
  301 |   // Buy 200г again (same as round 1) - exercises dedup in round 3 (#94)
  302 |   await specifyCompletedQuantity(page, "Помидоры", "Граммы", 200);
  303 |   expect(await getCompletedQuantity(page, "Помидоры")).toBe("200 г");
  304 | 
  305 |   // Соль - no recipe requirement, previously bought 500г → auto-applied
  306 |   await markShoppingItemCompleted(page, "Соль");
  307 |   expect(await getCompletedQuantity(page, "Соль")).toBe("500 г");
  308 |   // Keep 500г (same as round 1) - exercises dedup in round 3 (#94)
  309 |   await specifyCompletedQuantity(page, "Соль", "Граммы", 500);
  310 |   expect(await getCompletedQuantity(page, "Соль")).toBe("500 г");
  311 | 
  312 |   // Перец чёрный - no recipe requirement, round 1 was unspecified so no suggestion
  313 |   await markShoppingItemCompleted(page, "Перец чёрный");
  314 |   expect(await getCompletedQuantity(page, "Перец чёрный")).toBeUndefined();
  315 |   // Record a first concrete quantity so round 3 has something to suggest
  316 |   await specifyCompletedQuantity(page, "Перец чёрный", "Граммы", 10);
  317 |   expect(await getCompletedQuantity(page, "Перец чёрный")).toBe("10 г");
  318 | 
  319 |   // Морковь (manual) - not in any recipe, no preselected quantity expected
  320 |   await markShoppingItemCompleted(page, "Морковь");
  321 |   expect(await getCompletedQuantity(page, "Морковь")).toBeUndefined();
  322 |   // Buy a different amount than round 1 (250г vs 400г)
  323 |   await specifyCompletedQuantity(page, "Морковь", "Граммы", 250);
  324 |   expect(await getCompletedQuantity(page, "Морковь")).toBe("250 г");
  325 | 
  326 |   // Complete shopping to record history, then reset stock
  327 |   await completeShopping(page);
  328 |   await goToLeftovers(page);
  329 |   await markLeftoverAsLost(page, "Говядина");
  330 |   await markLeftoverAsLost(page, "Яйцо куриное");
  331 |   await markLeftoverAsLost(page, "Молоко");
  332 |   await markLeftoverAsLost(page, "Помидоры");
  333 |   await markLeftoverAsLost(page, "Соль");
  334 |   await markLeftoverAsLost(page, "Перец чёрный");
  335 |   await markLeftoverAsLost(page, "Морковь");
  336 | 
  337 |   // ------------------------------------------------------------------
  338 |   // Round 3: clear meal plans and re-plan once (1x requirements) so the
  339 |   // widest possible set of past purchases qualifies as suggestions.
  340 |   // Then verify suggestions via the modal — including dedup behavior
  341 |   // from issue #94 and full-history behavior for the manual ingredient.
  342 |   // ------------------------------------------------------------------
  343 |   await user.kitchen.cleanMealPlans();
  344 |   await addRecipeToMealPlan(page, recipeTitle, "Ужин");
  345 |   await goToShopping(page);
  346 | 
  347 |   await addToShoppingList(page, "Морковь");
  348 | 
  349 |   // Mark all items as completed so we can open the edit-quantity modal
  350 |   await markShoppingItemCompleted(page, "Говядина");
  351 |   await markShoppingItemCompleted(page, "Яйцо куриное");
  352 |   await markShoppingItemCompleted(page, "Молоко");
  353 |   await markShoppingItemCompleted(page, "Помидоры");
  354 |   await markShoppingItemCompleted(page, "Соль");
  355 |   await markShoppingItemCompleted(page, "Перец чёрный");
  356 |   await markShoppingItemCompleted(page, "Морковь");
  357 | 
  358 |   // Говядина - history [300г, 500г], both ≥ 300г recipe requirement
  359 |   expect(await getQuantitySuggestions(page, "Говядина")).toEqual([
  360 |     "300 г",
  361 |     "500 г",
  362 |   ]);
  363 | 
  364 |   // Яйцо куриное - history [10шт, 8шт], both ≥ 2шт recipe requirement
  365 |   // Sorted ascending
  366 |   expect(await getQuantitySuggestions(page, "Яйцо куриное")).toEqual([
  367 |     "8 шт",
  368 |     "10 шт",
  369 |   ]);
  370 | 
  371 |   // Молоко - history [500г WEIGHT, 500мл VOLUME], recipe requires 500мл.
  372 |   // Milk has a known g↔ml ratio so both purchases cover the requirement.
> 373 |   expect(await getQuantitySuggestions(page, "Молоко")).toEqual([
      |                                                        ^ Error: expect(received).toEqual(expected) // deep equality
  374 |     "500 г",
  375 |     "500 мл",
  376 |   ]);
  377 | 
  378 |   // Помидоры - history [200г, 200г], same quantity must appear only once (#94)
  379 |   expect(await getQuantitySuggestions(page, "Помидоры")).toEqual(["200 г"]);
  380 | 
  381 |   // Соль - history [500г, 500г], same quantity must appear only once (#94)
  382 |   expect(await getQuantitySuggestions(page, "Соль")).toEqual(["500 г"]);
  383 | 
  384 |   // Перец чёрный - round 1 unspecified (filtered out), round 2 = 10г
  385 |   expect(await getQuantitySuggestions(page, "Перец чёрный")).toEqual(["10 г"]);
  386 | 
  387 |   // Морковь (manual, not in any recipe):
  388 |   //  - No preselected quantity — auto-apply should not fire for ingredients
  389 |   //    that aren't tied to any recipe requirement
  390 |   //  - Full shopping history shows as suggestions, unfiltered
  391 |   expect(await getCompletedQuantity(page, "Морковь")).toBeUndefined();
  392 |   expect(await getQuantitySuggestions(page, "Морковь")).toEqual([
  393 |     "250 г",
  394 |     "400 г",
  395 |   ]);
  396 | });
  397 | 
  398 | function getItem(page: Page, ingredientName: string) {
  399 |   return page.getByRole("listitem", { name: ingredientName });
  400 | }
  401 | 
```