Skip to content

Commit 62e0530

Browse files
committed
Added API-functional tests
1 parent 19b92cd commit 62e0530

File tree

4 files changed

+384
-4
lines changed

4 files changed

+384
-4
lines changed

app/code/Magento/QuoteGraphQl/Model/Resolver/UpdateCartItems.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,17 +116,17 @@ private function processCartItems(Quote $cart, array $items): void
116116
if (!isset($item['quantity'])) {
117117
throw new GraphQlInputException(__('Required parameter "quantity" for "cart_items" is missing.'));
118118
}
119-
$qty = (float)$item['quantity'];
119+
$quantity = (float)$item['quantity'];
120120

121-
if ($qty <= 0.0) {
121+
if ($quantity <= 0.0) {
122122
$this->cartItemRepository->deleteById((int)$cart->getId(), $itemId);
123123
} else {
124124
$customizableOptions = $item['customizable_options'] ?? null;
125125

126126
if ($customizableOptions === null) { // Update only item's qty
127-
$this->updateItemQty($itemId, $cart, $qty);
127+
$this->updateItemQty($itemId, $cart, $quantity);
128128
} else { // Update customizable options (and QTY if changed)
129-
$this->updateCartItem->execute($cart, $itemId, $qty, $customizableOptions);
129+
$this->updateCartItem->execute($cart, $itemId, $quantity, $customizableOptions);
130130
$this->quoteRepository->save($cart);
131131
}
132132
}
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\GraphQl\Quote;
9+
10+
use Magento\Catalog\Api\ProductCustomOptionRepositoryInterface;
11+
use Magento\Catalog\Api\ProductRepositoryInterface;
12+
use Magento\Framework\Exception\NoSuchEntityException as NoSuchEntityException;
13+
use Magento\Quote\Model\Quote\Item;
14+
use Magento\Quote\Model\QuoteFactory;
15+
use Magento\Quote\Model\ResourceModel\Quote as QuoteResource;
16+
use Magento\TestFramework\Helper\Bootstrap;
17+
use Magento\TestFramework\TestCase\GraphQlAbstract;
18+
19+
/**
20+
* Edit cart customizable options test
21+
*/
22+
class EditQuoteItemCustomOptionsTest extends GraphQlAbstract
23+
{
24+
/**
25+
* @var ProductRepositoryInterface
26+
*/
27+
private $productRepository;
28+
29+
/**
30+
* @var GetMaskedQuoteIdByReservedOrderId
31+
*/
32+
private $getMaskedQuoteIdByReservedOrderId;
33+
34+
/**
35+
* @var ProductCustomOptionRepositoryInterface
36+
*/
37+
private $productCustomOptionsRepository;
38+
39+
/**
40+
* @var QuoteFactory
41+
*/
42+
private $quoteFactory;
43+
44+
/**
45+
* @var QuoteResource
46+
*/
47+
private $quoteResource;
48+
49+
/**
50+
* @inheritdoc
51+
*/
52+
protected function setUp()
53+
{
54+
$objectManager = Bootstrap::getObjectManager();
55+
$this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
56+
$this->productCustomOptionsRepository = $objectManager->get(ProductCustomOptionRepositoryInterface::class);
57+
$this->quoteFactory = $objectManager->get(QuoteFactory::class);
58+
$this->quoteResource = $objectManager->get(QuoteResource::class);
59+
$this->productRepository = $objectManager->get(ProductRepositoryInterface::class);
60+
}
61+
62+
/**
63+
* @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
64+
* @magentoApiDataFixture Magento/GraphQl/Catalog/_files/set_custom_options_simple_product.php
65+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
66+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product_with_options.php
67+
*/
68+
public function testChangeQuoteItemCustomOptions()
69+
{
70+
$sku = 'simple_product';
71+
$quoteItemId = $this->getQuoteItemIdBySku($sku);
72+
$customOptionsValues = $this->getCustomOptionsValuesForQuery($sku);
73+
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
74+
$customizableOptionsQuery = preg_replace('/"([^"]+)"\s*:\s*/', '$1:', json_encode($customOptionsValues));
75+
76+
$query = $this->getQuery($maskedQuoteId, $quoteItemId, $customizableOptionsQuery);
77+
$response = $this->graphQlMutation($query);
78+
$itemOptionsResponse = $response['updateCartItems']['cart']['items'][0]['customizable_options'];
79+
self::assertCount(2, $itemOptionsResponse);
80+
self::assertEquals('test', $itemOptionsResponse[0]['values'][0]['value']);
81+
self::assertEquals('test', $itemOptionsResponse[1]['values'][0]['value']);
82+
}
83+
84+
/**
85+
* @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
86+
* @magentoApiDataFixture Magento/GraphQl/Catalog/_files/set_custom_options_simple_product.php
87+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
88+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product_with_options.php
89+
*/
90+
public function testOptionsSetPersistsOnQtyChange()
91+
{
92+
$sku = 'simple_product';
93+
$newQuantity = 2;
94+
$quoteItemId = $this->getQuoteItemIdBySku($sku);
95+
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
96+
97+
$query = <<<QUERY
98+
mutation {
99+
updateCartItems(input: {
100+
cart_id:"$maskedQuoteId"
101+
cart_items: [
102+
{
103+
cart_item_id: $quoteItemId
104+
quantity: $newQuantity
105+
}
106+
]
107+
}) {
108+
cart {
109+
items {
110+
quantity
111+
... on SimpleCartItem {
112+
customizable_options {
113+
label
114+
values {
115+
value
116+
}
117+
}
118+
}
119+
}
120+
}
121+
}
122+
}
123+
QUERY;
124+
$response = $this->graphQlMutation($query);
125+
$cartItemResponse = $response['updateCartItems']['cart']['items'][0];
126+
127+
self::assertEquals($newQuantity, $cartItemResponse['quantity']);
128+
self::assertCount(2, $cartItemResponse['customizable_options']);
129+
self::assertEquals('initial value', $cartItemResponse['customizable_options'][0]['values'][0]['value']);
130+
self::assertEquals('initial value', $cartItemResponse['customizable_options'][1]['values'][0]['value']);
131+
}
132+
133+
/**
134+
* @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
135+
* @magentoApiDataFixture Magento/GraphQl/Catalog/_files/set_custom_options_simple_product.php
136+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
137+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product_with_options.php
138+
*/
139+
public function testOptionsSetChangedOnChangeOneOption()
140+
{
141+
$sku = 'simple_product';
142+
$quoteItemId = $this->getQuoteItemIdBySku($sku);
143+
144+
/* Get only the first option */
145+
$customOptionsValues = array_slice($this->getCustomOptionsValuesForQuery($sku), 0, 1);
146+
147+
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
148+
$customizableOptionsQuery = preg_replace('/"([^"]+)"\s*:\s*/', '$1:', json_encode($customOptionsValues));
149+
$query = $this->getQuery($maskedQuoteId, $quoteItemId, $customizableOptionsQuery);
150+
151+
$response = $this->graphQlMutation($query);
152+
$itemOptionsResponse = $response['updateCartItems']['cart']['items'][0]['customizable_options'];
153+
self::assertCount(1, $itemOptionsResponse);
154+
self::assertEquals('test', $itemOptionsResponse[0]['values'][0]['value']);
155+
}
156+
157+
/**
158+
* @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
159+
* @magentoApiDataFixture Magento/GraphQl/Catalog/_files/set_custom_options_simple_product.php
160+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
161+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product_with_options.php
162+
* @group recent
163+
*/
164+
public function testOptionSetPersistsOnExtraOptionWithIncorrectId()
165+
{
166+
$sku = 'simple_product';
167+
$quoteItemId = $this->getQuoteItemIdBySku($sku);
168+
$customOptionsValues = $this->getCustomOptionsValuesForQuery($sku);
169+
170+
/* Add nonexistent option to the query */
171+
$customOptionsValues[] = ['id' => -10, 'value' => 'value'];
172+
173+
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
174+
$customizableOptionsQuery = preg_replace('/"([^"]+)"\s*:\s*/', '$1:', json_encode($customOptionsValues));
175+
$query = $this->getQuery($maskedQuoteId, $quoteItemId, $customizableOptionsQuery);
176+
177+
$response = $this->graphQlMutation($query);
178+
$itemOptionsResponse = $response['updateCartItems']['cart']['items'][0]['customizable_options'];
179+
self::assertCount(2, $itemOptionsResponse);
180+
}
181+
182+
/**
183+
* Returns GraphQl query for updating items in shopping cart
184+
*
185+
* @param string $maskedQuoteId
186+
* @param int $quoteItemId
187+
* @param $customizableOptionsQuery
188+
* @return string
189+
*/
190+
private function getQuery(string $maskedQuoteId, int $quoteItemId, $customizableOptionsQuery): string
191+
{
192+
return <<<QUERY
193+
mutation {
194+
updateCartItems(input: {
195+
cart_id:"$maskedQuoteId"
196+
cart_items: [
197+
{
198+
cart_item_id: $quoteItemId
199+
quantity: 1
200+
customizable_options: $customizableOptionsQuery
201+
}
202+
]
203+
}) {
204+
cart {
205+
items {
206+
quantity
207+
product {
208+
name
209+
}
210+
... on SimpleCartItem {
211+
customizable_options {
212+
label
213+
values {
214+
label
215+
value
216+
}
217+
}
218+
}
219+
}
220+
}
221+
}
222+
}
223+
QUERY;
224+
}
225+
226+
/**
227+
* Returns quote item id by product's SKU
228+
*
229+
* @param string $sku
230+
* @return int
231+
* @throws NoSuchEntityException
232+
*/
233+
private function getQuoteItemIdBySku(string $sku): int
234+
{
235+
$quote = $this->quoteFactory->create();
236+
$product = $this->productRepository->get($sku);
237+
$this->quoteResource->load($quote, 'test_quote', 'reserved_order_id');
238+
/** @var Item $quoteItem */
239+
$quoteItem = $quote->getItemByProduct($product);
240+
241+
return (int)$quoteItem->getId();
242+
}
243+
244+
245+
/**
246+
* Generate an array with test values for customizable options
247+
* based on the option type
248+
*
249+
* @param string $sku
250+
* @return array
251+
*/
252+
private function getCustomOptionsValuesForQuery(string $sku): array
253+
{
254+
$customOptions = $this->productCustomOptionsRepository->getList($sku);
255+
$customOptionsValues = [];
256+
257+
foreach ($customOptions as $customOption) {
258+
$optionType = $customOption->getType();
259+
if ($optionType == 'field' || $optionType == 'area') {
260+
$customOptionsValues[] = [
261+
'id' => (int) $customOption->getOptionId(),
262+
'value' => 'test'
263+
];
264+
} elseif ($optionType == 'drop_down') {
265+
$optionSelectValues = $customOption->getValues();
266+
$customOptionsValues[] = [
267+
'id' => (int) $customOption->getOptionId(),
268+
'value' => reset($optionSelectValues)->getOptionTypeId()
269+
];
270+
}
271+
}
272+
273+
return $customOptionsValues;
274+
}
275+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Catalog\Api\Data\ProductCustomOptionInterface;
9+
use Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory;
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\TestFramework\Helper\Bootstrap;
12+
13+
$objectManager = Bootstrap::getObjectManager();
14+
15+
$productCustomOptions = [];
16+
$optionsSet = [
17+
[
18+
'title' => 'test_option_code_1',
19+
'type' => 'field',
20+
'is_require' => false,
21+
'sort_order' => 1,
22+
'price' => -10.0,
23+
'price_type' => 'fixed',
24+
'sku' => 'sku1',
25+
'max_characters' => 100,
26+
],
27+
[
28+
'title' => 'area option',
29+
'type' => 'area',
30+
'is_require' => false,
31+
'sort_order' => 2,
32+
'price' => 20.0,
33+
'price_type' => 'percent',
34+
'sku' => 'sku2',
35+
'max_characters' => 100
36+
]
37+
];
38+
39+
/** @var ProductRepositoryInterface $productRepository */
40+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
41+
$product = $productRepository->get('simple_product');
42+
/** @var ProductCustomOptionInterfaceFactory $customOptionFactory */
43+
$customOptionFactory = $objectManager->get(ProductCustomOptionInterfaceFactory::class);
44+
45+
foreach ($optionsSet as $option) {
46+
/** @var ProductCustomOptionInterface $customOption */
47+
$customOption = $customOptionFactory->create(['data' => $option]);
48+
$customOption->setProductSku($product->getSku());
49+
50+
$productCustomOptions[] = $customOption;
51+
}
52+
53+
$product->setOptions($productCustomOptions);
54+
$productRepository->save($product);

0 commit comments

Comments
 (0)