77
88namespace Magento \GraphQl \CatalogInventory ;
99
10+ use Magento \Catalog \Test \Fixture \Product as ProductFixture ;
1011use Magento \Config \Model \ResourceModel \Config ;
12+ use Magento \ConfigurableProduct \Test \Fixture \Attribute as AttributeFixture ;
13+ use Magento \ConfigurableProduct \Test \Fixture \Product as ConfigurableProductFixture ;
14+ use Magento \Eav \Api \Data \AttributeInterface ;
15+ use Magento \Eav \Api \Data \AttributeOptionInterface ;
1116use Magento \Framework \App \Config \ReinitableConfigInterface ;
1217use Magento \Catalog \Api \ProductRepositoryInterface ;
13- use Magento \Framework \App \Config \ScopeConfigInterface ;
18+ use Magento \Framework \DataObject ;
19+ use Magento \Quote \Test \Fixture \GuestCart as GuestCartFixture ;
20+ use Magento \Quote \Test \Fixture \QuoteIdMask as QuoteMaskFixture ;
21+ use Magento \TestFramework \App \ApiMutableScopeConfig ;
22+ use Magento \TestFramework \Fixture \DataFixture ;
23+ use Magento \TestFramework \Fixture \DataFixtureStorage ;
24+ use Magento \TestFramework \Fixture \DataFixtureStorageManager ;
1425use Magento \TestFramework \ObjectManager ;
1526use Magento \TestFramework \TestCase \GraphQlAbstract ;
1627use Magento \CatalogInventory \Model \Configuration ;
2031 */
2132class ProductOnlyXLeftInStockTest extends GraphQlAbstract
2233{
34+ private const PARENT_SKU_CONFIGURABLE = 'parent_configurable ' ;
35+
36+ private const SKU = 'simple_10 ' ;
37+
2338 /**
2439 * @var ProductRepositoryInterface
2540 */
@@ -30,7 +45,7 @@ class ProductOnlyXLeftInStockTest extends GraphQlAbstract
3045 private $ resourceConfig ;
3146
3247 /**
33- * @var ScopeConfigInterface
48+ * @var ApiMutableScopeConfig
3449 */
3550 private $ scopeConfig ;
3651
@@ -39,6 +54,11 @@ class ProductOnlyXLeftInStockTest extends GraphQlAbstract
3954 */
4055 private $ reinitConfig ;
4156
57+ /**
58+ * @var DataFixtureStorage
59+ */
60+ private $ fixtures ;
61+
4262 /**
4363 * @inheritdoc
4464 */
@@ -49,8 +69,9 @@ protected function setUp(): void
4969 $ objectManager = ObjectManager::getInstance ();
5070 $ this ->productRepository = $ objectManager ->create (ProductRepositoryInterface::class);
5171 $ this ->resourceConfig = $ objectManager ->get (Config::class);
52- $ this ->scopeConfig = $ objectManager ->get (ScopeConfigInterface ::class);
72+ $ this ->scopeConfig = $ objectManager ->get (ApiMutableScopeConfig ::class);
5373 $ this ->reinitConfig = $ objectManager ->get (ReinitableConfigInterface::class);
74+ $ this ->fixtures = DataFixtureStorageManager::getStorage ();
5475 }
5576
5677 /**
@@ -91,7 +112,7 @@ public function testQueryProductOnlyXLeftInStockEnabled()
91112 products(filter: {sku: {eq: " {$ productSku }"}})
92113 {
93114 items {
94- only_x_left_in_stock
115+ only_x_left_in_stock
95116 }
96117 }
97118 }
@@ -118,13 +139,13 @@ public function testQueryProductOnlyXLeftInStockOutstock()
118139 // need to resave product to reindex it with new configuration.
119140 $ product = $ this ->productRepository ->get ($ productSku );
120141 $ this ->productRepository ->save ($ product );
121-
142+
122143 $ query = <<<QUERY
123144 {
124145 products(filter: {sku: {eq: " {$ productSku }"}})
125146 {
126147 items {
127- only_x_left_in_stock
148+ only_x_left_in_stock
128149 }
129150 }
130151 }
@@ -138,4 +159,111 @@ public function testQueryProductOnlyXLeftInStockOutstock()
138159 $ this ->assertArrayHasKey ('only_x_left_in_stock ' , $ response ['products ' ]['items ' ][0 ]);
139160 $ this ->assertEquals (0 , $ response ['products ' ]['items ' ][0 ]['only_x_left_in_stock ' ]);
140161 }
162+
163+ #[
164+ DataFixture(ProductFixture::class, ['sku ' => self ::SKU ], as: 'product ' ),
165+ DataFixture(AttributeFixture::class, as: 'attribute ' ),
166+ DataFixture(
167+ ConfigurableProductFixture::class,
168+ [
169+ 'sku ' => self ::PARENT_SKU_CONFIGURABLE ,
170+ '_options ' => ['$attribute$ ' ],
171+ '_links ' => ['$product$ ' ],
172+ ],
173+ 'configurable_product '
174+ ),
175+ DataFixture(GuestCartFixture::class, as: 'cart ' ),
176+ DataFixture(QuoteMaskFixture::class, ['cart_id ' => '$cart.id$ ' ], 'quoteIdMask ' ),
177+ ]
178+ /**
179+ * @dataProvider stockThresholdQtyProvider
180+ */
181+ public function testOnlyXLeftInStockConfigurableProduct (string $ stockThresholdQty , ?int $ expected ): void
182+ {
183+ $ this ->scopeConfig ->setValue ('cataloginventory/options/stock_threshold_qty ' , $ stockThresholdQty );
184+ $ maskedQuoteId = $ this ->fixtures ->get ('quoteIdMask ' )->getMaskedId ();
185+ /** @var AttributeInterface $attribute */
186+ $ attribute = $ this ->fixtures ->get ('attribute ' );
187+ /** @var AttributeOptionInterface $option */
188+ $ option = $ attribute ->getOptions ()[1 ];
189+ $ selectedOption = base64_encode ("configurable/ {$ attribute ->getAttributeId ()}/ {$ option ->getValue ()}" );
190+ $ query = $ this ->mutationAddConfigurableProduct (
191+ $ maskedQuoteId ,
192+ self ::PARENT_SKU_CONFIGURABLE ,
193+ $ selectedOption ,
194+ 100
195+ );
196+
197+ $ this ->graphQlMutation ($ query );
198+
199+ $ query = <<<QUERY
200+ {
201+ cart(cart_id: " $ maskedQuoteId") {
202+ total_quantity
203+ itemsV2 {
204+ items {
205+ uid
206+ product {
207+ name
208+ sku
209+ stock_status
210+ only_x_left_in_stock
211+ }
212+ }
213+ }
214+ }
215+ }
216+ QUERY ;
217+
218+ $ response = $ this ->graphQlQuery ($ query );
219+ $ responseDataObject = new DataObject ($ response );
220+ self ::assertEquals (
221+ $ expected ,
222+ $ responseDataObject ->getData ('cart/itemsV2/items/0/product/only_x_left_in_stock ' ),
223+ );
224+ }
225+
226+ public function stockThresholdQtyProvider (): array
227+ {
228+ return [
229+ ['0 ' , null ],
230+ ['200 ' , 100 ]
231+ ];
232+ }
233+
234+ private function mutationAddConfigurableProduct (
235+ string $ cartId ,
236+ string $ sku ,
237+ string $ selectedOption ,
238+ int $ qty = 1
239+ ): string {
240+ return <<<QUERY
241+ mutation {
242+ addProductsToCart(
243+ cartId: " {$ cartId }",
244+ cartItems: [
245+ {
246+ sku: " {$ sku }"
247+ quantity: $ qty
248+ selected_options: [
249+ " $ selectedOption"
250+ ]
251+ }]
252+ ) {
253+ cart {
254+ items {
255+ is_available
256+ product {
257+ sku
258+ }
259+ }
260+ }
261+ user_errors {
262+ code
263+ message
264+ }
265+ }
266+ }
267+ QUERY ;
268+ }
141269}
0 commit comments