Skip to content

Commit da8a619

Browse files
authored
Merge branch '2.4-develop' into ArrowsBugFixDelivery_23112022
2 parents 1bba64d + eac615e commit da8a619

File tree

9 files changed

+315
-10
lines changed

9 files changed

+315
-10
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
10+
<test name="OnePageCheckoutForErrorTest">
11+
<annotations>
12+
<features value="Checkout"/>
13+
<stories value="Checkout Free Shipping Recalculation after Coupon Code Added For Error Message Check"/>
14+
<title value="Checkout Free Shipping Recalculation after Coupon Code Added For Error Message Check"/>
15+
<description value="User should be able to do checkout free shipping recalculation after adding coupon code"/>
16+
<severity value="BLOCKER"/>
17+
<testCaseId value="MC-28548"/>
18+
<useCaseId value="MAGETWO-96431"/>
19+
<group value="Checkout"/>
20+
</annotations>
21+
22+
<before>
23+
<createData entity="Simple_US_Customer" stepKey="createCustomer">
24+
<field key="group_id">1</field>
25+
</createData>
26+
<createData entity="_defaultCategory" stepKey="defaultCategory"/>
27+
<createData entity="_defaultProduct" stepKey="simpleProduct">
28+
<field key="price">90</field>
29+
<requiredEntity createDataKey="defaultCategory"/>
30+
</createData>
31+
<!--It is default for FlatRate-->
32+
<createData entity="FlatRateShippingMethodConfig" stepKey="enableFlatRate"/>
33+
<createData entity="FreeShippingMethodsSettingConfig" stepKey="freeShippingMethodsSettingConfig"/>
34+
<createData entity="MinimumOrderAmount90" stepKey="minimumOrderAmount90"/>
35+
<comment userInput="Adding the comment to replace CliCacheFlushActionGroup action group ('cache:flush' command) for preserving Backward Compatibility" stepKey="flushCache"/>
36+
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
37+
<actionGroup ref="AdminCartPriceRuleDeleteAllActionGroup" stepKey="deleteAllCartPriceRules"/>
38+
<actionGroup ref="AdminCreateCartPriceRuleWithCouponCodeActionGroup" stepKey="createCartPriceRule">
39+
<argument name="ruleName" value="CatPriceRule"/>
40+
<argument name="couponCode" value="CatPriceRule.coupon_code"/>
41+
</actionGroup>
42+
<actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStoreFront">
43+
<argument name="Customer" value="$createCustomer$"/>
44+
</actionGroup>
45+
<actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductPage">
46+
<argument name="productUrl" value="$simpleProduct.custom_attributes[url_key]$"/>
47+
</actionGroup>
48+
</before>
49+
50+
<after>
51+
<deleteData createDataKey="simpleProduct" stepKey="deleteProduct"/>
52+
<deleteData createDataKey="defaultCategory" stepKey="deleteCategory"/>
53+
<createData entity="DefaultShippingMethodsConfig" stepKey="defaultShippingMethodsConfig"/>
54+
<createData entity="DefaultMinimumOrderAmount" stepKey="defaultMinimumOrderAmount"/>
55+
<deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/>
56+
<comment userInput="Adding the comment to replace CliCacheFlushActionGroup action group ('cache:flush' command) for preserving Backward Compatibility" stepKey="flushCache"/>
57+
<actionGroup ref="AdminCartPriceRuleDeleteAllActionGroup" stepKey="deleteAllCartPriceRules"/>
58+
<actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/>
59+
</after>
60+
61+
<actionGroup ref="AddProductToStorefrontActionGroup" stepKey="addToCartProduct">
62+
<argument name="product" value="$simpleProduct$"/>
63+
</actionGroup>
64+
<actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart1"/>
65+
66+
67+
<waitForPageLoad stepKey="waitForShippingMethods"/>
68+
<click selector="{{CheckoutShippingMethodsSection.shippingMethodRowByName('Free')}}" stepKey="chooseFreeShipping"/>
69+
<actionGroup ref="StorefrontCheckoutClickNextOnShippingStepActionGroup" stepKey="clickNextAfterFreeShippingMethodSelection"/>
70+
<waitForPageLoad stepKey="waitForReviewAndPayments"/>
71+
<actionGroup ref="StorefrontApplyDiscountCodeActionGroup" stepKey="applyCouponCode">
72+
<argument name="discountCode" value="{{CatPriceRule.coupon_code}}"/>
73+
</actionGroup>
74+
<!-- Assert order cannot be placed and error message will shown. -->
75+
<actionGroup ref="AssertStorefrontOrderIsNotPlacedActionGroup" stepKey="seeShippingMethodError">
76+
<argument name="error" value="The shipping method is missing. Select the shipping method and try again."/>
77+
</actionGroup>
78+
</test>
79+
</tests>

