1010namespace Magento \Checkout \Controller ;
1111
1212use Magento \Catalog \Api \ProductRepositoryInterface ;
13- use Magento \Checkout \Model \Session ;
13+ use Magento \Catalog \Model \Product ;
14+ use Magento \Catalog \Test \Fixture \Product as ProductFixture ;
15+ use Magento \CatalogInventory \Api \StockItemRepositoryInterface ;
1416use Magento \Checkout \Model \Session as CheckoutSession ;
1517use Magento \Customer \Model \ResourceModel \CustomerRepository ;
1618use Magento \Framework \Data \Form \FormKey ;
1719use Magento \Framework \Api \SearchCriteriaBuilder ;
20+ use Magento \Framework \Exception \LocalizedException ;
21+ use Magento \Framework \Exception \NoSuchEntityException ;
22+ use Magento \Quote \Api \Data \CartInterface ;
23+ use Magento \Quote \Api \Data \CartItemInterface ;
1824use Magento \Quote \Model \Quote ;
1925use Magento \Quote \Api \CartRepositoryInterface ;
26+ use Magento \Quote \Model \QuoteRepository ;
27+ use Magento \Quote \Test \Fixture \AddProductToCart ;
28+ use Magento \Quote \Test \Fixture \GuestCart ;
29+ use Magento \TestFramework \Fixture \DataFixture ;
30+ use Magento \TestFramework \Fixture \DataFixtureStorage ;
31+ use Magento \TestFramework \Fixture \DataFixtureStorageManager ;
2032use Magento \TestFramework \Helper \Bootstrap ;
2133use Magento \TestFramework \Request ;
2234use Magento \Customer \Model \Session as CustomerSession ;
@@ -33,6 +45,16 @@ class CartTest extends \Magento\TestFramework\TestCase\AbstractController
3345 /** @var CheckoutSession */
3446 private $ checkoutSession ;
3547
48+ /**
49+ * @var ProductRepositoryInterface
50+ */
51+ private $ productRepository ;
52+
53+ /**
54+ * @var DataFixtureStorage
55+ */
56+ private $ fixtures ;
57+
3658 /**
3759 * @inheritdoc
3860 */
@@ -41,6 +63,8 @@ protected function setUp(): void
4163 parent ::setUp ();
4264 $ this ->checkoutSession = $ this ->_objectManager ->get (CheckoutSession::class);
4365 $ this ->_objectManager ->addSharedInstance ($ this ->checkoutSession , CheckoutSession::class);
66+ $ this ->productRepository = $ this ->_objectManager ->create (ProductRepositoryInterface::class);
67+ $ this ->fixtures = DataFixtureStorageManager::getStorage ();
4468 }
4569
4670 /**
@@ -370,7 +394,7 @@ public function testReorderItems(bool $loggedIn, string $request)
370394 $ customerSession = $ this ->_objectManager ->get (CustomerSession::class);
371395 $ customerSession ->logout ();
372396
373- $ checkoutSession = Bootstrap::getObjectManager ()->get (Session ::class);
397+ $ checkoutSession = Bootstrap::getObjectManager ()->get (CheckoutSession ::class);
374398 $ expected = [];
375399 if ($ loggedIn && $ request == Request::METHOD_POST ) {
376400 $ customer = $ this ->_objectManager ->create (CustomerRepository::class)->get ('customer2@example.com ' );
@@ -447,4 +471,133 @@ private function prepareRequest(string $method)
447471 break ;
448472 }
449473 }
474+
475+ /**
476+ * @throws NoSuchEntityException
477+ * @throws LocalizedException
478+ */
479+ #[
480+ DataFixture(ProductFixture::class, ['sku ' => 's1 ' , 'stock_item ' => ['is_in_stock ' => true ]], 'p1 ' ),
481+ DataFixture(ProductFixture::class, ['sku ' => 's2 ' ,'stock_item ' => ['is_in_stock ' => true ]], 'p2 ' ),
482+ DataFixture(GuestCart::class, as: 'cart ' ),
483+ DataFixture(
484+ AddProductToCart::class,
485+ ['cart_id ' => '$cart.id$ ' , 'product_id ' => '$p1.id$ ' , 'qty ' => 1 ],
486+ 'item1 '
487+ ),
488+ DataFixture(
489+ AddProductToCart::class,
490+ ['cart_id ' => '$cart.id$ ' , 'product_id ' => '$p2.id$ ' , 'qty ' => 1 ],
491+ 'item2 '
492+ )
493+ ]
494+ public function testUpdatePostActionWithMultipleProducts ()
495+ {
496+ $ cartId = (int )$ this ->fixtures ->get ('cart ' )->getId ();
497+ if (!$ cartId ) {
498+ $ this ->fail ('quote fixture failed ' );
499+ }
500+ /** @var QuoteRepository $quoteRepository */
501+ $ quoteRepository = Bootstrap::getObjectManager ()->get (QuoteRepository::class);
502+ $ quote = $ quoteRepository ->get ($ cartId );
503+
504+ $ checkoutSession = Bootstrap::getObjectManager ()->get (CheckoutSession::class);
505+ $ checkoutSession ->setQuoteId ($ quote ->getId ());
506+
507+ /** @var \Magento\Quote\Model\Quote\Item $item1 */
508+ $ item1 = $ this ->fixtures ->get ('item1 ' );
509+ /** @var \Magento\Quote\Model\Quote\Item $item2 */
510+ $ item2 = $ this ->fixtures ->get ('item2 ' );
511+
512+ $ p1 = $ this ->fixtures ->get ('p1 ' );
513+ /** @var $p1 Product */
514+ $ product1 = $ this ->productRepository ->get ($ p1 ->getSku (), true );
515+ $ stockItem = $ product1 ->getExtensionAttributes ()->getStockItem ();
516+ $ stockItem ->setQty (0 );
517+ $ stockItem ->setIsInStock (false );
518+ $ stockItemRepository = Bootstrap::getObjectManager ()->get (StockItemRepositoryInterface::class);
519+ $ stockItemRepository ->save ($ stockItem );
520+
521+ $ originalQuantity = 1 ;
522+ $ updatedQuantity = 2 ;
523+
524+ $ this ->assertEquals (
525+ $ originalQuantity + $ originalQuantity ,
526+ $ quote ->getItemsQty (),
527+ "Precondition failed: quote totals does not match. "
528+ );
529+
530+ $ response = $ this ->updatePostRequest ($ quote , $ item1 , $ item2 , $ updatedQuantity , $ updatedQuantity , true );
531+
532+ $ this ->assertStringContainsString (
533+ '"itemId": ' .$ item1 ->getId ().'}] ' ,
534+ $ response ['error_message ' ]
535+ );
536+
537+ $ response = $ this ->updatePostRequest ($ quote , $ item1 , $ item2 , $ originalQuantity , $ updatedQuantity , false );
538+
539+ $ this ->assertStringContainsString (
540+ '"itemId": ' .$ item1 ->getId ().'}] ' ,
541+ $ response ['error_message ' ]
542+ );
543+ $ this ->assertEquals (
544+ $ originalQuantity + $ updatedQuantity ,
545+ $ quote ->getItemsQty (),
546+ "Precondition failed: quote totals does not match. "
547+ );
548+
549+ $ response = $ this ->updatePostRequest ($ quote , $ item1 , $ item2 , $ updatedQuantity , $ updatedQuantity , false );
550+
551+ $ this ->assertStringContainsString (
552+ '"itemId": ' .$ item1 ->getId ().'}] ' ,
553+ $ response ['error_message ' ]
554+ );
555+ $ this ->assertEquals (
556+ $ originalQuantity + $ updatedQuantity ,
557+ $ quote ->getItemsQty (),
558+ "Precondition failed: quote totals does not match. "
559+ );
560+ }
561+
562+ /**
563+ * @param CartInterface $quote
564+ * @param CartItemInterface $item1
565+ * @param CartItemInterface $item2
566+ * @param float $qty1
567+ * @param float $qty2
568+ * @param bool $updateQty
569+ * @return mixed
570+ * @throws LocalizedException
571+ */
572+ private function updatePostRequest (
573+ CartInterface $ quote ,
574+ CartItemInterface $ item1 ,
575+ CartItemInterface $ item2 ,
576+ float $ qty1 ,
577+ float $ qty2 ,
578+ bool $ updateQty = true
579+ ): array {
580+ /** @var FormKey $formKey */
581+ $ formKey = Bootstrap::getObjectManager ()->get (FormKey::class);
582+
583+ $ request = [
584+ 'cart ' => [
585+ $ item1 ->getId () => ['qty ' => $ qty1 ],
586+ $ item2 ->getId () => ['qty ' => $ qty2 ]
587+ ],
588+ 'update_cart_action ' => 'update_qty ' ,
589+ 'form_key ' => $ formKey ->getFormKey (),
590+ ];
591+ $ this ->getRequest ()->setMethod (HttpRequest::METHOD_POST );
592+ $ this ->getRequest ()->setPostValue ($ request );
593+ if ($ updateQty ) {
594+ $ this ->dispatch ('checkout/cart/updateItemQty ' );
595+ } else {
596+ $ this ->dispatch ('checkout/cart/updatePost ' );
597+ $ quote ->collectTotals ();
598+ }
599+ $ response = $ this ->getResponse ()->getBody ();
600+ $ response = json_decode ($ response , true );
601+ return $ response ;
602+ }
450603}
0 commit comments