From 3de597cb25cec03ea560732b3bbed4cdf2c0e8bc Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <smankivskyi@ebay.com> Date: Fri, 27 Mar 2015 17:31:48 +0200 Subject: [PATCH] MAGETWO-21349: Advanced Mini Cart --- .../Controller/Sidebar/RemoveItem.php | 15 +- app/code/Magento/Checkout/Model/Sidebar.php | 29 +-- .../Controller/Sidebar/RemoveItemTest.php | 234 ++++++++++++++++++ .../Controller/Sidebar/UpdateItemQtyTest.php | 210 ++++++++++++++++ .../Checkout/Test/Unit/Model/SidebarTest.php | 233 +++++++++++++++++ 5 files changed, 703 insertions(+), 18 deletions(-) create mode 100644 app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/RemoveItemTest.php create mode 100644 app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/UpdateItemQtyTest.php create mode 100644 app/code/Magento/Checkout/Test/Unit/Model/SidebarTest.php diff --git a/app/code/Magento/Checkout/Controller/Sidebar/RemoveItem.php b/app/code/Magento/Checkout/Controller/Sidebar/RemoveItem.php index 90c0ad1ac4c..1097b3becf0 100644 --- a/app/code/Magento/Checkout/Controller/Sidebar/RemoveItem.php +++ b/app/code/Magento/Checkout/Controller/Sidebar/RemoveItem.php @@ -11,6 +11,7 @@ use Magento\Framework\App\Action\Context; use Magento\Framework\App\Response\Http; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Json\Helper\Data; +use Magento\Framework\View\Result\PageFactory; use Psr\Log\LoggerInterface; class RemoveItem extends Action @@ -30,15 +31,22 @@ class RemoveItem extends Action */ protected $jsonHelper; + /** + * @var PageFactory + */ + protected $resultPageFactory; + public function __construct( Context $context, Sidebar $sidebar, LoggerInterface $logger, - Data $jsonHelper + Data $jsonHelper, + PageFactory $resultPageFactory ) { $this->sidebar = $sidebar; $this->logger = $logger; $this->jsonHelper = $jsonHelper; + $this->resultPageFactory = $resultPageFactory; parent::__construct($context); } @@ -70,9 +78,8 @@ class RemoveItem extends Action { $response = $this->sidebar->getResponseData($error); if (isset($response['cleanup']) && (bool)$response['cleanup']) { - $this->_view->loadLayout(['default'], true, true, false); - $layout = $this->_view->getLayout(); - $block = $layout->getBlock('minicart.content')->toHtml(); + $resultPage = $this->resultPageFactory->create(); + $block = $resultPage->getLayout()->getBlock('minicart.content')->toHtml(); $response['content'] = $block; } return $this->getResponse()->representJson( diff --git a/app/code/Magento/Checkout/Model/Sidebar.php b/app/code/Magento/Checkout/Model/Sidebar.php index 7dc9fd93e8b..225c5c7323b 100644 --- a/app/code/Magento/Checkout/Model/Sidebar.php +++ b/app/code/Magento/Checkout/Model/Sidebar.php @@ -10,6 +10,7 @@ use Magento\Checkout\Model\Cart; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Locale\ResolverInterface; use Magento\Quote\Api\Data\CartItemInterface; +use Magento\Quote\Model\Quote\Address\Total; class Sidebar { @@ -56,25 +57,23 @@ class Sidebar */ public function getResponseData($error = '') { - $response = [ - 'success' => empty($error) ? true : false, - ]; - if ($response['success']) { - if (!$this->getSummaryQty()) { - $response['cleanup'] = true; - } - $response = array_merge($response, [ + if (empty($error)) { + $response = [ + 'success' => true, 'data' => [ 'summary_qty' => $this->getSummaryQty(), 'summary_text' => $this->getSummaryText(), 'subtotal' => $this->getSubtotalHtml(), ], - ]); - } - if (!empty($error)){ - $response = array_merge($response, [ + ]; + if (!$this->getSummaryQty()) { + $response['cleanup'] = true; + } + } else { + $response = [ + 'success' => false, 'error_message' => $error, - ]); + ]; } return $response; } @@ -171,7 +170,9 @@ class Sidebar protected function getSubtotalHtml() { $totals = $this->cart->getQuote()->getTotals(); - $subtotal = isset($totals['subtotal']) ? $totals['subtotal']->getValue() : 0; + $subtotal = isset($totals['subtotal']) && $totals['subtotal'] instanceof Total + ? $totals['subtotal']->getValue() + : 0; return $this->helperData->formatPrice($subtotal); } } diff --git a/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/RemoveItemTest.php b/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/RemoveItemTest.php new file mode 100644 index 00000000000..900693acec9 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/RemoveItemTest.php @@ -0,0 +1,234 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Test\Unit\Controller\Sidebar; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class RemoveItemTest extends \PHPUnit_Framework_TestCase +{ + /** @var \Magento\Checkout\Controller\Sidebar\RemoveItem */ + protected $removeItem; + + /** @var ObjectManagerHelper */ + protected $objectManagerHelper; + + /** @var \Magento\Checkout\Model\Sidebar|\PHPUnit_Framework_MockObject_MockObject */ + protected $sidebarMock; + + /** @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $loggerMock; + + /** @var \Magento\Framework\Json\Helper\Data|\PHPUnit_Framework_MockObject_MockObject */ + protected $jsonHelperMock; + + /** @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $requestMock; + + /** @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $responseMock; + + /** @var \Magento\Framework\View\Result\PageFactory|\PHPUnit_Framework_MockObject_MockObject */ + protected $resultPageFactoryMock; + + protected function setUp() + { + $this->sidebarMock = $this->getMock('Magento\Checkout\Model\Sidebar', [], [], '', false); + $this->loggerMock = $this->getMock('Psr\Log\LoggerInterface'); + $this->jsonHelperMock = $this->getMock('Magento\Framework\Json\Helper\Data', [], [], '', false); + $this->requestMock = $this->getMock('Magento\Framework\App\RequestInterface'); + $this->responseMock = $this->getMockForAbstractClass( + 'Magento\Framework\App\ResponseInterface', + [], + '', + false, + true, + true, + ['representJson'] + ); + $this->resultPageFactoryMock = $this->getMock('Magento\Framework\View\Result\PageFactory', [], [], '', false); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->removeItem = $this->objectManagerHelper->getObject( + 'Magento\Checkout\Controller\Sidebar\RemoveItem', + [ + 'sidebar' => $this->sidebarMock, + 'logger' => $this->loggerMock, + 'jsonHelper' => $this->jsonHelperMock, + 'request' => $this->requestMock, + 'response' => $this->responseMock, + 'resultPageFactory' => $this->resultPageFactoryMock, + ] + ); + } + + public function testExecute() + { + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('item_id', null) + ->willReturn('1'); + + $this->sidebarMock->expects($this->once()) + ->method('checkQuoteItem') + ->with(1) + ->willReturnSelf(); + $this->sidebarMock->expects($this->once()) + ->method('removeQuoteItem') + ->with(1) + ->willReturnSelf(); + $this->sidebarMock->expects($this->once()) + ->method('getResponseData') + ->with('') + ->willReturn( + [ + 'cleanup' => true, + 'data' => [ + 'summary_qty' => 0, + 'summary_text' => __(' items'), + 'subtotal' => 0, + ], + ] + ); + + $pageMock = $this->getMockBuilder('Magento\Framework\View\Result\Page') + ->disableOriginalConstructor() + ->getMock(); + + $this->resultPageFactoryMock->expects($this->once()) + ->method('create') + ->with(false, []) + ->willReturn($pageMock); + + $layoutMock = $this->getMockBuilder('Magento\Framework\View\LayoutInterface') + ->getMock(); + + $pageMock->expects($this->once()) + ->method('getLayout') + ->willReturn($layoutMock); + + $blockMock = $this->getMockBuilder('Magento\Framework\View\Element\BlockInterface') + ->getMock(); + + $layoutMock->expects($this->once()) + ->method('getBlock') + ->with('minicart.content') + ->willReturn($blockMock); + + $blockMock->expects($this->once()) + ->method('toHtml') + ->willReturn('block html'); + + $this->jsonHelperMock->expects($this->once()) + ->method('jsonEncode') + ->with( + [ + 'cleanup' => true, + 'data' => [ + 'summary_qty' => 0, + 'summary_text' => __(' items'), + 'subtotal' => 0, + ], + 'content' => 'block html', + ] + ) + ->willReturn('json encoded'); + + $this->responseMock->expects($this->once()) + ->method('representJson') + ->with('json encoded') + ->willReturn('json represented'); + + $this->assertEquals('json represented', $this->removeItem->execute()); + } + + public function testExecuteWithLocalizedException() + { + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('item_id', null) + ->willReturn('1'); + + $this->sidebarMock->expects($this->once()) + ->method('checkQuoteItem') + ->with(1) + ->willThrowException(new LocalizedException(__('Error message!'))); + + $this->sidebarMock->expects($this->once()) + ->method('getResponseData') + ->with('Error message!') + ->willReturn( + [ + 'success' => false, + 'error_message' => 'Error message!', + ] + ); + + $this->jsonHelperMock->expects($this->once()) + ->method('jsonEncode') + ->with( + [ + 'success' => false, + 'error_message' => 'Error message!', + ] + ) + ->willReturn('json encoded'); + + $this->responseMock->expects($this->once()) + ->method('representJson') + ->with('json encoded') + ->willReturn('json represented'); + + $this->assertEquals('json represented', $this->removeItem->execute()); + } + + public function testExecuteWithException() + { + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('item_id', null) + ->willReturn('1'); + + $exception = new \Exception('Error message!'); + + $this->sidebarMock->expects($this->once()) + ->method('checkQuoteItem') + ->with(1) + ->willThrowException($exception); + + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with($exception) + ->willReturn(null); + + $this->sidebarMock->expects($this->once()) + ->method('getResponseData') + ->with('Error message!') + ->willReturn( + [ + 'success' => false, + 'error_message' => 'Error message!', + ] + ); + + $this->jsonHelperMock->expects($this->once()) + ->method('jsonEncode') + ->with( + [ + 'success' => false, + 'error_message' => 'Error message!', + ] + ) + ->willReturn('json encoded'); + + $this->responseMock->expects($this->once()) + ->method('representJson') + ->with('json encoded') + ->willReturn('json represented'); + + $this->assertEquals('json represented', $this->removeItem->execute()); + } +} diff --git a/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/UpdateItemQtyTest.php b/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/UpdateItemQtyTest.php new file mode 100644 index 00000000000..b36cbed010b --- /dev/null +++ b/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/UpdateItemQtyTest.php @@ -0,0 +1,210 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Test\Unit\Controller\Sidebar; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class UpdateItemQtyTest extends \PHPUnit_Framework_TestCase +{ + /** @var \Magento\Checkout\Controller\Sidebar\UpdateItemQty */ + protected $updateItemQty; + + /** @var ObjectManagerHelper */ + protected $objectManagerHelper; + + /** @var \Magento\Checkout\Model\Sidebar|\PHPUnit_Framework_MockObject_MockObject */ + protected $sidebarMock; + + /** @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $loggerMock; + + /** @var \Magento\Framework\Json\Helper\Data|\PHPUnit_Framework_MockObject_MockObject */ + protected $jsonHelperMock; + + /** @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $requestMock; + + /** @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $responseMock; + + protected function setUp() + { + $this->sidebarMock = $this->getMock('Magento\Checkout\Model\Sidebar', [], [], '', false); + $this->loggerMock = $this->getMock('Psr\Log\LoggerInterface'); + $this->jsonHelperMock = $this->getMock('Magento\Framework\Json\Helper\Data', [], [], '', false); + $this->requestMock = $this->getMock('Magento\Framework\App\RequestInterface'); + $this->responseMock = $this->getMockForAbstractClass( + 'Magento\Framework\App\ResponseInterface', + [], + '', + false, + true, + true, + ['representJson'] + ); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->updateItemQty = $this->objectManagerHelper->getObject( + 'Magento\Checkout\Controller\Sidebar\UpdateItemQty', + [ + 'sidebar' => $this->sidebarMock, + 'logger' => $this->loggerMock, + 'jsonHelper' => $this->jsonHelperMock, + 'request' => $this->requestMock, + 'response' => $this->responseMock, + ] + ); + } + + public function testExecute() + { + $this->requestMock->expects($this->at(0)) + ->method('getParam') + ->with('item_id', null) + ->willReturn('1'); + $this->requestMock->expects($this->at(1)) + ->method('getParam') + ->with('item_qty', null) + ->willReturn('2'); + + $this->sidebarMock->expects($this->once()) + ->method('checkQuoteItem') + ->with(1) + ->willReturnSelf(); + $this->sidebarMock->expects($this->once()) + ->method('updateQuoteItem') + ->with(1, 2) + ->willReturnSelf(); + $this->sidebarMock->expects($this->once()) + ->method('getResponseData') + ->with('') + ->willReturn( + [ + 'data' => [ + 'summary_qty' => 2, + 'summary_text' => __(' items'), + 'subtotal' => 12.34, + ], + ] + ); + + $this->jsonHelperMock->expects($this->once()) + ->method('jsonEncode') + ->with( + [ + 'data' => [ + 'summary_qty' => 2, + 'summary_text' => __(' items'), + 'subtotal' => 12.34, + ], + ] + ) + ->willReturn('json encoded'); + + $this->responseMock->expects($this->once()) + ->method('representJson') + ->with('json encoded') + ->willReturn('json represented'); + + $this->assertEquals('json represented', $this->updateItemQty->execute()); + } + + public function testExecuteWithLocalizedException() + { + $this->requestMock->expects($this->at(0)) + ->method('getParam') + ->with('item_id', null) + ->willReturn('1'); + $this->requestMock->expects($this->at(1)) + ->method('getParam') + ->with('item_qty', null) + ->willReturn('2'); + + $this->sidebarMock->expects($this->once()) + ->method('checkQuoteItem') + ->with(1) + ->willThrowException(new LocalizedException(__('Error!'))); + + $this->sidebarMock->expects($this->once()) + ->method('getResponseData') + ->with('Error!') + ->willReturn( + [ + 'success' => false, + 'error_message' => 'Error!', + ] + ); + + $this->jsonHelperMock->expects($this->once()) + ->method('jsonEncode') + ->with( + [ + 'success' => false, + 'error_message' => 'Error!', + ] + ) + ->willReturn('json encoded'); + + $this->responseMock->expects($this->once()) + ->method('representJson') + ->with('json encoded') + ->willReturn('json represented'); + + $this->assertEquals('json represented', $this->updateItemQty->execute()); + } + + public function testExecuteWithException() + { + $this->requestMock->expects($this->at(0)) + ->method('getParam') + ->with('item_id', null) + ->willReturn('1'); + $this->requestMock->expects($this->at(1)) + ->method('getParam') + ->with('item_qty', null) + ->willReturn('2'); + + $exception = new \Exception('Error!'); + + $this->sidebarMock->expects($this->once()) + ->method('checkQuoteItem') + ->with(1) + ->willThrowException($exception); + + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with($exception) + ->willReturn(null); + + $this->sidebarMock->expects($this->once()) + ->method('getResponseData') + ->with('Error!') + ->willReturn( + [ + 'success' => false, + 'error_message' => 'Error!', + ] + ); + + $this->jsonHelperMock->expects($this->once()) + ->method('jsonEncode') + ->with( + [ + 'success' => false, + 'error_message' => 'Error!', + ] + ) + ->willReturn('json encoded'); + + $this->responseMock->expects($this->once()) + ->method('representJson') + ->with('json encoded') + ->willReturn('json represented'); + + $this->assertEquals('json represented', $this->updateItemQty->execute()); + } +} diff --git a/app/code/Magento/Checkout/Test/Unit/Model/SidebarTest.php b/app/code/Magento/Checkout/Test/Unit/Model/SidebarTest.php new file mode 100644 index 00000000000..c928db0923d --- /dev/null +++ b/app/code/Magento/Checkout/Test/Unit/Model/SidebarTest.php @@ -0,0 +1,233 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Test\Unit\Model; + +use Magento\Checkout\Model\Sidebar; + +class SidebarTest extends \PHPUnit_Framework_TestCase +{ + /** @var Sidebar */ + protected $sidebar; + + /** @var \Magento\Checkout\Model\Cart|\PHPUnit_Framework_MockObject_MockObject */ + protected $cartMock; + + /** @var \Magento\Checkout\Helper\Data|\PHPUnit_Framework_MockObject_MockObject */ + protected $checkoutHelperMock; + + /** @var \Magento\Framework\Locale\ResolverInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $resolverMock; + + protected function setUp() + { + $this->cartMock = $this->getMock('Magento\Checkout\Model\Cart', [], [], '', false); + $this->checkoutHelperMock = $this->getMock('Magento\Checkout\Helper\Data', [], [], '', false); + $this->resolverMock = $this->getMock('Magento\Framework\Locale\ResolverInterface'); + + $this->sidebar = new Sidebar( + $this->cartMock, + $this->checkoutHelperMock, + $this->resolverMock + ); + } + + /** + * @param string $error + * @param float $summaryQty + * @param array $totals + * @param array $result + * + * @dataProvider dataProviderGetResponseData + */ + public function testGetResponseData($error, $summaryQty, $totals, $result) + { + $quoteMock = $this->getMockBuilder('Magento\Quote\Model\Quote') + ->disableOriginalConstructor() + ->getMock(); + $quoteMock->expects($this->any()) + ->method('getTotals') + ->willReturn($totals); + + $this->cartMock->expects($this->any()) + ->method('getSummaryQty') + ->willReturn($summaryQty); + $this->cartMock->expects($this->any()) + ->method('getQuote') + ->willReturn($quoteMock); + + $this->checkoutHelperMock->expects($this->any()) + ->method('formatPrice') + ->willReturnArgument(0); + + $this->assertEquals($result, $this->sidebar->getResponseData($error)); + } + + public function dataProviderGetResponseData() + { + $totalMock = $this->getMockBuilder('Magento\Quote\Model\Quote\Address\Total') + ->disableOriginalConstructor() + ->setMethods(['getValue']) + ->getMock(); + $totalMock->expects($this->any()) + ->method('getValue') + ->willReturn(12.34); + + return [ + [ + '', + 0, + [], + [ + 'success' => true, + 'data' => [ + 'summary_qty' => 0, + 'summary_text' => __(' items'), + 'subtotal' => 0, + ], + 'cleanup' => true, + ], + ], + [ + '', + 1, + [ + 'subtotal' => $this->getMock('NonexistentClass'), + ], + [ + 'success' => true, + 'data' => [ + 'summary_qty' => 1, + 'summary_text' => __(' item'), + 'subtotal' => 0, + ], + ], + ], + [ + '', + 2, + [ + 'subtotal' => $totalMock, + ], + [ + 'success' => true, + 'data' => [ + 'summary_qty' => 2, + 'summary_text' => __(' items'), + 'subtotal' => 12.34, + ], + ], + ], + [ + 'Error', + 0, + [], + [ + 'success' => false, + 'error_message' => 'Error', + ], + ], + ]; + } + + public function testCheckQuoteItem() + { + $itemId = 1; + + $itemMock = $this->getMockBuilder('Magento\Quote\Api\Data\CartItemInterface') + ->getMock(); + + $quoteMock = $this->getMockBuilder('Magento\Quote\Model\Quote') + ->disableOriginalConstructor() + ->getMock(); + $quoteMock->expects($this->once()) + ->method('getItemById') + ->with($itemId) + ->willReturn($itemMock); + + $this->cartMock->expects($this->any()) + ->method('getQuote') + ->willReturn($quoteMock); + + $this->assertEquals($this->sidebar, $this->sidebar->checkQuoteItem($itemId)); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @exceptedExceptionMessage We can't find the quote item. + */ + public function testCheckQuoteItemWithException() + { + $itemId = 2; + + $quoteMock = $this->getMockBuilder('Magento\Quote\Model\Quote') + ->disableOriginalConstructor() + ->getMock(); + $quoteMock->expects($this->once()) + ->method('getItemById') + ->with($itemId) + ->willReturn(null); + + $this->cartMock->expects($this->any()) + ->method('getQuote') + ->willReturn($quoteMock); + + $this->sidebar->checkQuoteItem($itemId); + } + + public function testRemoveQuoteItem() + { + $itemId = 1; + + $this->cartMock->expects($this->once()) + ->method('removeItem') + ->with($itemId) + ->willReturnSelf(); + $this->cartMock->expects($this->once()) + ->method('save') + ->willReturnSelf(); + + $this->assertEquals($this->sidebar, $this->sidebar->removeQuoteItem($itemId)); + } + + public function testUpdateQuoteItem() + { + $itemId = 1; + $itemQty = 2; + + $this->resolverMock->expects($this->once()) + ->method('getLocale') + ->willReturn('en'); + + $this->cartMock->expects($this->once()) + ->method('updateItems') + ->with([$itemId => ['qty' => $itemQty]]) + ->willReturnSelf(); + $this->cartMock->expects($this->once()) + ->method('save') + ->willReturnSelf(); + + $this->assertEquals($this->sidebar, $this->sidebar->updateQuoteItem($itemId, $itemQty)); + } + + public function testUpdateQuoteItemWithZeroQty() + { + $itemId = 1; + $itemQty = 0; + + $this->resolverMock->expects($this->never()) + ->method('getLocale'); + + $this->cartMock->expects($this->once()) + ->method('updateItems') + ->with([$itemId => ['qty' => $itemQty]]) + ->willReturnSelf(); + $this->cartMock->expects($this->once()) + ->method('save') + ->willReturnSelf(); + + $this->assertEquals($this->sidebar, $this->sidebar->updateQuoteItem($itemId, $itemQty)); + } +} -- GitLab