app/code/Magento/Integration/Setup/Patch/Data/UpgradeConsumerSecret.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public static function getDependencies()
120120
*/
121121
public static function getVersion()
122122
{
123-
return '2.0.0';
123+
return '2.2.2';
124124
}
125125

126126
/**

app/code/Magento/QuoteGraphQl/Model/Cart/ExtractQuoteAddressData.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Magento\QuoteGraphQl\Model\Cart;
99

1010
use Magento\Framework\Api\ExtensibleDataObjectConverter;
11+
use Magento\Framework\GraphQl\Query\Uid;
1112
use Magento\Quote\Api\Data\AddressInterface;
1213
use Magento\Quote\Model\Quote\Address as QuoteAddress;
1314

@@ -24,9 +25,20 @@ class ExtractQuoteAddressData
2425
/**
2526
* @param ExtensibleDataObjectConverter $dataObjectConverter
2627
*/
27-
public function __construct(ExtensibleDataObjectConverter $dataObjectConverter)
28-
{
28+
29+
/** @var Uid */
30+
private Uid $uidEncoder;
31+
32+
/**
33+
* @param ExtensibleDataObjectConverter $dataObjectConverter
34+
* @param Uid $uidEncoder
35+
*/
36+
public function __construct(
37+
ExtensibleDataObjectConverter $dataObjectConverter,
38+
Uid $uidEncoder
39+
) {
2940
$this->dataObjectConverter = $dataObjectConverter;
41+
$this->uidEncoder = $uidEncoder;
3042
}
3143

3244
/**
@@ -52,6 +64,7 @@ public function execute(QuoteAddress $address): array
5264
'label' => $address->getRegion(),
5365
'region_id'=> $address->getRegionId()
5466
],
67+
'uid' => $this->uidEncoder->encode((string)$address->getAddressId()) ,
5568
'street' => $address->getStreet(),
5669
'items_weight' => $address->getWeight(),
5770
'customer_notes' => $address->getCustomerNotes()

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

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@
77

88
namespace Magento\QuoteGraphQl\Model\Resolver;
99

10+
use Magento\Framework\Exception\AlreadyExistsException;
1011
use Magento\Framework\Exception\LocalizedException;
1112
use Magento\Framework\Exception\NoSuchEntityException;
1213
use Magento\Framework\GraphQl\Config\Element\Field;
1314
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
1415
use Magento\Framework\GraphQl\Query\ResolverInterface;
1516
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1617
use Magento\Quote\Model\Quote;
18+
use Magento\Quote\Model\QuoteIdMaskFactory;
1719
use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
20+
use Magento\Quote\Model\ResourceModel\Quote\QuoteIdMask as QuoteIdMaskResourceModel;
1821

1922
/**
2023
* Get cart id from the cart
@@ -24,15 +27,31 @@ class MaskedCartId implements ResolverInterface
2427
/**
2528
* @var QuoteIdToMaskedQuoteIdInterface
2629
*/
27-
private $quoteIdToMaskedQuoteId;
30+
private QuoteIdToMaskedQuoteIdInterface $quoteIdToMaskedQuoteId;
31+
32+
/**
33+
* @var QuoteIdMaskFactory
34+
*/
35+
private QuoteIdMaskFactory $quoteIdMaskFactory;
36+
37+
/**
38+
* @var QuoteIdMaskResourceModel
39+
*/
40+
private QuoteIdMaskResourceModel $quoteIdMaskResourceModel;
2841

2942
/**
3043
* @param QuoteIdToMaskedQuoteIdInterface $quoteIdToMaskedQuoteId
44+
* @param QuoteIdMaskFactory $quoteIdMaskFactory
45+
* @param QuoteIdMaskResourceModel $quoteIdMaskResourceModel
3146
*/
3247
public function __construct(
33-
QuoteIdToMaskedQuoteIdInterface $quoteIdToMaskedQuoteId
48+
QuoteIdToMaskedQuoteIdInterface $quoteIdToMaskedQuoteId,
49+
QuoteIdMaskFactory $quoteIdMaskFactory,
50+
QuoteIdMaskResourceModel $quoteIdMaskResourceModel
3451
) {
3552
$this->quoteIdToMaskedQuoteId = $quoteIdToMaskedQuoteId;
53+
$this->quoteIdMaskFactory = $quoteIdMaskFactory;
54+
$this->quoteIdMaskResourceModel = $quoteIdMaskResourceModel;
3655
}
3756

3857
/**
@@ -60,10 +79,33 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
6079
private function getQuoteMaskId(int $quoteId): string
6180
{
6281
try {
63-
$maskedId = $this->quoteIdToMaskedQuoteId->execute($quoteId);
82+
$maskedId =$this->ensureQuoteMaskExist($quoteId);
6483
} catch (NoSuchEntityException $exception) {
6584
throw new GraphQlNoSuchEntityException(__('Current user does not have an active cart.'));
6685
}
6786
return $maskedId;
6887
}
88+
89+
/**
90+
* Create masked id for quote if it's not exists
91+
*
92+
* @param int $quoteId
93+
* @return string
94+
* @throws AlreadyExistsException
95+
*/
96+
private function ensureQuoteMaskExist(int $quoteId): string
97+
{
98+
try {
99+
$maskedId = $this->quoteIdToMaskedQuoteId->execute($quoteId);
100+
} catch (NoSuchEntityException $e) {
101+
$maskedId = '';
102+
}
103+
if ($maskedId === '') {
104+
$quoteIdMask = $this->quoteIdMaskFactory->create();
105+
$quoteIdMask->setQuoteId($quoteId);
106+
$this->quoteIdMaskResourceModel->save($quoteIdMask);
107+
$maskedId = $this->quoteIdToMaskedQuoteId->execute($quoteId);
108+
}
109+
return $maskedId;
110+
}
69111
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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\QuoteGraphQl\Test\Unit\Model\Resolver;
9+
10+
use Magento\Framework\Exception\LocalizedException;
11+
use Magento\Framework\GraphQl\Config\Element\Field;
12+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
13+
use Magento\GraphQl\Model\Query\Context;
14+
use Magento\Quote\Model\Quote;
15+
use Magento\Quote\Model\QuoteIdMask;
16+
use Magento\Quote\Model\QuoteIdMaskFactory;
17+
use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
18+
use Magento\Quote\Model\ResourceModel\Quote\QuoteIdMask as QuoteIdMaskResourceModel;
19+
use Magento\QuoteGraphQl\Model\Resolver\Cart;
20+
use Magento\QuoteGraphQl\Model\Resolver\MaskedCartId;
21+
use PHPUnit\Framework\MockObject\MockObject;
22+
use PHPUnit\Framework\TestCase;
23+
24+
class MaskedCartIdTest extends TestCase
25+
{
26+
/**
27+
* @var MaskedCartId
28+
*/
29+
private MaskedCartId $maskedCartId;
30+
31+
/**
32+
* @var QuoteIdToMaskedQuoteIdInterface|MockObject
33+
*/
34+
private QuoteIdToMaskedQuoteIdInterface $quoteIdToMaskedQuoteId;
35+
36+
/**
37+
* @var \Magento\QuoteGraphQl\Test\Unit\Model\Resolver\QuoteIdMaskFactory|MockObject
38+
*/
39+
private QuoteIdMaskFactory $quoteIdMaskFactory;
40+
41+
/**
42+
* @var QuoteIdMaskResourceModel|MockObject
43+
*/
44+
private QuoteIdMaskResourceModel $quoteIdMaskResourceModelMock;
45+
46+
/**
47+
* @var Field|MockObject
48+
*/
49+
private Field $fieldMock;
50+
51+
/**
52+
* @var ResolveInfo|MockObject
53+
*/
54+
private ResolveInfo $resolveInfoMock;
55+
56+
/**
57+
* @var Context|MockObject
58+
*/
59+
private Context $contextMock;
60+
61+
/**
62+
* @var Quote|MockObject
63+
*/
64+
private Quote $quoteMock;
65+
66+
/**
67+
* @var QuoteIdMask|MockObject
68+
*/
69+
private QuoteIdMask $quoteIdMask;
70+
71+
/**
72+
* @var array
73+
*/
74+
private array $valueMock = [];
75+
76+
protected function setUp(): void
77+
{
78+
$this->fieldMock = $this->createMock(Field::class);
79+
$this->resolveInfoMock = $this->createMock(ResolveInfo::class);
80+
$this->contextMock = $this->createMock(Context::class);
81+
$this->quoteIdToMaskedQuoteId = $this->createPartialMock(
82+
QuoteIdToMaskedQuoteIdInterface::class,
83+
['execute']
84+
);
85+
$this->quoteIdMaskFactory = $this->createPartialMock(
86+
QuoteIdMaskFactory::class,
87+
['create']
88+
);
89+
$this->quoteIdMaskResourceModelMock = $this->getMockBuilder(QuoteIdMaskResourceModel::class)
90+
->disableOriginalConstructor()
91+
->addMethods(
92+
[
93+
'setQuoteId',
94+
]
95+
)
96+
->onlyMethods(['save'])
97+
->getMock();
98+
$this->maskedCartId = new MaskedCartId(
99+
$this->quoteIdToMaskedQuoteId,
100+
$this->quoteIdMaskFactory,
101+
$this->quoteIdMaskResourceModelMock
102+
);
103+
$this->quoteMock = $this->getMockBuilder(Quote::class)
104+
->disableOriginalConstructor()
105+
->getMock();
106+
$this->quoteIdMask = $this->getMockBuilder(QuoteIdMask::class)
107+
->disableOriginalConstructor()
108+
->getMock();
109+
}
110+
111+
public function testResolveWithoutModelInValueParameter(): void
112+
{
113+
$this->expectException(LocalizedException::class);
114+
$this->expectExceptionMessage('"model" value should be specified');
115+
$this->maskedCartId->resolve($this->fieldMock, $this->contextMock, $this->resolveInfoMock, $this->valueMock);
116+
}
117+
118+
public function testResolve(): void
119+
{
120+
$this->valueMock = ['model' => $this->quoteMock];
121+
$cartId = 1;
122+
$this->quoteMock
123+
->expects($this->once())
124+
->method('getId')
125+
->willReturn($cartId);
126+
$this->quoteIdMaskFactory
127+
->expects($this->once())
128+
->method('create')
129+
->willReturn($this->quoteIdMask);
130+
$this->quoteIdMask->setQuoteId($cartId);
131+
$this->quoteIdMaskResourceModelMock
132+
->expects($this->once())
133+
->method('save')
134+
->with($this->quoteIdMask);
135+
$this->maskedCartId->resolve($this->fieldMock, $this->contextMock, $this->resolveInfoMock, $this->valueMock);
136+
}
137+
}

app/code/Magento/QuoteGraphQl/etc/schema.graphqls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ type Cart @doc(description: "Contains the contents and other details about a gue
221221
}
222222

223223
interface CartAddressInterface @typeResolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartAddressTypeResolver") {
224+
uid: String! @doc(description: "The unique id of the customer address.")
224225
firstname: String! @doc(description: "The first name of the customer or guest.")
225226
lastname: String! @doc(description: "The last name of the customer or guest.")
226227
company: String @doc(description: "The company specified for the billing or shipping address.")
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
11+
<actionGroup name="AddProductToStorefrontActionGroup">
12+
<annotations>
13+
<description>Clicks on Add to Cart on a Storefront Product page. Validates that the Success Message is present and correct. Goes to the Storefront Shopping Cart page. Applies the provided Coupon Code to the Shopping Cart.</description>
14+
</annotations>
15+
<arguments>
16+
<argument name="product"/>
17+
</arguments>
18+
19+
<waitForElementNotVisible selector="{{StorefrontProductActionSection.addToCartDisabled}}" stepKey="waitForAddToCartButtonToRemoveDisabledState"/>
20+
<waitForElementClickable selector="{{StorefrontProductActionSection.addToCart}}" stepKey="waitForAddToCartButton"/>
21+
<click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addToCart"/>
22+
<waitForPageLoad stepKey="waitForAddToCart"/>
23+
<waitForElementVisible selector="{{StorefrontMessagesSection.success}}" stepKey="waitForSuccessMessage"/>
24+
<waitForText userInput="You added {{product.name}} to your shopping cart." stepKey="waitForText"/>
25+
<amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCheckoutPage"/>
26+
<waitForPageLoad stepKey="waitForPageLoad1"/>
27+
</actionGroup>
28+
</actionGroups>

0 commit comments

Comments
 (0)