CartTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Checkout\Test\Unit\Model;
  7. use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
  8. /**
  9. * Class CartTest
  10. *
  11. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  12. */
  13. class CartTest extends \PHPUnit\Framework\TestCase
  14. {
  15. /** @var \Magento\Checkout\Model\Cart */
  16. protected $cart;
  17. /** @var ObjectManagerHelper */
  18. protected $objectManagerHelper;
  19. /** @var \Magento\Checkout\Model\Session|\PHPUnit_Framework_MockObject_MockObject */
  20. protected $checkoutSessionMock;
  21. /**
  22. * @var \PHPUnit_Framework_MockObject_MockObject
  23. */
  24. protected $customerSessionMock;
  25. /** @var \Magento\CatalogInventory\Api\Data\StockItemInterface|\PHPUnit_Framework_MockObject_MockObject */
  26. protected $stockItemMock;
  27. /**
  28. * @var \PHPUnit_Framework_MockObject_MockObject
  29. */
  30. protected $scopeConfigMock;
  31. /**
  32. * @var \Magento\Quote\Model\Quote|\PHPUnit_Framework_MockObject_MockObject
  33. */
  34. protected $quoteMock;
  35. /**
  36. * @var \PHPUnit_Framework_MockObject_MockObject
  37. */
  38. protected $eventManagerMock;
  39. /**
  40. * @var \PHPUnit_Framework_MockObject_MockObject
  41. */
  42. protected $stockRegistry;
  43. /**
  44. * @var \PHPUnit_Framework_MockObject_MockObject
  45. */
  46. protected $stockState;
  47. /**
  48. * @var \PHPUnit_Framework_MockObject_MockObject
  49. */
  50. private $storeManagerMock;
  51. /**
  52. * @var \PHPUnit_Framework_MockObject_MockObject
  53. */
  54. private $storeMock;
  55. /**
  56. * @var \PHPUnit_Framework_MockObject_MockObject
  57. */
  58. private $productRepository;
  59. /**
  60. * @var \PHPUnit_Framework_MockObject_MockObject
  61. */
  62. private $requestInfoFilterMock;
  63. protected function setUp()
  64. {
  65. $this->checkoutSessionMock = $this->createMock(\Magento\Checkout\Model\Session::class);
  66. $this->customerSessionMock = $this->createMock(\Magento\Customer\Model\Session::class);
  67. $this->scopeConfigMock = $this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
  68. $this->quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class);
  69. $this->eventManagerMock = $this->createMock(\Magento\Framework\Event\ManagerInterface::class);
  70. $this->storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class);
  71. $this->productRepository = $this->createMock(\Magento\Catalog\Api\ProductRepositoryInterface::class);
  72. $this->stockRegistry = $this->getMockBuilder(\Magento\CatalogInventory\Model\StockRegistry::class)
  73. ->disableOriginalConstructor()
  74. ->setMethods(['getStockItem', '__wakeup'])
  75. ->getMock();
  76. $this->stockItemMock = $this->createPartialMock(
  77. \Magento\CatalogInventory\Model\Stock\Item::class,
  78. ['getMinSaleQty', '__wakeup']
  79. );
  80. $this->stockState = $this->createPartialMock(
  81. \Magento\CatalogInventory\Model\StockState::class,
  82. ['suggestQty', '__wakeup']
  83. );
  84. $this->storeMock =
  85. $this->createPartialMock(\Magento\Store\Model\Store::class, ['getWebsiteId', 'getId', '__wakeup']);
  86. $this->requestInfoFilterMock = $this->createMock(
  87. \Magento\Checkout\Model\Cart\RequestInfoFilterInterface::class
  88. );
  89. $this->stockRegistry->expects($this->any())
  90. ->method('getStockItem')
  91. ->will($this->returnValue($this->stockItemMock));
  92. $this->storeMock->expects($this->any())
  93. ->method('getWebsiteId')
  94. ->will($this->returnValue(10));
  95. $this->storeMock->expects($this->any())
  96. ->method('getId')
  97. ->will($this->returnValue(10));
  98. $this->storeManagerMock->expects($this->any())
  99. ->method('getStore')
  100. ->will($this->returnValue($this->storeMock));
  101. $this->objectManagerHelper = new ObjectManagerHelper($this);
  102. $this->cart = $this->objectManagerHelper->getObject(
  103. \Magento\Checkout\Model\Cart::class,
  104. [
  105. 'scopeConfig' => $this->scopeConfigMock,
  106. 'checkoutSession' => $this->checkoutSessionMock,
  107. 'stockRegistry' => $this->stockRegistry,
  108. 'stockState' => $this->stockState,
  109. 'customerSession' => $this->customerSessionMock,
  110. 'eventManager' => $this->eventManagerMock,
  111. 'storeManager' => $this->storeManagerMock,
  112. 'productRepository' => $this->productRepository
  113. ]
  114. );
  115. $this->objectManagerHelper
  116. ->setBackwardCompatibleProperty($this->cart, 'requestInfoFilter', $this->requestInfoFilterMock);
  117. }
  118. public function testSuggestItemsQty()
  119. {
  120. $data = [[] , ['qty' => -2], ['qty' => 3], ['qty' => 3.5], ['qty' => 5], ['qty' => 4]];
  121. $this->quoteMock->expects($this->any())
  122. ->method('getItemById')
  123. ->will($this->returnValueMap([
  124. [2, $this->prepareQuoteItemMock(2)],
  125. [3, $this->prepareQuoteItemMock(3)],
  126. [4, $this->prepareQuoteItemMock(4)],
  127. [5, $this->prepareQuoteItemMock(5)],
  128. ]));
  129. $this->stockState->expects($this->at(0))
  130. ->method('suggestQty')
  131. ->will($this->returnValue(3.0));
  132. $this->stockState->expects($this->at(1))
  133. ->method('suggestQty')
  134. ->will($this->returnValue(3.5));
  135. $this->checkoutSessionMock->expects($this->any())
  136. ->method('getQuote')
  137. ->will($this->returnValue($this->quoteMock));
  138. $this->assertSame(
  139. [
  140. [],
  141. ['qty' => -2],
  142. ['qty' => 3., 'before_suggest_qty' => 3.],
  143. ['qty' => 3.5, 'before_suggest_qty' => 3.5],
  144. ['qty' => 5],
  145. ['qty' => 4],
  146. ],
  147. $this->cart->suggestItemsQty($data)
  148. );
  149. }
  150. public function testUpdateItems()
  151. {
  152. $data = [['qty' => 5.5, 'before_suggest_qty' => 5.5]];
  153. $infoDataObject = $this->objectManagerHelper->getObject(
  154. \Magento\Framework\DataObject::class,
  155. ['data' => $data]
  156. );
  157. $this->checkoutSessionMock->expects($this->once())
  158. ->method('getQuote')
  159. ->will($this->returnValue($this->quoteMock));
  160. $this->eventManagerMock->expects($this->at(0))->method('dispatch')->with(
  161. 'checkout_cart_update_items_before',
  162. ['cart' => $this->cart, 'info' => $infoDataObject]
  163. );
  164. $this->eventManagerMock->expects($this->at(1))->method('dispatch')->with(
  165. 'checkout_cart_update_items_after',
  166. ['cart' => $this->cart, 'info' => $infoDataObject]
  167. );
  168. $result = $this->cart->updateItems($data);
  169. $this->assertSame($this->cart, $result);
  170. }
  171. /**
  172. * @param int|bool $itemId
  173. * @return \PHPUnit_Framework_MockObject_MockObject
  174. */
  175. public function prepareQuoteItemMock($itemId)
  176. {
  177. $store = $this->createPartialMock(\Magento\Store\Model\Store::class, ['getId', '__wakeup', 'getWebsiteId']);
  178. $store->expects($this->any())
  179. ->method('getWebsiteId')
  180. ->will($this->returnValue(10));
  181. $store->expects($this->any())
  182. ->method('getId')
  183. ->will($this->returnValue(10));
  184. $this->storeManagerMock->expects($this->any())
  185. ->method('getStore')
  186. ->will($this->returnValue($store));
  187. switch ($itemId) {
  188. case 2:
  189. $product = $this->createPartialMock(
  190. \Magento\Catalog\Model\Product::class,
  191. ['getStore', 'getId', '__wakeup']
  192. );
  193. $product->expects($this->once())
  194. ->method('getId')
  195. ->will($this->returnValue(4));
  196. $product->expects($this->once())
  197. ->method('getStore')
  198. ->will($this->returnValue($store));
  199. break;
  200. case 3:
  201. $product = $this->createPartialMock(
  202. \Magento\Catalog\Model\Product::class,
  203. ['getStore', 'getId', '__wakeup']
  204. );
  205. $product->expects($this->once())
  206. ->method('getId')
  207. ->will($this->returnValue(5));
  208. $product->expects($this->once())
  209. ->method('getStore')
  210. ->will($this->returnValue($store));
  211. break;
  212. case 4:
  213. $product = false;
  214. break;
  215. default:
  216. return false;
  217. }
  218. $quoteItem = $this->createMock(\Magento\Quote\Model\Quote\Item::class);
  219. $quoteItem->expects($this->once())
  220. ->method('getProduct')
  221. ->will($this->returnValue($product));
  222. return $quoteItem;
  223. }
  224. /**
  225. * @param boolean $useQty
  226. * @dataProvider useQtyDataProvider
  227. */
  228. public function testGetSummaryQty($useQty)
  229. {
  230. $quoteId = 1;
  231. $itemsCount = 1;
  232. $quoteMock = $this->createPartialMock(
  233. \Magento\Quote\Model\Quote::class,
  234. ['getItemsCount', 'getItemsQty', '__wakeup']
  235. );
  236. $this->checkoutSessionMock->expects($this->any())->method('getQuote')->will($this->returnValue($quoteMock));
  237. $this->checkoutSessionMock->expects($this->at(2))->method('getQuoteId')->will($this->returnValue($quoteId));
  238. $this->customerSessionMock->expects($this->any())->method('isLoggedIn')->will($this->returnValue(true));
  239. $this->scopeConfigMock->expects($this->once())->method('getValue')
  240. ->with('checkout/cart_link/use_qty', \Magento\Store\Model\ScopeInterface::SCOPE_STORE)
  241. ->will($this->returnValue($useQty));
  242. $qtyMethodName = ($useQty) ? 'getItemsQty' : 'getItemsCount';
  243. $quoteMock->expects($this->once())->method($qtyMethodName)->will($this->returnValue($itemsCount));
  244. $this->assertEquals($itemsCount, $this->cart->getSummaryQty());
  245. }
  246. /**
  247. * @return array
  248. */
  249. public function useQtyDataProvider()
  250. {
  251. return [
  252. ['useQty' => true],
  253. ['useQty' => false]
  254. ];
  255. }
  256. /**
  257. * Test successful scenarios for AddProduct
  258. *
  259. * @param int|\Magento\Catalog\Model\Product $productInfo
  260. * @param \Magento\Framework\DataObject|int|array $requestInfo
  261. * @dataProvider addProductDataProvider
  262. */
  263. public function testAddProduct($productInfo, $requestInfo)
  264. {
  265. $product = $this->createPartialMock(
  266. \Magento\Catalog\Model\Product::class,
  267. ['getStore', 'getWebsiteIds', 'getProductUrl', 'getId', '__wakeup']
  268. );
  269. $product->expects($this->any())
  270. ->method('getId')
  271. ->will($this->returnValue(4));
  272. $product->expects($this->once())
  273. ->method('getStore')
  274. ->will($this->returnValue($this->storeMock));
  275. $product->expects($this->any())
  276. ->method('getWebsiteIds')
  277. ->will($this->returnValue([10]));
  278. $product->expects($this->any())
  279. ->method('getProductUrl')
  280. ->will($this->returnValue('url'));
  281. $this->productRepository->expects($this->any())
  282. ->method('getById')
  283. ->will($this->returnValue($product));
  284. $this->eventManagerMock->expects($this->at(0))->method('dispatch')->with(
  285. 'checkout_cart_product_add_before',
  286. ['info' => $requestInfo, 'product' => $product]
  287. );
  288. $this->quoteMock->expects($this->once())
  289. ->method('addProduct')
  290. ->will($this->returnValue(1));
  291. $this->checkoutSessionMock->expects($this->once())
  292. ->method('getQuote')
  293. ->will($this->returnValue($this->quoteMock));
  294. $this->eventManagerMock->expects($this->at(1))->method('dispatch')->with(
  295. 'checkout_cart_product_add_after',
  296. ['quote_item' => 1, 'product' => $product]
  297. );
  298. if (!$productInfo) {
  299. $productInfo = $product;
  300. }
  301. $result = $this->cart->addProduct($productInfo, $requestInfo);
  302. $this->assertSame($this->cart, $result);
  303. }
  304. /**
  305. * Test exception on adding product for AddProduct
  306. *
  307. * @throws \Magento\Framework\Exception\LocalizedException
  308. */
  309. public function testAddProductException()
  310. {
  311. $product = $this->createPartialMock(
  312. \Magento\Catalog\Model\Product::class,
  313. ['getStore', 'getWebsiteIds', 'getProductUrl', 'getId', '__wakeup']
  314. );
  315. $product->expects($this->any())
  316. ->method('getId')
  317. ->will($this->returnValue(4));
  318. $product->expects($this->once())
  319. ->method('getStore')
  320. ->will($this->returnValue($this->storeMock));
  321. $product->expects($this->any())
  322. ->method('getWebsiteIds')
  323. ->will($this->returnValue([10]));
  324. $product->expects($this->any())
  325. ->method('getProductUrl')
  326. ->will($this->returnValue('url'));
  327. $this->productRepository->expects($this->any())
  328. ->method('getById')
  329. ->will($this->returnValue($product));
  330. $this->eventManagerMock->expects($this->once())->method('dispatch')->with(
  331. 'checkout_cart_product_add_before',
  332. ['info' => 4, 'product' => $product]
  333. );
  334. $this->quoteMock->expects($this->once())
  335. ->method('addProduct')
  336. ->will($this->returnValue('error'));
  337. $this->checkoutSessionMock->expects($this->once())
  338. ->method('getQuote')
  339. ->will($this->returnValue($this->quoteMock));
  340. $this->expectException(\Magento\Framework\Exception\LocalizedException::class);
  341. $this->cart->addProduct(4, 4);
  342. }
  343. /**
  344. * Test bad parameters on adding product for AddProduct
  345. *
  346. * @throws \Magento\Framework\Exception\LocalizedException
  347. */
  348. public function testAddProductExceptionBadParams()
  349. {
  350. $product = $this->createPartialMock(
  351. \Magento\Catalog\Model\Product::class,
  352. ['getWebsiteIds', 'getId', '__wakeup']
  353. );
  354. $product->expects($this->any())
  355. ->method('getId')
  356. ->will($this->returnValue(4));
  357. $product->expects($this->any())
  358. ->method('getWebsiteIds')
  359. ->will($this->returnValue([10]));
  360. $this->productRepository->expects($this->any())
  361. ->method('getById')
  362. ->will($this->returnValue($product));
  363. $this->eventManagerMock->expects($this->never())->method('dispatch')->with(
  364. 'checkout_cart_product_add_before',
  365. ['info' => 'bad', 'product' => $product]
  366. );
  367. $this->eventManagerMock->expects($this->never())->method('dispatch')->with(
  368. 'checkout_cart_product_add_after',
  369. ['quote_item' => 1, 'product' => $product]
  370. );
  371. $this->expectException(\Magento\Framework\Exception\LocalizedException::class);
  372. $this->cart->addProduct(4, 'bad');
  373. }
  374. /**
  375. * Data provider for testAddProduct
  376. *
  377. * @return array
  378. */
  379. public function addProductDataProvider()
  380. {
  381. $obj = new ObjectManagerHelper($this);
  382. $data = ['qty' => 5.5, 'sku' => 'prod'];
  383. return [
  384. 'prod_int_info_int' => [4, 4],
  385. 'prod_int_info_array' => [ 4, $data],
  386. 'prod_int_info_object' => [
  387. 4,
  388. $obj->getObject(
  389. \Magento\Framework\DataObject::class,
  390. ['data' => $data]
  391. )
  392. ],
  393. 'prod_obj_info_int' => [null, 4],
  394. 'prod_obj_info_array' => [ null, $data],
  395. 'prod_obj_info_object' => [
  396. null,
  397. $obj->getObject(
  398. \Magento\Framework\DataObject::class,
  399. ['data' => $data]
  400. )
  401. ]
  402. ];
  403. }
  404. }