diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminDashboardWithChartsChart.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminDashboardWithChartsTest.xml
similarity index 100%
rename from app/code/Magento/Backend/Test/Mftf/Test/AdminDashboardWithChartsChart.xml
rename to app/code/Magento/Backend/Test/Mftf/Test/AdminDashboardWithChartsTest.xml
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProductsTest.xml
similarity index 100%
rename from app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml
rename to app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProductsTest.xml
diff --git a/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php b/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php
index 76f5dbd1bea88..523efe08c6a4e 100644
--- a/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php
+++ b/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php
@@ -149,7 +149,7 @@ public function getItems()
$this->_compareProduct->setAllowUsedFlat(false);
$this->_items = $this->_itemCollectionFactory->create();
- $this->_items->useProductItem(true)->setStoreId($this->_storeManager->getStore()->getId());
+ $this->_items->useProductItem()->setStoreId($this->_storeManager->getStore()->getId());
if ($this->httpContext->getValue(Context::CONTEXT_AUTH)) {
$this->_items->setCustomerId($this->currentCustomer->getCustomerId());
diff --git a/app/code/Magento/Catalog/Helper/Product/Compare.php b/app/code/Magento/Catalog/Helper/Product/Compare.php
index 49a90c590a440..4e476fe8d1568 100644
--- a/app/code/Magento/Catalog/Helper/Product/Compare.php
+++ b/app/code/Magento/Catalog/Helper/Product/Compare.php
@@ -279,7 +279,7 @@ public function getItemCollection()
// cannot be placed in constructor because of the cyclic dependency which cannot be fixed with proxy class
// collection uses this helper in constructor when calling isEnabledFlat() method
$this->_itemCollection = $this->_itemCollectionFactory->create();
- $this->_itemCollection->useProductItem(true)->setStoreId($this->_storeManager->getStore()->getId());
+ $this->_itemCollection->useProductItem()->setStoreId($this->_storeManager->getStore()->getId());
if ($this->_customerSession->isLoggedIn()) {
$this->_itemCollection->setCustomerId($this->_customerSession->getCustomerId());
@@ -313,7 +313,7 @@ public function calculate($logout = false)
{
/** @var $collection Collection */
$collection = $this->_itemCollectionFactory->create()
- ->useProductItem(true);
+ ->useProductItem();
if (!$logout && $this->_customerSession->isLoggedIn()) {
$collection->setCustomerId($this->_customerSession->getCustomerId());
} elseif ($this->_customerId) {
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductFormCategoryExistInCategoryListActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductFormCategoryExistInCategoryListActionGroup.xml
new file mode 100644
index 0000000000000..c9ad309dcadc1
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductFormCategoryExistInCategoryListActionGroup.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ Check Category exist in Category list for Assign to Product.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductFormCategoryNotExistInCategoryListActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductFormCategoryNotExistInCategoryListActionGroup.xml
new file mode 100644
index 0000000000000..fb0717fe173af
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductFormCategoryNotExistInCategoryListActionGroup.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ Check Category not exist in Category list for Assign to Product.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSubmitCategoriesPopupActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSubmitCategoriesPopupActionGroup.xml
new file mode 100644
index 0000000000000..8905643658cd8
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSubmitCategoriesPopupActionGroup.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ Clicks the "Done" button on the Search Categories popup.
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontCategoryCurrentPageIsNthActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontCategoryCurrentPageIsNthActionGroup.xml
new file mode 100644
index 0000000000000..84e14269d24c2
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontCategoryCurrentPageIsNthActionGroup.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+ {{expectedPage}}
+ currentPageText
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontNavigateCategoryNextPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontNavigateCategoryNextPageActionGroup.xml
new file mode 100644
index 0000000000000..4776c9d32a34d
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontNavigateCategoryNextPageActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ Navigates storefront category next page from toolbar
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryBottomToolbarSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryBottomToolbarSection.xml
index 09eb4ad954274..c27a6107e5e35 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryBottomToolbarSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryBottomToolbarSection.xml
@@ -12,6 +12,6 @@
-
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/ConfigurableOptionTextInputLengthValidationHint.xml b/app/code/Magento/Catalog/Test/Mftf/Test/ConfigurableOptionTextInputLengthValidationHintTest.xml
similarity index 100%
rename from app/code/Magento/Catalog/Test/Mftf/Test/ConfigurableOptionTextInputLengthValidationHint.xml
rename to app/code/Magento/Catalog/Test/Mftf/Test/ConfigurableOptionTextInputLengthValidationHintTest.xml
diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php
index 28624c667e42b..360df8f4edc66 100644
--- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php
+++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php
@@ -572,11 +572,11 @@ public function prepareProductIndex($indexData, $productData, $storeId)
foreach ($indexData as $entityId => $attributeData) {
foreach ($attributeData as $attributeId => $attributeValues) {
$value = $this->getAttributeValue($attributeId, $attributeValues, $storeId);
- if (!empty($value)) {
+ if ($value !== null && $value !== false && $value != '') {
if (!isset($index[$attributeId])) {
$index[$attributeId] = [];
}
- $index[$attributeId][$entityId] = $value;
+ $index[$attributeId][$entityId] = $value;
}
}
}
diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontCheckUnableAdvancedSearchWithNegativePriceTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontCheckUnableAdvancedSearchWithNegativePriceTest.xml
index 67e9fdd43f5fe..cceac0475aa78 100644
--- a/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontCheckUnableAdvancedSearchWithNegativePriceTest.xml
+++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/StorefrontCheckUnableAdvancedSearchWithNegativePriceTest.xml
@@ -13,6 +13,7 @@
+
diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml
index c33b784fcd20c..192f20653f8c3 100644
--- a/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml
+++ b/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml
@@ -105,7 +105,7 @@
- opc-new-shipping-address
-
-
-
- Ship here
+ - Ship Here
- action primary action-save-address
-
diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminDeleteCmsPageTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminDeleteCmsPageTest.xml
index c46410dce919e..3687bb4fe5743 100644
--- a/app/code/Magento/Cms/Test/Mftf/Test/AdminDeleteCmsPageTest.xml
+++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminDeleteCmsPageTest.xml
@@ -14,6 +14,7 @@
+
diff --git a/app/code/Magento/Customer/Test/Mftf/Data/ExtensionAttributeSimple.xml b/app/code/Magento/Customer/Test/Mftf/Data/ExtensionAttributeSimpleData.xml
similarity index 100%
rename from app/code/Magento/Customer/Test/Mftf/Data/ExtensionAttributeSimple.xml
rename to app/code/Magento/Customer/Test/Mftf/Data/ExtensionAttributeSimpleData.xml
diff --git a/app/code/Magento/Customer/view/frontend/email/change_email.html b/app/code/Magento/Customer/view/frontend/email/change_email.html
index bd961ad99ec40..5341a2dc67ad5 100644
--- a/app/code/Magento/Customer/view/frontend/email/change_email.html
+++ b/app/code/Magento/Customer/view/frontend/email/change_email.html
@@ -18,8 +18,5 @@
{{trans "We have received a request to change the following information associated with your account at %store_name: email." store_name=$store.frontend_name}}
{{trans 'If you have not authorized this action, please contact us immediately at %store_email' store_email=$store_email |raw}}{{depend store_phone}} {{trans 'or call us at %store_phone' store_phone=$store_phone |raw}}{{/depend}}.
-
-
-{{trans "Thanks,
%store_name" store_name=$store.frontend_name |raw}}
{{template config_path="design/email/footer_template"}}
diff --git a/app/code/Magento/Customer/view/frontend/email/change_email_and_password.html b/app/code/Magento/Customer/view/frontend/email/change_email_and_password.html
index 4f5c85b2381f3..ed2af7ada669e 100644
--- a/app/code/Magento/Customer/view/frontend/email/change_email_and_password.html
+++ b/app/code/Magento/Customer/view/frontend/email/change_email_and_password.html
@@ -18,8 +18,5 @@
{{trans "We have received a request to change the following information associated with your account at %store_name: email, password." store_name=$store.frontend_name}}
{{trans 'If you have not authorized this action, please contact us immediately at %store_email' store_email=$store_email |raw}}{{depend store_phone}} {{trans 'or call us at %store_phone' store_phone=$store_phone |raw}}{{/depend}}.
-
-
-{{trans "Thanks,
%store_name" store_name=$store.frontend_name |raw}}
{{template config_path="design/email/footer_template"}}
diff --git a/app/code/Magento/Customer/view/frontend/email/password_reset.html b/app/code/Magento/Customer/view/frontend/email/password_reset.html
index cab05a89227b6..a6c54842a1573 100644
--- a/app/code/Magento/Customer/view/frontend/email/password_reset.html
+++ b/app/code/Magento/Customer/view/frontend/email/password_reset.html
@@ -19,8 +19,5 @@
{{trans "We have received a request to change the following information associated with your account at %store_name: password." store_name=$store.frontend_name}}
{{trans 'If you have not authorized this action, please contact us immediately at %store_email' store_email=$store_email |raw}}{{depend store_phone}} {{trans 'or call us at %store_phone' store_phone=$store_phone |raw}}{{/depend}}.
-
-
-{{trans "Thanks,
%store_name" store_name=$store.frontend_name |raw}}
{{template config_path="design/email/footer_template"}}
diff --git a/app/code/Magento/Downloadable/Test/Mftf/Test/AdminCreateAndSwitchProductType.xml b/app/code/Magento/Downloadable/Test/Mftf/Test/AdminCreateDownloadableProductSwitchToSimpleTest.xml
similarity index 100%
rename from app/code/Magento/Downloadable/Test/Mftf/Test/AdminCreateAndSwitchProductType.xml
rename to app/code/Magento/Downloadable/Test/Mftf/Test/AdminCreateDownloadableProductSwitchToSimpleTest.xml
diff --git a/app/code/Magento/Elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php b/app/code/Magento/Elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php
index 7f0ecf899e51c..245e4d494afe1 100644
--- a/app/code/Magento/Elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php
+++ b/app/code/Magento/Elasticsearch/Model/Adapter/BatchDataMapper/ProductDataMapper.php
@@ -209,7 +209,7 @@ private function convertAttribute(Attribute $attribute, array $attributeValues,
$productAttributes = [];
$retrievedValue = $this->retrieveFieldValue($attributeValues);
- if ($retrievedValue) {
+ if ($retrievedValue !== null) {
$productAttributes[$attribute->getAttributeCode()] = $retrievedValue;
if ($attribute->getIsSearchable()) {
@@ -354,7 +354,7 @@ private function getAttributeOptions(Attribute $attribute, int $storeId): array
*/
private function retrieveFieldValue(array $values)
{
- $values = \array_filter(\array_unique($values));
+ $values = \array_unique($values);
return count($values) === 1 ? \array_shift($values) : \array_values($values);
}
diff --git a/app/code/Magento/Elasticsearch/SearchAdapter/Filter/Builder/Term.php b/app/code/Magento/Elasticsearch/SearchAdapter/Filter/Builder/Term.php
index 76a2f00f44fe2..ce79f433460d9 100644
--- a/app/code/Magento/Elasticsearch/SearchAdapter/Filter/Builder/Term.php
+++ b/app/code/Magento/Elasticsearch/SearchAdapter/Filter/Builder/Term.php
@@ -68,7 +68,7 @@ public function buildFilter(RequestFilterInterface $filter)
$fieldName .= '.' . $suffix;
}
- if ($filter->getValue()) {
+ if ($filter->getValue() !== false) {
$operator = is_array($filter->getValue()) ? 'terms' : 'term';
$filterQuery []= [
$operator => [
diff --git a/app/code/Magento/GiftMessageGraphQl/Model/Resolver/Cart/GiftMessage.php b/app/code/Magento/GiftMessageGraphQl/Model/Resolver/Cart/GiftMessage.php
new file mode 100644
index 0000000000000..c317221fb6ef7
--- /dev/null
+++ b/app/code/Magento/GiftMessageGraphQl/Model/Resolver/Cart/GiftMessage.php
@@ -0,0 +1,94 @@
+cartRepository = $cartRepository;
+ $this->giftMessageHelper = $giftMessageHelper;
+ }
+
+ /**
+ * Return information about Gift message of cart
+ *
+ * @param Field $field
+ * @param ContextInterface $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ *
+ * @return array|Value|mixed
+ *
+ * @throws GraphQlInputException
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ) {
+ if (!isset($value['model'])) {
+ throw new GraphQlInputException(__('"model" value should be specified'));
+ }
+
+ $cart = $value['model'];
+
+ if (!$this->giftMessageHelper->isMessagesAllowed('order', $cart)) {
+ return null;
+ }
+
+ try {
+ $giftCartMessage = $this->cartRepository->get($cart->getId());
+ } catch (LocalizedException $e) {
+ throw new GraphQlInputException(__('Can\'t load cart.'));
+ }
+
+ if (!isset($giftCartMessage)) {
+ return null;
+ }
+
+ return [
+ 'to' => $giftCartMessage->getRecipient() ?? '',
+ 'from' => $giftCartMessage->getSender() ?? '',
+ 'message'=> $giftCartMessage->getMessage() ?? ''
+ ];
+ }
+}
diff --git a/app/code/Magento/GiftMessageGraphQl/Model/Resolver/Order/GiftMessage.php b/app/code/Magento/GiftMessageGraphQl/Model/Resolver/Order/GiftMessage.php
new file mode 100644
index 0000000000000..aae0e3709d87f
--- /dev/null
+++ b/app/code/Magento/GiftMessageGraphQl/Model/Resolver/Order/GiftMessage.php
@@ -0,0 +1,78 @@
+orderRepository = $orderRepository;
+ }
+
+ /**
+ * Return information about gift message for order
+ *
+ * @param Field $field
+ * @param ContextInterface $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ *
+ * @return array|Value|mixed
+ * @throws GraphQlInputException
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ) {
+ if (!isset($value['id'])) {
+ throw new GraphQlInputException(__('"id" value should be specified'));
+ }
+
+ try {
+ $orderGiftMessage = $this->orderRepository->get($value['id']);
+ } catch (LocalizedException $e) {
+ throw new GraphQlInputException(__('Can\'t load gift message for order'));
+ }
+
+ if (!isset($orderGiftMessage)) {
+ return null;
+ }
+
+ return [
+ 'to' => $orderGiftMessage->getRecipient() ?? '',
+ 'from' => $orderGiftMessage->getSender() ?? '',
+ 'message'=> $orderGiftMessage->getMessage() ?? ''
+ ];
+ }
+}
diff --git a/app/code/Magento/GiftMessageGraphQl/README.md b/app/code/Magento/GiftMessageGraphQl/README.md
new file mode 100644
index 0000000000000..fa2e02116b66c
--- /dev/null
+++ b/app/code/Magento/GiftMessageGraphQl/README.md
@@ -0,0 +1,3 @@
+# GiftMessageGraphQl
+
+**GiftMessageGraphQl** provides information about gift messages for cart, cart items, order and order items.
diff --git a/app/code/Magento/GiftMessageGraphQl/composer.json b/app/code/Magento/GiftMessageGraphQl/composer.json
new file mode 100644
index 0000000000000..48088f2a48a32
--- /dev/null
+++ b/app/code/Magento/GiftMessageGraphQl/composer.json
@@ -0,0 +1,25 @@
+{
+ "name": "magento/module-gift-message-graph-ql",
+ "description": "N/A",
+ "type": "magento2-module",
+ "require": {
+ "php": "~7.3.0||~7.4.0",
+ "magento/framework": "*",
+ "magento/module-gift-message": "*"
+ },
+ "suggest": {
+ "magento/module-graph-ql": "*"
+ },
+ "license": [
+ "OSL-3.0",
+ "AFL-3.0"
+ ],
+ "autoload": {
+ "files": [
+ "registration.php"
+ ],
+ "psr-4": {
+ "Magento\\GiftMessageGraphQl\\": ""
+ }
+ }
+}
diff --git a/app/code/Magento/GiftMessageGraphQl/etc/module.xml b/app/code/Magento/GiftMessageGraphQl/etc/module.xml
new file mode 100644
index 0000000000000..5eaaae0b0b988
--- /dev/null
+++ b/app/code/Magento/GiftMessageGraphQl/etc/module.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/GiftMessageGraphQl/etc/schema.graphqls b/app/code/Magento/GiftMessageGraphQl/etc/schema.graphqls
new file mode 100644
index 0000000000000..f14c812a9a5f3
--- /dev/null
+++ b/app/code/Magento/GiftMessageGraphQl/etc/schema.graphqls
@@ -0,0 +1,20 @@
+# Copyright © Magento, Inc. All rights reserved.
+# See COPYING.txt for license details.
+
+type Cart {
+ gift_message: GiftMessage @resolver (class: "\\Magento\\GiftMessageGraphQl\\Model\\Resolver\\Cart\\GiftMessage") @doc(description: "The entered gift message for the cart")
+}
+
+type SalesItemInterface {
+ gift_message: GiftMessage @doc(description: "The entered gift message for the order item")
+}
+
+type CustomerOrder {
+ gift_message: GiftMessage @resolver (class: "\\Magento\\GiftMessageGraphQl\\Model\\Resolver\\Order\\GiftMessage") @doc(description: "The entered gift message for the order")
+}
+
+type GiftMessage {
+ to: String! @doc(description: "Recepient name")
+ from: String! @doc(description: "Sender name")
+ message: String! @doc(description: "Gift message text")
+}
diff --git a/app/code/Magento/GiftMessageGraphQl/registration.php b/app/code/Magento/GiftMessageGraphQl/registration.php
new file mode 100644
index 0000000000000..bb260c23b0177
--- /dev/null
+++ b/app/code/Magento/GiftMessageGraphQl/registration.php
@@ -0,0 +1,13 @@
+Magento\Webapi\Model\Authorization\TokenUserContext
- 10
- -
-
- Magento\Webapi\Model\Authorization\OauthUserContext
- - 40
-
-
- Magento\Webapi\Model\Authorization\GuestUserContext
- 100
diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchGroupedProductBySkuWithHyphenTest.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchGroupedProductBySkuWithHyphenTest.xml
index aaa9cf5b2f925..e966ccf82648f 100644
--- a/app/code/Magento/GroupedProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchGroupedProductBySkuWithHyphenTest.xml
+++ b/app/code/Magento/GroupedProduct/Test/Mftf/Test/StorefrontAdvanceCatalogSearchGroupedProductBySkuWithHyphenTest.xml
@@ -21,7 +21,6 @@
-
diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckingWithCartPriceRuleMatchingSubtotalForMultiShipmentTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckingWithCartPriceRuleMatchingSubtotalForMultiShipmentTest.xml
index 02187658a8781..815d406c68bfa 100644
--- a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckingWithCartPriceRuleMatchingSubtotalForMultiShipmentTest.xml
+++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckingWithCartPriceRuleMatchingSubtotalForMultiShipmentTest.xml
@@ -19,12 +19,6 @@
-
-
-
-
-
-
diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckoutWithMultipleAddressesTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckoutWithMultipleAddressesTest.xml
index a49a37e475409..8205ab962b9fe 100644
--- a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckoutWithMultipleAddressesTest.xml
+++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCheckoutWithMultipleAddressesTest.xml
@@ -22,8 +22,6 @@
-
-
diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontOrderWithMultishippingTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontOrderWithMultishippingTest.xml
index 80407a219a841..2e5c0acc32053 100644
--- a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontOrderWithMultishippingTest.xml
+++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontOrderWithMultishippingTest.xml
@@ -27,7 +27,6 @@
-
@@ -43,7 +42,6 @@
-
diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontProcessMultishippingCheckoutWhenCartPageIsOpenedInAnotherTabTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontProcessMultishippingCheckoutWhenCartPageIsOpenedInAnotherTabTest.xml
index caf0ce3a51bae..7bb26525b173f 100644
--- a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontProcessMultishippingCheckoutWhenCartPageIsOpenedInAnotherTabTest.xml
+++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontProcessMultishippingCheckoutWhenCartPageIsOpenedInAnotherTabTest.xml
@@ -22,8 +22,6 @@
-
-
diff --git a/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php b/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php
index 6391219e23c7e..2519dd3a6fea8 100644
--- a/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php
+++ b/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php
@@ -116,6 +116,7 @@ public function setMessagesScope($scope)
* @param string $email
* @param int $websiteId
* @return array
+ * @throws LocalizedException
*/
public function loadBySubscriberEmail(string $email, int $websiteId): array
{
diff --git a/app/code/Magento/Newsletter/i18n/en_US.csv b/app/code/Magento/Newsletter/i18n/en_US.csv
index f390f6792635d..f8706967117fe 100644
--- a/app/code/Magento/Newsletter/i18n/en_US.csv
+++ b/app/code/Magento/Newsletter/i18n/en_US.csv
@@ -153,3 +153,6 @@ Store,Store
"Newsletter Subscriptions","Newsletter Subscriptions"
"We have updated your subscription.","We have updated your subscription."
"Are you sure you want to delete the selected subscriber(s)?","Are you sure you want to delete the selected subscriber(s)?"
+"Cannot create a newsletter subscription.","Cannot create a newsletter subscription."
+"Enter a valid email address.","Enter a valid email address."
+"Guests can not subscribe to the newsletter. You must create an account to subscribe.","Guests can not subscribe to the newsletter. You must create an account to subscribe."
diff --git a/app/code/Magento/Newsletter/view/frontend/email/subscr_success.html b/app/code/Magento/Newsletter/view/frontend/email/subscr_success.html
index d56163c10fdf3..996dff0c973e9 100644
--- a/app/code/Magento/Newsletter/view/frontend/email/subscr_success.html
+++ b/app/code/Magento/Newsletter/view/frontend/email/subscr_success.html
@@ -13,6 +13,6 @@
{{template config_path="design/email/header_template"}}
-{{trans "You have been successfully subscribed to our newsletter."}}
+{{trans "You have been successfully subscribed to our newsletter."}}
{{template config_path="design/email/footer_template"}}
diff --git a/app/code/Magento/Newsletter/view/frontend/email/unsub_success.html b/app/code/Magento/Newsletter/view/frontend/email/unsub_success.html
index d39b5d8a8b8e9..1f222f85abac7 100644
--- a/app/code/Magento/Newsletter/view/frontend/email/unsub_success.html
+++ b/app/code/Magento/Newsletter/view/frontend/email/unsub_success.html
@@ -13,6 +13,6 @@
{{template config_path="design/email/header_template"}}
-{{trans "You have been unsubscribed from the newsletter."}}
+{{trans "You have been unsubscribed from the newsletter."}}
{{template config_path="design/email/footer_template"}}
diff --git a/app/code/Magento/NewsletterGraphQl/Model/Resolver/SubscribeEmailToNewsletter.php b/app/code/Magento/NewsletterGraphQl/Model/Resolver/SubscribeEmailToNewsletter.php
new file mode 100644
index 0000000000000..a4b3bc43d0a8b
--- /dev/null
+++ b/app/code/Magento/NewsletterGraphQl/Model/Resolver/SubscribeEmailToNewsletter.php
@@ -0,0 +1,142 @@
+customerRepository = $customerRepository;
+ $this->enumLookup = $enumLookup;
+ $this->logger = $logger;
+ $this->subscriptionManager = $subscriptionManager;
+ $this->validator = $validator;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ) {
+ $email = trim($args['email']);
+
+ if (empty($email)) {
+ throw new GraphQlInputException(
+ __('You must specify an email address to subscribe to a newsletter.')
+ );
+ }
+
+ $currentUserId = (int)$context->getUserId();
+ $storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
+ $websiteId = (int)$context->getExtensionAttributes()->getStore()->getWebsiteId();
+
+ $this->validator->execute($email, $currentUserId, $websiteId);
+
+ try {
+ $subscriber = $this->isCustomerSubscription($email, $currentUserId)
+ ? $this->subscriptionManager->subscribeCustomer($currentUserId, $storeId)
+ : $this->subscriptionManager->subscribe($email, $storeId);
+
+ $status = $this->enumLookup->getEnumValueFromField(
+ 'SubscriptionStatusesEnum',
+ (string)$subscriber->getSubscriberStatus()
+ );
+ } catch (LocalizedException $e) {
+ $this->logger->error($e->getMessage());
+
+ throw new GraphQlInputException(
+ __('Cannot create a newsletter subscription.')
+ );
+ }
+
+ return [
+ 'status' => $status
+ ];
+ }
+
+ /**
+ * Returns true if a provided email equals to a current customer one
+ *
+ * @param string $email
+ * @param int $currentUserId
+ * @return bool
+ * @throws LocalizedException
+ * @throws NoSuchEntityException
+ */
+ private function isCustomerSubscription(string $email, int $currentUserId): bool
+ {
+ if ($currentUserId > 0) {
+ $customer = $this->customerRepository->getById($currentUserId);
+
+ if ($customer->getEmail() == $email) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/app/code/Magento/NewsletterGraphQl/Model/SubscribeEmailToNewsletter/Validation.php b/app/code/Magento/NewsletterGraphQl/Model/SubscribeEmailToNewsletter/Validation.php
new file mode 100644
index 0000000000000..8b8cac0c58cf2
--- /dev/null
+++ b/app/code/Magento/NewsletterGraphQl/Model/SubscribeEmailToNewsletter/Validation.php
@@ -0,0 +1,195 @@
+customerAccountManagement = $customerAccountManagement;
+ $this->customerRepository = $customerRepository;
+ $this->emailValidator = $emailValidator;
+ $this->logger = $logger;
+ $this->scopeConfig = $scopeConfig;
+ $this->subscriberResource = $subscriberResource;
+ }
+
+ /**
+ * Validate the next cases:
+ * - email format
+ * - email address isn't being used by a different account
+ * - if a guest user can be subscribed to a newsletter
+ * - verify if email is already subscribed
+ *
+ * @param string $email
+ * @param int $currentUserId
+ * @param int $websiteId
+ * @throws GraphQlAlreadyExistsException
+ * @throws GraphQlInputException
+ */
+ public function execute(string $email = '', int $currentUserId = 0, int $websiteId = 1): void
+ {
+ $this->validateEmailFormat($email);
+
+ if ($currentUserId > 0) {
+ $this->validateEmailAvailable($email, $currentUserId, $websiteId);
+ } else {
+ $this->validateGuestSubscription();
+ }
+
+ $this->validateAlreadySubscribed($email, $websiteId);
+ }
+
+ /**
+ * Validate the format of the email address
+ *
+ * @param string $email
+ * @throws GraphQlInputException
+ */
+ private function validateEmailFormat(string $email): void
+ {
+ if (!$this->emailValidator->isValid($email)) {
+ throw new GraphQlInputException(__('Enter a valid email address.'));
+ }
+ }
+
+ /**
+ * Validate that the email address isn't being used by a different account.
+ *
+ * @param string $email
+ * @param int $currentUserId
+ * @param int $websiteId
+ * @throws GraphQlInputException
+ */
+ private function validateEmailAvailable(string $email, int $currentUserId, int $websiteId): void
+ {
+ try {
+ $customer = $this->customerRepository->getById($currentUserId);
+ $customerEmail = $customer->getEmail();
+ } catch (LocalizedException $e) {
+ $customerEmail = '';
+ }
+
+ try {
+ $emailAvailable = $this->customerAccountManagement->isEmailAvailable($email, $websiteId);
+ } catch (LocalizedException $e) {
+ $emailAvailable = false;
+ }
+
+ if (!$emailAvailable && $customerEmail != $email) {
+ $this->logger->error(
+ __('This email address is already assigned to another user.')
+ );
+
+ throw new GraphQlInputException(
+ __('Cannot create a newsletter subscription.')
+ );
+ }
+ }
+
+ /**
+ * Validate if a guest user can be subscribed to a newsletter.
+ *
+ * @throws GraphQlInputException
+ */
+ private function validateGuestSubscription(): void
+ {
+ if (!$this->scopeConfig->getValue(
+ Subscriber::XML_PATH_ALLOW_GUEST_SUBSCRIBE_FLAG,
+ ScopeInterface::SCOPE_STORE
+ )) {
+ throw new GraphQlInputException(
+ __('Guests can not subscribe to the newsletter. You must create an account to subscribe.')
+ );
+ }
+ }
+
+ /**
+ * Verify if email is already subscribed
+ *
+ * @param string $email
+ * @param int $websiteId
+ * @throws GraphQlAlreadyExistsException
+ */
+ private function validateAlreadySubscribed(string $email, int $websiteId): void
+ {
+ try {
+ $subscriberData = $this->subscriberResource->loadBySubscriberEmail($email, $websiteId);
+ } catch (LocalizedException $e) {
+ $subscriberData = [];
+ }
+
+ if (isset($subscriberData['subscriber_status'])
+ && (int)$subscriberData['subscriber_status'] === Subscriber::STATUS_SUBSCRIBED) {
+ throw new GraphQlAlreadyExistsException(
+ __('This email address is already subscribed.')
+ );
+ }
+ }
+}
diff --git a/app/code/Magento/NewsletterGraphQl/README.md b/app/code/Magento/NewsletterGraphQl/README.md
new file mode 100644
index 0000000000000..c65d44fbcfeba
--- /dev/null
+++ b/app/code/Magento/NewsletterGraphQl/README.md
@@ -0,0 +1 @@
+The Magento_NewsletterGraphQl module allows a shopper to subscribe to a newsletter using GraphQL.
diff --git a/app/code/Magento/NewsletterGraphQl/composer.json b/app/code/Magento/NewsletterGraphQl/composer.json
new file mode 100644
index 0000000000000..92352a8a9adfe
--- /dev/null
+++ b/app/code/Magento/NewsletterGraphQl/composer.json
@@ -0,0 +1,30 @@
+{
+ "name": "magento/module-newsletter-graph-ql",
+ "description": "Provides GraphQl functionality for the newsletter subscriptions.",
+ "config": {
+ "sort-packages": true
+ },
+ "type": "magento2-module",
+ "require": {
+ "php": "~7.3.0||~7.4.0",
+ "magento/framework": "*",
+ "magento/module-customer": "*",
+ "magento/module-newsletter": "*",
+ "magento/module-store": "*"
+ },
+ "suggest": {
+ "magento/module-graph-ql": "*"
+ },
+ "license": [
+ "OSL-3.0",
+ "AFL-3.0"
+ ],
+ "autoload": {
+ "files": [
+ "registration.php"
+ ],
+ "psr-4": {
+ "Magento\\NewsletterGraphQl\\": ""
+ }
+ }
+}
diff --git a/app/code/Magento/NewsletterGraphQl/etc/graphql/di.xml b/app/code/Magento/NewsletterGraphQl/etc/graphql/di.xml
new file mode 100644
index 0000000000000..302a562ec4700
--- /dev/null
+++ b/app/code/Magento/NewsletterGraphQl/etc/graphql/di.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+ -
+
- 1
+ - 2
+ - 3
+ - 4
+
+
+
+
+
diff --git a/app/code/Magento/NewsletterGraphQl/etc/module.xml b/app/code/Magento/NewsletterGraphQl/etc/module.xml
new file mode 100644
index 0000000000000..8bda85d80c830
--- /dev/null
+++ b/app/code/Magento/NewsletterGraphQl/etc/module.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/NewsletterGraphQl/etc/schema.graphqls b/app/code/Magento/NewsletterGraphQl/etc/schema.graphqls
new file mode 100644
index 0000000000000..d96756e12caea
--- /dev/null
+++ b/app/code/Magento/NewsletterGraphQl/etc/schema.graphqls
@@ -0,0 +1,17 @@
+# Copyright © Magento, Inc. All rights reserved.
+# See COPYING.txt for license details.
+
+type Mutation {
+ subscribeEmailToNewsletter(email: String!): SubscribeEmailToNewsletterOutput @doc(description:"Subscribes the specified email to a newsletter") @resolver(class: "Magento\\NewsletterGraphQl\\Model\\Resolver\\SubscribeEmailToNewsletter")
+}
+
+type SubscribeEmailToNewsletterOutput {
+ status: SubscriptionStatusesEnum @doc(description: "Returns the status of the subscription request")
+}
+
+enum SubscriptionStatusesEnum {
+ NOT_ACTIVE
+ SUBSCRIBED
+ UNSUBSCRIBED
+ UNCONFIRMED
+}
diff --git a/app/code/Magento/NewsletterGraphQl/registration.php b/app/code/Magento/NewsletterGraphQl/registration.php
new file mode 100644
index 0000000000000..82d5512f4afb5
--- /dev/null
+++ b/app/code/Magento/NewsletterGraphQl/registration.php
@@ -0,0 +1,9 @@
+getData('item_collection');
if ($collection === null) {
if ($collection = $this->getCreateOrderModel()->getCustomerCompareList()) {
- $collection = $collection->getItemCollection()->useProductItem(
- true
- )->setStoreId(
- $this->getQuote()->getStoreId()
- )->addStoreFilter(
- $this->getQuote()->getStoreId()
- )->setCustomerId(
- $this->getCustomerId()
- )->addAttributeToSelect(
- 'name'
- )->addAttributeToSelect(
- 'price'
- )->addAttributeToSelect(
- 'image'
- )->addAttributeToSelect(
- 'status'
- )->load();
+ $collection = $collection->getItemCollection()
+ ->useProductItem()
+ ->setStoreId($this->getQuote()->getStoreId())
+ ->addStoreFilter($this->getQuote()->getStoreId())
+ ->setCustomerId($this->getCustomerId())
+ ->addAttributeToSelect('name')
+ ->addAttributeToSelect('price')->addAttributeToSelect('image')
+ ->addAttributeToSelect('status')
+ ->load();
}
$this->setData('item_collection', $collection);
}
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/Pcompared.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/Pcompared.php
index 8442d5b36466e..c9f251621f9de 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/Pcompared.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/Pcompared.php
@@ -89,13 +89,11 @@ public function getItemCollection()
// get products to skip
$skipProducts = [];
if ($collection = $this->getCreateOrderModel()->getCustomerCompareList()) {
- $collection = $collection->getItemCollection()->useProductItem(
- true
- )->setStoreId(
- $this->getStoreId()
- )->setCustomerId(
- $this->getCustomerId()
- )->load();
+ $collection = $collection->getItemCollection()
+ ->useProductItem()
+ ->setStoreId($this->getStoreId())
+ ->setCustomerId($this->getCustomerId())
+ ->load();
foreach ($collection as $_item) {
$skipProducts[] = $_item->getProductId();
}
diff --git a/app/code/Magento/Sales/Cron/CleanExpiredQuotes.php b/app/code/Magento/Sales/Cron/CleanExpiredQuotes.php
index a3242228b28e0..978aec1b79ec4 100644
--- a/app/code/Magento/Sales/Cron/CleanExpiredQuotes.php
+++ b/app/code/Magento/Sales/Cron/CleanExpiredQuotes.php
@@ -5,12 +5,15 @@
*/
namespace Magento\Sales\Cron;
-use Magento\Quote\Model\ResourceModel\Quote\Collection;
+use Exception;
+use Magento\Quote\Model\QuoteRepository;
+use Magento\Quote\Model\ResourceModel\Quote\Collection as QuoteCollection;
use Magento\Sales\Model\ResourceModel\Collection\ExpiredQuotesCollection;
use Magento\Store\Model\StoreManagerInterface;
+use Psr\Log\LoggerInterface;
/**
- * Class CleanExpiredQuotes
+ * Cron job for cleaning expired Quotes
*/
class CleanExpiredQuotes
{
@@ -24,16 +27,32 @@ class CleanExpiredQuotes
*/
private $storeManager;
+ /**
+ * @var QuoteRepository
+ */
+ private $quoteRepository;
+
+ /**
+ * @var LoggerInterface
+ */
+ private $logger;
+
/**
* @param StoreManagerInterface $storeManager
* @param ExpiredQuotesCollection $expiredQuotesCollection
+ * @param QuoteRepository $quoteRepository
+ * @param LoggerInterface $logger
*/
public function __construct(
StoreManagerInterface $storeManager,
- ExpiredQuotesCollection $expiredQuotesCollection
+ ExpiredQuotesCollection $expiredQuotesCollection,
+ QuoteRepository $quoteRepository,
+ LoggerInterface $logger
) {
$this->storeManager = $storeManager;
$this->expiredQuotesCollection = $expiredQuotesCollection;
+ $this->quoteRepository = $quoteRepository;
+ $this->logger = $logger;
}
/**
@@ -45,9 +64,41 @@ public function execute()
{
$stores = $this->storeManager->getStores(true);
foreach ($stores as $store) {
- /** @var $quotes Collection */
- $quotes = $this->expiredQuotesCollection->getExpiredQuotes($store);
- $quotes->walk('delete');
+ /** @var $quoteCollection QuoteCollection */
+ $quoteCollection = $this->expiredQuotesCollection->getExpiredQuotes($store);
+ $quoteCollection->setPageSize(50);
+
+ // Last page returns 1 even when we don't have any results
+ $lastPage = $quoteCollection->getSize() ? $quoteCollection->getLastPageNumber() : 0;
+
+ for ($currentPage = $lastPage; $currentPage >= 1; $currentPage--) {
+ $quoteCollection->setCurPage($currentPage);
+
+ $this->deleteQuotes($quoteCollection);
+ }
}
}
+
+ /**
+ * Deletes all quotes in collection
+ *
+ * @param QuoteCollection $quoteCollection
+ */
+ private function deleteQuotes(QuoteCollection $quoteCollection): void
+ {
+ foreach ($quoteCollection as $quote) {
+ try {
+ $this->quoteRepository->delete($quote);
+ } catch (Exception $e) {
+ $message = sprintf(
+ 'Unable to delete expired quote (ID: %s): %s',
+ $quote->getId(),
+ (string)$e
+ );
+ $this->logger->error($message);
+ }
+ }
+
+ $quoteCollection->clear();
+ }
}
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/StorefrontCreateOrdersWithMoveJSCodeBottomTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontCreateOrdersWithMoveJSCodeBottomTest.xml
index 0888132669177..1c67d778937d1 100644
--- a/app/code/Magento/Sales/Test/Mftf/Test/StorefrontCreateOrdersWithMoveJSCodeBottomTest.xml
+++ b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontCreateOrdersWithMoveJSCodeBottomTest.xml
@@ -10,8 +10,10 @@
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
+
+
diff --git a/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php b/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php
index 57a61fecae5ca..76159dc8320e1 100644
--- a/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php
+++ b/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php
@@ -7,63 +7,83 @@
namespace Magento\SampleData\Console\Command;
use Composer\Console\Application;
+use Composer\Console\ApplicationFactory;
+use Exception;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Console\Cli;
+use Magento\Framework\Exception\FileSystemException;
+use Magento\Framework\Exception\InvalidArgumentException;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Filesystem;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\SampleData\Model\Dependency;
use Magento\Setup\Model\PackagesAuth;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\ArrayInputFactory;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Command for deployment of Sample Data
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class SampleDataDeployCommand extends Command
{
const OPTION_NO_UPDATE = 'no-update';
/**
- * @var \Magento\Framework\Filesystem
+ * @var Filesystem
*/
private $filesystem;
/**
- * @var \Magento\SampleData\Model\Dependency
+ * @var Dependency
*/
private $sampleDataDependency;
/**
- * @var \Symfony\Component\Console\Input\ArrayInputFactory
+ * @var ArrayInputFactory
* @deprecated 100.1.0
*/
private $arrayInputFactory;
/**
- * @var \Composer\Console\ApplicationFactory
+ * @var ApplicationFactory
*/
private $applicationFactory;
/**
- * @param \Magento\Framework\Filesystem $filesystem
- * @param \Magento\SampleData\Model\Dependency $sampleDataDependency
- * @param \Symfony\Component\Console\Input\ArrayInputFactory $arrayInputFactory
- * @param \Composer\Console\ApplicationFactory $applicationFactory
+ * @var Json
+ */
+ private $serializer;
+
+ /**
+ * @param Filesystem $filesystem
+ * @param Dependency $sampleDataDependency
+ * @param ArrayInputFactory $arrayInputFactory
+ * @param ApplicationFactory $applicationFactory
+ * @param Json $serializer
*/
public function __construct(
- \Magento\Framework\Filesystem $filesystem,
- \Magento\SampleData\Model\Dependency $sampleDataDependency,
- \Symfony\Component\Console\Input\ArrayInputFactory $arrayInputFactory,
- \Composer\Console\ApplicationFactory $applicationFactory
+ Filesystem $filesystem,
+ Dependency $sampleDataDependency,
+ ArrayInputFactory $arrayInputFactory,
+ ApplicationFactory $applicationFactory,
+ Json $serializer
) {
$this->filesystem = $filesystem;
$this->sampleDataDependency = $sampleDataDependency;
$this->arrayInputFactory = $arrayInputFactory;
$this->applicationFactory = $applicationFactory;
+ $this->serializer = $serializer;
parent::__construct();
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
protected function configure()
{
@@ -79,15 +99,42 @@ protected function configure()
}
/**
- * {@inheritdoc}
+ * @inheritdoc
+ *
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return int
+ * @throws FileSystemException
+ * @throws LocalizedException
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
- $rootJson = json_decode($this->filesystem->getDirectoryRead(DirectoryList::ROOT)->readFile("composer.json"));
- if (!isset($rootJson->version)) {
- // @codingStandardsIgnoreLine
- $output->writeln('' . 'Git installations must deploy sample data from GitHub; see https://devdocs.magento.com/guides/v2.3/install-gde/install/sample-data-after-clone.html for more information.' . '');
- return;
+ $rootJson = $this->serializer->unserialize(
+ $this->filesystem->getDirectoryRead(
+ DirectoryList::ROOT
+ )->readFile("composer.json")
+ );
+ if (!isset($rootJson['version'])) {
+ $magentoProductPackage = array_filter(
+ $rootJson['require'],
+ function ($package) {
+ return false !== strpos($package, 'magento/product-');
+ },
+ ARRAY_FILTER_USE_KEY
+ );
+ $version = reset($magentoProductPackage);
+ $output->writeln(
+ '' .
+ // @codingStandardsIgnoreLine
+ 'We don\'t recommend to remove the "version" field from your composer.json; see https://getcomposer.org/doc/02-libraries.md#library-versioning for more information.' .
+ ''
+ );
+ $restoreVersion = new ArrayInput([
+ 'command' => 'config',
+ 'setting-key' => 'version',
+ 'setting-value' => [$version],
+ '--quiet' => 1
+ ]);
}
$this->updateMemoryLimit();
$this->createAuthFile();
@@ -109,6 +156,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
/** @var Application $application */
$application = $this->applicationFactory->create();
$application->setAutoExit(false);
+ if (!empty($restoreVersion)) {
+ $result = $application->run($restoreVersion, clone $output);
+ if ($result === 0) {
+ $output->writeln('The field "version" has been restored.');
+ }
+ }
$result = $application->run($commandInput, $output);
if ($result !== 0) {
$output->writeln(
@@ -116,9 +169,15 @@ protected function execute(InputInterface $input, OutputInterface $output)
. ''
);
$application->resetComposer();
+
+ return Cli::RETURN_FAILURE;
}
+
+ return Cli::RETURN_SUCCESS;
} else {
$output->writeln('' . 'There is no sample data for current set of modules.' . '');
+
+ return Cli::RETURN_FAILURE;
}
}
@@ -128,7 +187,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
* We create auth.json with correct permissions instead of relying on Composer.
*
* @return void
- * @throws \Exception
+ * @throws LocalizedException
*/
private function createAuthFile()
{
@@ -137,30 +196,51 @@ private function createAuthFile()
if (!$directory->isExist(PackagesAuth::PATH_TO_AUTH_FILE)) {
try {
$directory->writeFile(PackagesAuth::PATH_TO_AUTH_FILE, '{}');
- } catch (\Exception $e) {
- $message = 'Error in writing Auth file '
- . $directory->getAbsolutePath(PackagesAuth::PATH_TO_AUTH_FILE)
- . '. Please check permissions for writing.';
- throw new \Exception($message);
+ } catch (Exception $e) {
+ throw new LocalizedException(__(
+ 'Error in writing Auth file %1. Please check permissions for writing.',
+ $directory->getAbsolutePath(PackagesAuth::PATH_TO_AUTH_FILE)
+ ));
}
}
}
/**
+ * Updates PHP memory limit
+ *
+ * @throws InvalidArgumentException
* @return void
*/
private function updateMemoryLimit()
{
if (function_exists('ini_set')) {
- @ini_set('display_errors', 1);
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ $result = ini_set('display_errors', 1);
+ if ($result === false) {
+ $error = error_get_last();
+ throw new InvalidArgumentException(__(
+ 'Failed to set ini option display_errors to value 1. %1',
+ $error['message']
+ ));
+ }
$memoryLimit = trim(ini_get('memory_limit'));
if ($memoryLimit != -1 && $this->getMemoryInBytes($memoryLimit) < 756 * 1024 * 1024) {
- @ini_set('memory_limit', '756M');
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ $result = ini_set('memory_limit', '756M');
+ if ($result === false) {
+ $error = error_get_last();
+ throw new InvalidArgumentException(__(
+ 'Failed to set ini option memory_limit to 756M. %1',
+ $error['message']
+ ));
+ }
}
}
}
/**
+ * Retrieves the memory size in bytes
+ *
* @param string $value
* @return int
*/
diff --git a/app/code/Magento/SampleData/Test/Unit/Console/Command/AbstractSampleDataCommandTest.php b/app/code/Magento/SampleData/Test/Unit/Console/Command/AbstractSampleDataCommandTest.php
index 51235dbffc417..3bf664ea6b0d2 100644
--- a/app/code/Magento/SampleData/Test/Unit/Console/Command/AbstractSampleDataCommandTest.php
+++ b/app/code/Magento/SampleData/Test/Unit/Console/Command/AbstractSampleDataCommandTest.php
@@ -20,10 +20,22 @@
use Symfony\Component\Console\Input\ArrayInputFactory;
/**
+ * Common class for tests
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
abstract class AbstractSampleDataCommandTest extends TestCase
{
+ /*
+ * Expected arguments for `composer config` to set missing field "version"
+ */
+ private const STUB_EXPECTED_COMPOSER_CONFIG = [
+ 'command' => 'config',
+ 'setting-key' => 'version',
+ 'setting-value' => ['0.0.1'],
+ '--quiet' => 1
+ ];
+
/**
* @var ReadInterface|MockObject
*/
@@ -60,8 +72,10 @@ abstract class AbstractSampleDataCommandTest extends TestCase
protected $applicationFactoryMock;
/**
- * @return void
+ * @var int
*/
+ private $appRunResult;
+
protected function setUp(): void
{
$this->directoryReadMock = $this->getMockForAbstractClass(ReadInterface::class);
@@ -74,47 +88,84 @@ protected function setUp(): void
}
/**
- * @param array $sampleDataPackages Array in form [package_name => version_constraint]
- * @param string $pathToComposerJson Fake path to composer.json
- * @param int $appRunResult Composer exit code
+ * @param array $sampleDataPackages Array in form [package_name => version_constraint]
+ * @param string $pathToComposerJson Fake path to composer.json
+ * @param int $appRunResult Composer exit code
+ * @param array $composerJsonContent Content of the composer.json
* @param array $additionalComposerArgs Additional arguments that composer expects
*/
protected function setupMocks(
$sampleDataPackages,
$pathToComposerJson,
$appRunResult,
+ $composerJsonContent = [],
$additionalComposerArgs = []
) {
- $this->directoryReadMock->expects($this->any())->method('getAbsolutePath')->willReturn($pathToComposerJson);
- $this->directoryReadMock->expects($this->any())->method('readFile')->with('composer.json')->willReturn(
- '{"version": "0.0.1"}'
- );
- $this->filesystemMock->expects($this->any())->method('getDirectoryRead')->with(DirectoryList::ROOT)->willReturn(
- $this->directoryReadMock
- );
- $this->sampleDataDependencyMock->expects($this->any())->method('getSampleDataPackages')->willReturn(
- $sampleDataPackages
- );
+ $this->appRunResult = $appRunResult;
+ $this->directoryReadMock->expects($this->any())
+ ->method('getAbsolutePath')
+ ->willReturn($pathToComposerJson);
+ $this->directoryReadMock->expects($this->any())
+ ->method('readFile')
+ ->with('composer.json')
+ ->willReturn(json_encode($composerJsonContent));
+ $this->filesystemMock->expects($this->any())
+ ->method('getDirectoryRead')
+ ->with(DirectoryList::ROOT)
+ ->willReturn($this->directoryReadMock);
+ $this->sampleDataDependencyMock->expects($this->any())
+ ->method('getSampleDataPackages')
+ ->willReturn($sampleDataPackages);
$this->arrayInputFactoryMock->expects($this->never())->method('create');
- $this->applicationMock->expects($this->any())
- ->method('run')
- ->with(
- new ArrayInput(
- array_merge(
- $this->expectedComposerArguments(
- $sampleDataPackages,
- $pathToComposerJson
+ if (!array_key_exists('version', $composerJsonContent)) {
+ $this->applicationMock->expects($this->any())
+ ->method('run')
+ ->withConsecutive(
+ [
+ 'input' => new ArrayInput(
+ self::STUB_EXPECTED_COMPOSER_CONFIG
),
- $additionalComposerArgs
- )
- ),
- $this->anything()
- )
- ->willReturn($appRunResult);
+ 'output' => $this->anything()
+ ],
+ [
+ 'input' => new ArrayInput(
+ array_merge(
+ $this->expectedComposerArgumentsSampleDataCommands(
+ $sampleDataPackages,
+ $pathToComposerJson
+ ),
+ $additionalComposerArgs
+ )
+ ),
+ 'output' => $this->anything()
+ ]
+ )->willReturnOnConsecutiveCalls(
+ $this->returnValue(0),
+ $this->returnValue($appRunResult)
+ );
+ } else {
+ $this->applicationMock->expects($this->any())
+ ->method('run')
+ ->with(
+ new ArrayInput(
+ array_merge(
+ $this->expectedComposerArgumentsSampleDataCommands(
+ $sampleDataPackages,
+ $pathToComposerJson
+ ),
+ $additionalComposerArgs
+ )
+ ),
+ $this->anything()
+ )
+ ->willReturn($appRunResult);
+ }
if (($appRunResult !== 0) && !empty($sampleDataPackages)) {
- $this->applicationMock->expects($this->once())->method('resetComposer')->willReturnSelf();
+ $this->applicationMock->expects($this->any())
+ ->method('resetComposer')
+ ->willReturnSelf();
}
$this->applicationFactoryMock->expects($this->any())
@@ -123,14 +174,14 @@ protected function setupMocks(
}
/**
- * Expected arguments for composer based on sample data packages and composer.json path
+ * Expected arguments for composer based on sample data command
*
* @param array $sampleDataPackages
* @param string $pathToComposerJson
* @return array
*/
- abstract protected function expectedComposerArguments(
+ abstract protected function expectedComposerArgumentsSampleDataCommands(
array $sampleDataPackages,
string $pathToComposerJson
- ) : array;
+ ): array;
}
diff --git a/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php
index 45db83403b4f5..a1186d6015871 100644
--- a/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php
+++ b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php
@@ -7,26 +7,54 @@
namespace Magento\SampleData\Test\Unit\Console\Command;
+use Exception;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Serialize\Serializer\Json;
use Magento\SampleData\Console\Command\SampleDataDeployCommand;
use Magento\Setup\Model\PackagesAuth;
+use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\Console\Tester\CommandTester;
class SampleDataDeployCommandTest extends AbstractSampleDataCommandTest
{
/**
+ * @var Json|MockObject
+ */
+ private $serializerMock;
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+ $this->serializerMock = $this->createMock(Json::class);
+ }
+
+ /**
+ * Sets mock for unserialization composer content
+ * @param array $composerJsonContent
+ * @return void
+ */
+ protected function setupMockForSerializer(array $composerJsonContent): void
+ {
+ $this->serializerMock->expects($this->any())
+ ->method('unserialize')
+ ->will($this->returnValue($composerJsonContent));
+ }
+
+ /**
+ * Sets mocks for auth file
+ *
* @param bool $authExist True to test with existing auth.json, false without
+ * @return void
*/
- protected function setupMocksForAuthFile($authExist)
+ protected function setupMocksForAuthFile(bool $authExist): void
{
$this->directoryWriteMock->expects($this->once())
->method('isExist')
->with(PackagesAuth::PATH_TO_AUTH_FILE)
->willReturn($authExist);
- $this->directoryWriteMock->expects($authExist ? $this->never() : $this->once())->method('writeFile')->with(
- PackagesAuth::PATH_TO_AUTH_FILE,
- '{}'
- );
+ $this->directoryWriteMock->expects($authExist ? $this->never() : $this->once())
+ ->method('writeFile')
+ ->with(PackagesAuth::PATH_TO_AUTH_FILE, '{}');
$this->filesystemMock->expects($this->once())
->method('getDirectoryWrite')
->with(DirectoryList::COMPOSER_HOME)
@@ -34,18 +62,30 @@ protected function setupMocksForAuthFile($authExist)
}
/**
- * @param array $sampleDataPackages
- * @param int $appRunResult - int 0 if everything went fine, or an error code
- * @param string $expectedMsg
- * @param bool $authExist
- * @return void
+ * @param array $sampleDataPackages
+ * @param int $appRunResult - int 0 if everything went fine, or an error code
+ * @param array $composerJsonContent
+ * @param string $expectedMsg
+ * @param bool $authExist
+ * @return void
*
* @dataProvider processDataProvider
*/
- public function testExecute(array $sampleDataPackages, $appRunResult, $expectedMsg, $authExist)
- {
- $this->setupMocks($sampleDataPackages, '/path/to/composer.json', $appRunResult);
+ public function testExecute(
+ array $sampleDataPackages,
+ int $appRunResult,
+ array $composerJsonContent,
+ string $expectedMsg,
+ bool $authExist
+ ): void {
+ $this->setupMocks(
+ $sampleDataPackages,
+ '/path/to/composer.json',
+ $appRunResult,
+ $composerJsonContent
+ );
$this->setupMocksForAuthFile($authExist);
+ $this->setupMockForSerializer($composerJsonContent);
$commandTester = $this->createCommandTester();
$commandTester->execute([]);
@@ -53,23 +93,31 @@ public function testExecute(array $sampleDataPackages, $appRunResult, $expectedM
}
/**
- * @param array $sampleDataPackages
- * @param int $appRunResult - int 0 if everything went fine, or an error code
- * @param string $expectedMsg
- * @param bool $authExist
- * @return void
+ * @param array $sampleDataPackages
+ * @param int $appRunResult - int 0 if everything went fine, or an error code
+ * @param array $composerJsonContent
+ * @param string $expectedMsg
+ * @param bool $authExist
+ * @return void
*
* @dataProvider processDataProvider
*/
- public function testExecuteWithNoUpdate(array $sampleDataPackages, $appRunResult, $expectedMsg, $authExist)
- {
+ public function testExecuteWithNoUpdate(
+ array $sampleDataPackages,
+ int $appRunResult,
+ array $composerJsonContent,
+ string $expectedMsg,
+ bool $authExist
+ ): void {
$this->setupMocks(
$sampleDataPackages,
'/path/to/composer.json',
$appRunResult,
+ $composerJsonContent,
['--no-update' => 1]
);
$this->setupMocksForAuthFile($authExist);
+ $this->setupMockForSerializer($composerJsonContent);
$commandInput = ['--no-update' => 1];
$commandTester = $this->createCommandTester();
@@ -79,14 +127,20 @@ public function testExecuteWithNoUpdate(array $sampleDataPackages, $appRunResult
}
/**
+ * Data provider
+ *
* @return array
*/
- public function processDataProvider()
+ public function processDataProvider(): array
{
return [
'No sample data found' => [
'sampleDataPackages' => [],
'appRunResult' => 1,
+ 'composerJsonContent' => [
+ 'require' => ["magento/product-community-edition" => "0.0.1"],
+ 'version' => '0.0.1'
+ ],
'expectedMsg' => 'There is no sample data for current set of modules.' . PHP_EOL,
'authExist' => true,
],
@@ -95,15 +149,36 @@ public function processDataProvider()
'magento/module-cms-sample-data' => '1.0.0-beta',
],
'appRunResult' => 1,
+ 'composerJsonContent' => [
+ 'require' => ["magento/product-community-edition" => "0.0.1"],
+ 'version' => '0.0.1'
+ ],
'expectedMsg' => 'There is an error during sample data deployment. Composer file will be reverted.'
. PHP_EOL,
'authExist' => false,
],
+ 'Successful sample data installation without field "version"' => [
+ 'sampleDataPackages' => [
+ 'magento/module-cms-sample-data' => '1.0.0-beta',
+ ],
+ 'appRunResult' => 0,
+ 'composerJsonContent' => [
+ 'require' => ["magento/product-community-edition" => "0.0.1"]
+ ],
+ // @codingStandardsIgnoreLine
+ 'expectedMsg' => 'We don\'t recommend to remove the "version" field from your composer.json; see https://getcomposer.org/doc/02-libraries.md#library-versioning for more information.'
+ . PHP_EOL . 'The field "version" has been restored.' . PHP_EOL,
+ 'authExist' => true,
+ ],
'Successful sample data installation' => [
'sampleDataPackages' => [
'magento/module-cms-sample-data' => '1.0.0-beta',
],
'appRunResult' => 0,
+ 'composerJsonContent' => [
+ 'require' => ["magento/product-community-edition" => "0.0.1"],
+ 'version' => '0.0.1'
+ ],
'expectedMsg' => '',
'authExist' => true,
],
@@ -113,7 +188,7 @@ public function processDataProvider()
/**
* @return void
*/
- public function testExecuteWithException()
+ public function testExecuteWithException(): void
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage(
@@ -122,12 +197,17 @@ public function testExecuteWithException()
$this->directoryReadMock->expects($this->once())
->method('readFile')
->with('composer.json')
- ->willReturn('{"version": "0.0.1"}');
+ ->willReturn('{"require": {"magento/product-community-edition": "0.0.1"}, "version": "0.0.1"}');
+ $this->serializerMock->expects($this->any())
+ ->method('unserialize')
+ ->will($this->returnValue([
+ 'require' => ["magento/product-community-edition" => "0.0.1"],
+ 'version' => '0.0.1'
+ ]));
$this->filesystemMock->expects($this->once())
->method('getDirectoryRead')
->with(DirectoryList::ROOT)
->willReturn($this->directoryReadMock);
-
$this->directoryWriteMock->expects($this->once())
->method('isExist')
->with(PackagesAuth::PATH_TO_AUTH_FILE)
@@ -135,7 +215,7 @@ public function testExecuteWithException()
$this->directoryWriteMock->expects($this->once())
->method('writeFile')
->with(PackagesAuth::PATH_TO_AUTH_FILE, '{}')
- ->willThrowException(new \Exception('Something went wrong...'));
+ ->willThrowException(new Exception('Something went wrong...'));
$this->directoryWriteMock->expects($this->once())
->method('getAbsolutePath')
->with(PackagesAuth::PATH_TO_AUTH_FILE)
@@ -153,15 +233,15 @@ public function testExecuteWithException()
*/
private function createCommandTester(): CommandTester
{
- $commandTester = new CommandTester(
+ return new CommandTester(
new SampleDataDeployCommand(
$this->filesystemMock,
$this->sampleDataDependencyMock,
$this->arrayInputFactoryMock,
- $this->applicationFactoryMock
+ $this->applicationFactoryMock,
+ $this->serializerMock
)
);
- return $commandTester;
}
/**
@@ -169,10 +249,10 @@ private function createCommandTester(): CommandTester
* @param $pathToComposerJson
* @return array
*/
- protected function expectedComposerArguments(
+ protected function expectedComposerArgumentsSampleDataCommands(
array $sampleDataPackages,
string $pathToComposerJson
- ) : array {
+ ): array {
return [
'command' => 'require',
'--working-dir' => $pathToComposerJson,
diff --git a/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataRemoveCommandTest.php b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataRemoveCommandTest.php
index cbb562ff10f25..9883100ce5c49 100644
--- a/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataRemoveCommandTest.php
+++ b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataRemoveCommandTest.php
@@ -10,20 +10,32 @@
use Magento\SampleData\Console\Command\SampleDataRemoveCommand;
use Symfony\Component\Console\Tester\CommandTester;
+/**
+ * Tests for command `sampledata:remove`
+ */
class SampleDataRemoveCommandTest extends AbstractSampleDataCommandTest
{
-
/**
- * @param array $sampleDataPackages
- * @param int $appRunResult - int 0 if everything went fine, or an error code
- * @param string $expectedMsg
- * @return void
+ * @param array $sampleDataPackages
+ * @param int $appRunResult - int 0 if everything went fine, or an error code
+ * @param array $composerJsonContent
+ * @param string $expectedMsg
+ * @return void
*
* @dataProvider processDataProvider
*/
- public function testExecute(array $sampleDataPackages, $appRunResult, $expectedMsg)
- {
- $this->setupMocks($sampleDataPackages, '/path/to/composer.json', $appRunResult);
+ public function testExecute(
+ array $sampleDataPackages,
+ int $appRunResult,
+ array $composerJsonContent,
+ string $expectedMsg
+ ): void {
+ $this->setupMocks(
+ $sampleDataPackages,
+ '/path/to/composer.json',
+ $appRunResult,
+ $composerJsonContent
+ );
$commandTester = $this->createCommandTester();
$commandTester->execute([]);
@@ -31,19 +43,25 @@ public function testExecute(array $sampleDataPackages, $appRunResult, $expectedM
}
/**
- * @param array $sampleDataPackages
- * @param int $appRunResult - int 0 if everything went fine, or an error code
- * @param string $expectedMsg
- * @return void
+ * @param array $sampleDataPackages
+ * @param int $appRunResult - int 0 if everything went fine, or an error code
+ * @param array $composerJsonContent
+ * @param string $expectedMsg
+ * @return void
*
* @dataProvider processDataProvider
*/
- public function testExecuteWithNoUpdate(array $sampleDataPackages, $appRunResult, $expectedMsg)
- {
+ public function testExecuteWithNoUpdate(
+ array $sampleDataPackages,
+ int $appRunResult,
+ array $composerJsonContent,
+ string $expectedMsg
+ ): void {
$this->setupMocks(
$sampleDataPackages,
'/path/to/composer.json',
$appRunResult,
+ $composerJsonContent,
['--no-update' => 1]
);
$commandInput = ['--no-update' => 1];
@@ -55,32 +73,51 @@ public function testExecuteWithNoUpdate(array $sampleDataPackages, $appRunResult
}
/**
+ * Data provider
+ *
* @return array
*/
- public function processDataProvider()
+ public function processDataProvider(): array
{
return [
- 'No sample data found' => [
- 'sampleDataPackages' => [],
+ 'No sample data found in require' => [
+ 'sampleDataPackages' => [
+ 'magento/module-cms-sample-data' => '1.0.0-beta',
+ ],
'appRunResult' => 1,
- 'expectedMsg' => 'There is no sample data for current set of modules.' . PHP_EOL,
+ 'composerJsonContent' => [
+ "require" => [
+ "magento/product-community-edition" => "0.0.1",
+ ],
+ "version" => "0.0.1"
+ ],
+ 'expectedMsg' => 'There is an error during remove sample data.' . PHP_EOL,
],
- 'Successful sample data installation' => [
+ 'Successful sample data removing' => [
'sampleDataPackages' => [
'magento/module-cms-sample-data' => '1.0.0-beta',
],
'appRunResult' => 0,
+ 'composerJsonContent' => [
+ "require" => [
+ "magento/product-community-edition" => "0.0.1",
+ "magento/module-cms-sample-data" => "1.0.0-beta",
+ ],
+ "version" => "0.0.1"
+ ],
'expectedMsg' => '',
],
];
}
/**
+ * Creates command tester
+ *
* @return CommandTester
*/
private function createCommandTester(): CommandTester
{
- $commandTester = new CommandTester(
+ return new CommandTester(
new SampleDataRemoveCommand(
$this->filesystemMock,
$this->sampleDataDependencyMock,
@@ -88,15 +125,16 @@ private function createCommandTester(): CommandTester
$this->applicationFactoryMock
)
);
- return $commandTester;
}
/**
+ * Returns expected arguments for command `composer remove`
+ *
* @param $sampleDataPackages
* @param $pathToComposerJson
* @return array
*/
- protected function expectedComposerArguments(
+ protected function expectedComposerArgumentsSampleDataCommands(
array $sampleDataPackages,
string $pathToComposerJson
) : array {
diff --git a/app/code/Magento/Security/Test/Mftf/Test/AdminLockAdminUserWhenCreatingNewIntegrationTest.xml b/app/code/Magento/Security/Test/Mftf/Test/AdminLockAdminUserWhenCreatingNewIntegrationTest.xml
index a75f65dffeca3..83e3479c753e4 100644
--- a/app/code/Magento/Security/Test/Mftf/Test/AdminLockAdminUserWhenCreatingNewIntegrationTest.xml
+++ b/app/code/Magento/Security/Test/Mftf/Test/AdminLockAdminUserWhenCreatingNewIntegrationTest.xml
@@ -18,8 +18,6 @@
-
-
diff --git a/app/code/Magento/Security/Test/Mftf/Test/AdminLockAdminUserWhenCreatingNewRoleTest.xml b/app/code/Magento/Security/Test/Mftf/Test/AdminLockAdminUserWhenCreatingNewRoleTest.xml
index 3d04f3eed4daf..3fffbcd480761 100644
--- a/app/code/Magento/Security/Test/Mftf/Test/AdminLockAdminUserWhenCreatingNewRoleTest.xml
+++ b/app/code/Magento/Security/Test/Mftf/Test/AdminLockAdminUserWhenCreatingNewRoleTest.xml
@@ -18,8 +18,6 @@
-
-
@@ -41,7 +39,7 @@
-
+
diff --git a/app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithInvalidExpiration.xml b/app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithInvalidExpirationTest.xml
similarity index 97%
rename from app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithInvalidExpiration.xml
rename to app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithInvalidExpirationTest.xml
index 3fb798521fb45..1421b589d5669 100644
--- a/app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithInvalidExpiration.xml
+++ b/app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithInvalidExpirationTest.xml
@@ -9,7 +9,7 @@
-
+
diff --git a/app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithValidExpiration.xml b/app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithValidExpirationTest.xml
similarity index 97%
rename from app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithValidExpiration.xml
rename to app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithValidExpirationTest.xml
index 5d12650351bc0..9a9ae8f3872ba 100644
--- a/app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithValidExpiration.xml
+++ b/app/code/Magento/Security/Test/Mftf/Test/AdminLoginAdminUserWithValidExpirationTest.xml
@@ -9,7 +9,7 @@
-
+
diff --git a/app/code/Magento/Swatches/Block/LayeredNavigation/RenderLayered.php b/app/code/Magento/Swatches/Block/LayeredNavigation/RenderLayered.php
index fc13372520945..9ba1083adab74 100644
--- a/app/code/Magento/Swatches/Block/LayeredNavigation/RenderLayered.php
+++ b/app/code/Magento/Swatches/Block/LayeredNavigation/RenderLayered.php
@@ -5,11 +5,17 @@
*/
namespace Magento\Swatches\Block\LayeredNavigation;
-use Magento\Eav\Model\Entity\Attribute;
+use Magento\Catalog\Model\Layer\Filter\AbstractFilter;
+use Magento\Catalog\Model\Layer\Filter\Item as FilterItem;
use Magento\Catalog\Model\ResourceModel\Layer\Filter\AttributeFactory;
-use Magento\Framework\View\Element\Template;
+use Magento\Eav\Model\Entity\Attribute;
use Magento\Eav\Model\Entity\Attribute\Option;
-use Magento\Catalog\Model\Layer\Filter\Item as FilterItem;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\View\Element\Template;
+use Magento\Framework\View\Element\Template\Context;
+use Magento\Swatches\Helper\Data;
+use Magento\Swatches\Helper\Media;
+use Magento\Theme\Block\Html\Pager;
/**
* Class RenderLayered Render Swatches at Layered Navigation
@@ -37,7 +43,7 @@ class RenderLayered extends Template
protected $eavAttribute;
/**
- * @var \Magento\Catalog\Model\Layer\Filter\AbstractFilter
+ * @var AbstractFilter
*/
protected $filter;
@@ -47,41 +53,52 @@ class RenderLayered extends Template
protected $layerAttribute;
/**
- * @var \Magento\Swatches\Helper\Data
+ * @var Data
*/
protected $swatchHelper;
/**
- * @var \Magento\Swatches\Helper\Media
+ * @var Media
*/
protected $mediaHelper;
/**
- * @param Template\Context $context
+ * @var Pager
+ */
+ private $htmlPagerBlock;
+
+ /**
+ * @param Context $context
* @param Attribute $eavAttribute
* @param AttributeFactory $layerAttribute
- * @param \Magento\Swatches\Helper\Data $swatchHelper
- * @param \Magento\Swatches\Helper\Media $mediaHelper
+ * @param Data $swatchHelper
+ * @param Media $mediaHelper
* @param array $data
+ * @param Pager|null $htmlPagerBlock
*/
public function __construct(
- \Magento\Framework\View\Element\Template\Context $context,
+ Context $context,
Attribute $eavAttribute,
AttributeFactory $layerAttribute,
- \Magento\Swatches\Helper\Data $swatchHelper,
- \Magento\Swatches\Helper\Media $mediaHelper,
- array $data = []
+ Data $swatchHelper,
+ Media $mediaHelper,
+ array $data = [],
+ ?Pager $htmlPagerBlock = null
) {
$this->eavAttribute = $eavAttribute;
$this->layerAttribute = $layerAttribute;
$this->swatchHelper = $swatchHelper;
$this->mediaHelper = $mediaHelper;
+ $this->htmlPagerBlock = $htmlPagerBlock ?? ObjectManager::getInstance()->get(Pager::class);
parent::__construct($context, $data);
}
/**
+ * Set filter and attribute objects
+ *
* @param \Magento\Catalog\Model\Layer\Filter\AbstractFilter $filter
+ *
* @return $this
* @throws \Magento\Framework\Exception\LocalizedException
*/
@@ -94,6 +111,8 @@ public function setSwatchFilter(\Magento\Catalog\Model\Layer\Filter\AbstractFilt
}
/**
+ * Get attribute swatch data
+ *
* @return array
*/
public function getSwatchData()
@@ -114,30 +133,46 @@ public function getSwatchData()
$attributeOptionIds = array_keys($attributeOptions);
$swatches = $this->swatchHelper->getSwatchesByOptionsId($attributeOptionIds);
- $data = [
+ return [
'attribute_id' => $this->eavAttribute->getId(),
'attribute_code' => $this->eavAttribute->getAttributeCode(),
'attribute_label' => $this->eavAttribute->getStoreLabel(),
'options' => $attributeOptions,
'swatches' => $swatches,
];
-
- return $data;
}
/**
+ * Build filter option url
+ *
* @param string $attributeCode
* @param int $optionId
+ *
* @return string
*/
public function buildUrl($attributeCode, $optionId)
{
- $query = [$attributeCode => $optionId];
- return $this->_urlBuilder->getUrl('*/*/*', ['_current' => true, '_use_rewrite' => true, '_query' => $query]);
+ $query = [
+ $attributeCode => $optionId,
+ // exclude current page from urls
+ $this->htmlPagerBlock->getPageVarName() => null
+ ];
+
+ return $this->_urlBuilder->getUrl(
+ '*/*/*',
+ [
+ '_current' => true,
+ '_use_rewrite' => true,
+ '_query' => $query
+ ]
+ );
}
/**
+ * Get view data for option with no results
+ *
* @param Option $swatchOption
+ *
* @return array
*/
protected function getUnusedOption(Option $swatchOption)
@@ -150,8 +185,11 @@ protected function getUnusedOption(Option $swatchOption)
}
/**
+ * Get option data if visible
+ *
* @param FilterItem[] $filterItems
* @param Option $swatchOption
+ *
* @return array
*/
protected function getFilterOption(array $filterItems, Option $swatchOption)
@@ -166,8 +204,11 @@ protected function getFilterOption(array $filterItems, Option $swatchOption)
}
/**
+ * Get view data for option
+ *
* @param FilterItem $filterItem
* @param Option $swatchOption
+ *
* @return array
*/
protected function getOptionViewData(FilterItem $filterItem, Option $swatchOption)
@@ -187,15 +228,20 @@ protected function getOptionViewData(FilterItem $filterItem, Option $swatchOptio
}
/**
+ * Check if option should be visible
+ *
* @param FilterItem $filterItem
+ *
* @return bool
*/
protected function isOptionVisible(FilterItem $filterItem)
{
- return $this->isOptionDisabled($filterItem) && $this->isShowEmptyResults() ? false : true;
+ return !($this->isOptionDisabled($filterItem) && $this->isShowEmptyResults());
}
/**
+ * Check if attribute values should be visible with no results
+ *
* @return bool
*/
protected function isShowEmptyResults()
@@ -204,7 +250,10 @@ protected function isShowEmptyResults()
}
/**
+ * Check if option should be disabled
+ *
* @param FilterItem $filterItem
+ *
* @return bool
*/
protected function isOptionDisabled(FilterItem $filterItem)
@@ -213,8 +262,11 @@ protected function isOptionDisabled(FilterItem $filterItem)
}
/**
+ * Retrieve filter item by id
+ *
* @param FilterItem[] $filterItems
* @param integer $id
+ *
* @return bool|FilterItem
*/
protected function getFilterItemById(array $filterItems, $id)
@@ -228,14 +280,15 @@ protected function getFilterItemById(array $filterItems, $id)
}
/**
+ * Get swatch image path
+ *
* @param string $type
* @param string $filename
+ *
* @return string
*/
public function getSwatchPath($type, $filename)
{
- $imagePath = $this->mediaHelper->getSwatchAttributeImage($type, $filename);
-
- return $imagePath;
+ return $this->mediaHelper->getSwatchAttributeImage($type, $filename);
}
}
diff --git a/app/code/Magento/Swatches/Test/Mftf/ActionGroup/AddTextSwatchToProductActionGroup.xml b/app/code/Magento/Swatches/Test/Mftf/ActionGroup/AddTextSwatchToProductActionGroup.xml
index 97a391137d8e3..5f3ec07bd4983 100644
--- a/app/code/Magento/Swatches/Test/Mftf/ActionGroup/AddTextSwatchToProductActionGroup.xml
+++ b/app/code/Magento/Swatches/Test/Mftf/ActionGroup/AddTextSwatchToProductActionGroup.xml
@@ -19,6 +19,7 @@
+
@@ -41,6 +42,7 @@
+
diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontRedirectToFirstPageOnFilteringBySwatchTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontRedirectToFirstPageOnFilteringBySwatchTest.xml
new file mode 100644
index 0000000000000..c6266e034bffc
--- /dev/null
+++ b/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontRedirectToFirstPageOnFilteringBySwatchTest.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Swatches/Test/Unit/Block/LayeredNavigation/RenderLayeredTest.php b/app/code/Magento/Swatches/Test/Unit/Block/LayeredNavigation/RenderLayeredTest.php
index 4056bf27f571e..06960c409b476 100644
--- a/app/code/Magento/Swatches/Test/Unit/Block/LayeredNavigation/RenderLayeredTest.php
+++ b/app/code/Magento/Swatches/Test/Unit/Block/LayeredNavigation/RenderLayeredTest.php
@@ -18,6 +18,7 @@
use Magento\Swatches\Block\LayeredNavigation\RenderLayered;
use Magento\Swatches\Helper\Data;
use Magento\Swatches\Helper\Media;
+use Magento\Theme\Block\Html\Pager;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
@@ -28,35 +29,60 @@
*/
class RenderLayeredTest extends TestCase
{
- /** @var MockObject */
- protected $contextMock;
-
- /** @var MockObject */
- protected $requestMock;
-
- /** @var MockObject */
- protected $urlBuilder;
-
- /** @var MockObject */
- protected $eavAttributeMock;
-
- /** @var MockObject */
- protected $layerAttributeFactoryMock;
-
- /** @var MockObject */
- protected $layerAttributeMock;
-
- /** @var MockObject */
- protected $swatchHelperMock;
-
- /** @var MockObject */
- protected $mediaHelperMock;
-
- /** @var MockObject */
- protected $filterMock;
-
- /** @var MockObject */
- protected $block;
+ /**
+ * @var RenderLayered|MockObject
+ */
+ private $block;
+
+ /**
+ * @var Context|MockObject
+ */
+ private $contextMock;
+
+ /**
+ * @var RequestInterface|MockObject
+ */
+ private $requestMock;
+
+ /**
+ * @var Url|MockObject
+ */
+ private $urlBuilder;
+
+ /**
+ * @var Attribute|MockObject
+ */
+ private $eavAttributeMock;
+
+ /**
+ * @var AttributeFactory|MockObject
+ */
+ private $layerAttributeFactoryMock;
+
+ /**
+ * @var \Magento\Catalog\Model\ResourceModel\Layer\Filter\Attribute|MockObject
+ */
+ private $layerAttributeMock;
+
+ /**
+ * @var Data|MockObject
+ */
+ private $swatchHelperMock;
+
+ /**
+ * @var Media|MockObject
+ */
+ private $mediaHelperMock;
+
+ /**
+ * @var AbstractFilter|MockObject
+ */
+ private $filterMock;
+
+ /**
+ * @var Pager|MockObject
+ */
+ private $htmlBlockPagerMock;
protected function setUp(): void
{
@@ -66,8 +92,8 @@ protected function setUp(): void
Url::class,
['getCurrentUrl', 'getRedirectUrl', 'getUrl']
);
- $this->contextMock->expects($this->any())->method('getRequest')->willReturn($this->requestMock);
- $this->contextMock->expects($this->any())->method('getUrlBuilder')->willReturn($this->urlBuilder);
+ $this->contextMock->method('getRequest')->willReturn($this->requestMock);
+ $this->contextMock->method('getUrlBuilder')->willReturn($this->urlBuilder);
$this->eavAttributeMock = $this->createMock(Attribute::class);
$this->layerAttributeFactoryMock = $this->createPartialMock(
AttributeFactory::class,
@@ -80,6 +106,7 @@ protected function setUp(): void
$this->swatchHelperMock = $this->createMock(Data::class);
$this->mediaHelperMock = $this->createMock(Media::class);
$this->filterMock = $this->createMock(AbstractFilter::class);
+ $this->htmlBlockPagerMock = $this->createMock(Pager::class);
$this->block = $this->getMockBuilder(RenderLayered::class)
->setMethods(['filter', 'eavAttribute'])
@@ -91,6 +118,7 @@ protected function setUp(): void
$this->swatchHelperMock,
$this->mediaHelperMock,
[],
+ $this->htmlBlockPagerMock
]
)
->getMock();
@@ -114,7 +142,7 @@ public function testGetSwatchData()
$item3 = $this->createMock(Item::class);
$item4 = $this->createMock(Item::class);
- $item1->expects($this->any())->method('__call')->withConsecutive(
+ $item1->method('__call')->withConsecutive(
['getValue'],
['getCount'],
['getValue'],
@@ -128,9 +156,9 @@ public function testGetSwatchData()
'Yellow'
);
- $item2->expects($this->any())->method('__call')->with('getValue')->willReturn('blue');
+ $item2->method('__call')->with('getValue')->willReturn('blue');
- $item3->expects($this->any())->method('__call')->withConsecutive(
+ $item3->method('__call')->withConsecutive(
['getValue'],
['getCount']
)->willReturnOnConsecutiveCalls(
@@ -138,7 +166,7 @@ public function testGetSwatchData()
0
);
- $item4->expects($this->any())->method('__call')->withConsecutive(
+ $item4->method('__call')->withConsecutive(
['getValue'],
['getCount'],
['getValue'],
@@ -162,22 +190,22 @@ public function testGetSwatchData()
$this->block->method('filter')->willReturn($this->filterMock);
$option1 = $this->createMock(Option::class);
- $option1->expects($this->any())->method('getValue')->willReturn('yellow');
+ $option1->method('getValue')->willReturn('yellow');
$option2 = $this->createMock(Option::class);
- $option2->expects($this->any())->method('getValue')->willReturn(null);
+ $option2->method('getValue')->willReturn(null);
$option3 = $this->createMock(Option::class);
- $option3->expects($this->any())->method('getValue')->willReturn('red');
+ $option3->method('getValue')->willReturn('red');
$option4 = $this->createMock(Option::class);
- $option4->expects($this->any())->method('getValue')->willReturn('green');
+ $option4->method('getValue')->willReturn('green');
$eavAttribute = $this->createMock(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class);
$eavAttribute->expects($this->once())
->method('getOptions')
->willReturn([$option1, $option2, $option3, $option4]);
- $eavAttribute->expects($this->any())->method('getIsFilterable')->willReturn(0);
+ $eavAttribute->method('getIsFilterable')->willReturn(0);
$this->filterMock->expects($this->once())->method('getAttributeModel')->willReturn($eavAttribute);
$this->block->method('eavAttribute')->willReturn($eavAttribute);
@@ -200,7 +228,7 @@ public function testGetSwatchDataException()
{
$this->block->method('filter')->willReturn($this->filterMock);
$this->block->setSwatchFilter($this->filterMock);
- $this->expectException('\RuntimeException');
+ $this->expectException(\RuntimeException::class);
$this->block->getSwatchData();
}
diff --git a/app/code/Magento/Theme/view/base/requirejs-config.js b/app/code/Magento/Theme/view/base/requirejs-config.js
index f5580461f7d9e..423ac707c6572 100644
--- a/app/code/Magento/Theme/view/base/requirejs-config.js
+++ b/app/code/Magento/Theme/view/base/requirejs-config.js
@@ -4,8 +4,8 @@
*/
var config = {
- 'waitSeconds': 0,
- 'map': {
+ waitSeconds: 0,
+ map: {
'*': {
'ko': 'knockoutjs/knockout',
'knockout': 'knockoutjs/knockout',
@@ -13,7 +13,7 @@ var config = {
'rjsResolver': 'mage/requirejs/resolver'
}
},
- 'shim': {
+ shim: {
'jquery/jquery-migrate': ['jquery'],
'jquery/jstree/jquery.hotkeys': ['jquery'],
'jquery/hover-intent': ['jquery'],
@@ -28,7 +28,7 @@ var config = {
},
'magnifier/magnifier': ['jquery']
},
- 'paths': {
+ paths: {
'jquery/validate': 'jquery/jquery.validate',
'jquery/hover-intent': 'jquery/jquery.hoverIntent',
'jquery/file-uploader': 'jquery/fileUploader/jquery.fileupload-fp',
@@ -40,11 +40,11 @@ var config = {
'tinycolor': 'jquery/spectrum/tinycolor',
'jquery-ui-modules': 'jquery/ui-modules'
},
- 'deps': [
+ deps: [
'jquery/jquery-migrate'
],
- 'config': {
- 'mixins': {
+ config: {
+ mixins: {
'jquery/jstree/jquery.jstree': {
'mage/backend/jstree-mixin': true
},
@@ -52,7 +52,7 @@ var config = {
'jquery/patches/jquery': true
}
},
- 'text': {
+ text: {
'headers': {
'X-Requested-With': 'XMLHttpRequest'
}
@@ -60,6 +60,27 @@ var config = {
}
};
+/* eslint-disable max-depth */
+/**
+ * Adds polyfills only for browser contexts which prevents bundlers from including them.
+ */
+if (typeof window !== 'undefined' && window.document) {
+ /**
+ * Polyfill localStorage and sessionStorage for browsers that do not support them.
+ */
+ try {
+ if (!window.localStorage || !window.sessionStorage) {
+ throw new Error();
+ }
+
+ localStorage.setItem('storage_test', 1);
+ localStorage.removeItem('storage_test');
+ } catch (e) {
+ config.deps.push('mage/polyfill');
+ }
+}
+/* eslint-enable max-depth */
+
require(['jquery'], function ($) {
'use strict';
diff --git a/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml b/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml
index a4a10ef3f6ee9..96f8fbed4c041 100644
--- a/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml
+++ b/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml
@@ -10,7 +10,6 @@
-
diff --git a/app/code/Magento/Ui/view/base/requirejs-config.js b/app/code/Magento/Ui/view/base/requirejs-config.js
index 5e76600673254..4ca2c39781343 100644
--- a/app/code/Magento/Ui/view/base/requirejs-config.js
+++ b/app/code/Magento/Ui/view/base/requirejs-config.js
@@ -4,6 +4,7 @@
*/
var config = {
+ deps: [],
shim: {
'chartjs/Chart.min': ['moment'],
'tiny_mce_4/tinymce.min': {
@@ -30,3 +31,29 @@ var config = {
}
}
};
+
+/**
+ * Adds polyfills only for browser contexts which prevents bundlers from including them.
+ */
+if (typeof window !== 'undefined' && window.document) {
+ /**
+ * Polyfill Map and WeakMap for older browsers that do not support them.
+ */
+ if (typeof Map === 'undefined' || typeof WeakMap === 'undefined') {
+ config.deps.push('es6-collections');
+ }
+
+ /**
+ * Polyfill MutationObserver only for the browsers that do not support it.
+ */
+ if (typeof MutationObserver === 'undefined') {
+ config.deps.push('MutationObserver');
+ }
+
+ /**
+ * Polyfill FormData object for old browsers that don't have full support for it.
+ */
+ if (typeof FormData === 'undefined' || typeof FormData.prototype.get === 'undefined') {
+ config.deps.push('FormData');
+ }
+}
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/core/events.js b/app/code/Magento/Ui/view/base/web/js/lib/core/events.js
index fdb11cd89f361..15965fba1ad2d 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/core/events.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/core/events.js
@@ -6,8 +6,7 @@
/* global WeakMap, Map*/
define([
'ko',
- 'underscore',
- 'es6-collections'
+ 'underscore'
], function (ko, _) {
'use strict';
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/knockout/extender/bound-nodes.js b/app/code/Magento/Ui/view/base/web/js/lib/knockout/extender/bound-nodes.js
index 6b3c437b90508..0b80a75bf0c18 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/knockout/extender/bound-nodes.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/knockout/extender/bound-nodes.js
@@ -8,8 +8,7 @@ define([
'ko',
'underscore',
'mage/utils/wrapper',
- 'uiEvents',
- 'es6-collections'
+ 'uiEvents'
], function (ko, _, wrapper, Events) {
'use strict';
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/registry/registry.js b/app/code/Magento/Ui/view/base/web/js/lib/registry/registry.js
index 826e8ec8c33b4..18e05b8daac68 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/registry/registry.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/registry/registry.js
@@ -9,8 +9,7 @@
/* global WeakMap */
define([
'jquery',
- 'underscore',
- 'es6-collections'
+ 'underscore'
], function ($, _) {
'use strict';
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js
index f8e752fb77af2..cb9f5b13de494 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js
@@ -5,7 +5,6 @@
define([
'jquery',
'underscore',
- 'MutationObserver',
'domReady!'
], function ($, _) {
'use strict';
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/raf.js b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/raf.js
index 3ec0996543c7d..bc8e3095b5cd2 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/raf.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/raf.js
@@ -4,9 +4,7 @@
*/
/* global WeakMap */
-define([
- 'es6-collections'
-], function () {
+define([], function () {
'use strict';
var processMap = new WeakMap(),
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminSearchUrlRewriteByRequestPathActionGroup.xml b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminSearchUrlRewriteByRequestPathActionGroup.xml
new file mode 100644
index 0000000000000..dfdc840e0dc9f
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminSearchUrlRewriteByRequestPathActionGroup.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ EXTENDS: SearchAndSelectUrlRewrite. Removes 'clickOnRowSelectButton' and 'clickOnEditButton'.
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertAdminRequestPathInUrlRewriteGrigActionGroup.xml b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertAdminRequestPathInUrlRewriteGrigActionGroup.xml
new file mode 100644
index 0000000000000..9de6045d70c03
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertAdminRequestPathInUrlRewriteGrigActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ Assert the requested path is shown in the URL Rewrite grid.
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertAdminRequestPathIsNotFoundInUrlRewriteGrigActionGroup.xml b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertAdminRequestPathIsNotFoundInUrlRewriteGrigActionGroup.xml
new file mode 100644
index 0000000000000..8aac6ae54582a
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertAdminRequestPathIsNotFoundInUrlRewriteGrigActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ Assert the requested path is not shown in the URL Rewrite grid.
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertAdminStoreValueIsSetForUrlRewriteActionGroup.xml b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertAdminStoreValueIsSetForUrlRewriteActionGroup.xml
new file mode 100644
index 0000000000000..dea0b8d19b428
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertAdminStoreValueIsSetForUrlRewriteActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ Verifies that the proper Store Value is used for URL Rewrite.
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertStorefrontUrlRewriteSuccessOutsideRedirectActionGroup.xml b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertStorefrontUrlRewriteSuccessOutsideRedirectActionGroup.xml
new file mode 100644
index 0000000000000..757c15775dd66
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AssertStorefrontUrlRewriteSuccessOutsideRedirectActionGroup.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+ Assert redirect to proper URL on the Storefront.
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml
index 036d35d9c3258..d890cde5ecf9d 100644
--- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml
@@ -63,26 +63,25 @@
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
@@ -95,8 +94,13 @@
-
-
+
+
+
+
+
+
+
@@ -109,7 +113,12 @@
-
-
+
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesPermanentTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesPermanentTest.xml
index 9b739b157cddc..16916426167b8 100644
--- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesPermanentTest.xml
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesPermanentTest.xml
@@ -51,8 +51,11 @@
-
-
-
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTest.xml
index cce0cd11e0199..e98d1b3f526c5 100644
--- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTest.xml
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTest.xml
@@ -39,47 +39,60 @@
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestAllStoreViewTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestAllStoreViewTest.xml
index 1876b001eb5bc..de44200994873 100644
--- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestAllStoreViewTest.xml
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestAllStoreViewTest.xml
@@ -28,9 +28,13 @@
-
+
-
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestAllStoreViewWithConfigurationTurnedOffTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestAllStoreViewWithConfigurationTurnedOffTest.xml
index 14f7c9fb7cbe3..bc2005b32bae2 100644
--- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestAllStoreViewWithConfigurationTurnedOffTest.xml
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestAllStoreViewWithConfigurationTurnedOffTest.xml
@@ -28,9 +28,13 @@
-
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestWithConfigurationTurnedOffTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestWithConfigurationTurnedOffTest.xml
index 639cd2c57f7d1..885e09f775c36 100644
--- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestWithConfigurationTurnedOffTest.xml
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductInAnchorCategoriesTestWithConfigurationTurnedOffTest.xml
@@ -47,7 +47,7 @@
-
+
@@ -55,59 +55,96 @@
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductsWithConfigurationTurnedOffTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductsWithConfigurationTurnedOffTest.xml
index 1d460b9b668a0..99be6028a3908 100644
--- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductsWithConfigurationTurnedOffTest.xml
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUrlRewritesForProductInAnchorCategoriesTest/AdminUrlRewritesForProductsWithConfigurationTurnedOffTest.xml
@@ -41,17 +41,26 @@
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Test/AdminUpdateUserTest.xml b/app/code/Magento/User/Test/Mftf/Test/AdminUpdateUserTest.xml
index 501e9520c6367..0943b33e8a711 100644
--- a/app/code/Magento/User/Test/Mftf/Test/AdminUpdateUserTest.xml
+++ b/app/code/Magento/User/Test/Mftf/Test/AdminUpdateUserTest.xml
@@ -18,8 +18,9 @@
-
-
+
+
+
diff --git a/app/code/Magento/Wishlist/Model/Wishlist.php b/app/code/Magento/Wishlist/Model/Wishlist.php
index 9b7ff5177afae..cb1a7d956570b 100644
--- a/app/code/Magento/Wishlist/Model/Wishlist.php
+++ b/app/code/Magento/Wishlist/Model/Wishlist.php
@@ -181,6 +181,7 @@ class Wishlist extends AbstractModel implements IdentityInterface
* @param Json|null $serializer
* @param StockRegistryInterface|null $stockRegistry
* @param ScopeConfigInterface|null $scopeConfig
+ *
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -226,6 +227,7 @@ public function __construct(
*
* @param int $customerId
* @param bool $create Create wishlist if don't exists
+ *
* @return $this
*/
public function loadByCustomerId($customerId, $create = false)
@@ -274,6 +276,7 @@ public function generateSharingCode()
* Load by sharing code
*
* @param string $code
+ *
* @return $this
*/
public function loadByCode($code)
@@ -370,6 +373,7 @@ protected function _addCatalogProduct(Product $product, $qty = 1, $forciblySetQt
* Retrieve wishlist item collection
*
* @return \Magento\Wishlist\Model\ResourceModel\Item\Collection
+ *
* @throws NoSuchEntityException
*/
public function getItemCollection()
@@ -389,6 +393,7 @@ public function getItemCollection()
* Retrieve wishlist item collection
*
* @param int $itemId
+ *
* @return false|Item
*/
public function getItem($itemId)
@@ -403,7 +408,9 @@ public function getItem($itemId)
* Adding item to wishlist
*
* @param Item $item
+ *
* @return $this
+ *
* @throws Exception
*/
public function addItem(Item $item)
@@ -424,9 +431,12 @@ public function addItem(Item $item)
* @param int|Product $product
* @param DataObject|array|string|null $buyRequest
* @param bool $forciblySetQty
+ *
* @return Item|string
+ *
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
+ *
* @throws LocalizedException
* @throws InvalidArgumentException
*/
@@ -529,7 +539,9 @@ public function addNewItem($product, $buyRequest = null, $forciblySetQty = false
* Set customer id
*
* @param int $customerId
+ *
* @return $this
+ *
* @throws LocalizedException
*/
public function setCustomerId($customerId)
@@ -541,6 +553,7 @@ public function setCustomerId($customerId)
* Retrieve customer id
*
* @return int
+ *
* @throws LocalizedException
*/
public function getCustomerId()
@@ -552,6 +565,7 @@ public function getCustomerId()
* Retrieve data for save
*
* @return array
+ *
* @throws LocalizedException
*/
public function getDataForSave()
@@ -567,6 +581,7 @@ public function getDataForSave()
* Retrieve shared store ids for current website or all stores if $current is false
*
* @return array
+ *
* @throws NoSuchEntityException
*/
public function getSharedStoreIds()
@@ -590,6 +605,7 @@ public function getSharedStoreIds()
* Set shared store ids
*
* @param array $storeIds
+ *
* @return $this
*/
public function setSharedStoreIds($storeIds)
@@ -602,6 +618,7 @@ public function setSharedStoreIds($storeIds)
* Retrieve wishlist store object
*
* @return \Magento\Store\Model\Store
+ *
* @throws NoSuchEntityException
*/
public function getStore()
@@ -616,6 +633,7 @@ public function getStore()
* Set wishlist store
*
* @param Store $store
+ *
* @return $this
*/
public function setStore($store)
@@ -653,6 +671,7 @@ public function isSalable()
* Retrieve if product has stock or config is set for showing out of stock products
*
* @param int $productId
+ *
* @return bool
*/
private function isInStock($productId)
@@ -671,7 +690,9 @@ private function isInStock($productId)
* Check customer is owner this wishlist
*
* @param int $customerId
+ *
* @return bool
+ *
* @throws LocalizedException
*/
public function isOwner($customerId)
@@ -696,10 +717,13 @@ public function isOwner($customerId)
* @param int|Item $itemId
* @param DataObject $buyRequest
* @param null|array|DataObject $params
+ *
* @return $this
+ *
* @throws LocalizedException
*
* @see \Magento\Catalog\Helper\Product::addParamsToBuyRequest()
+ *
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
@@ -748,10 +772,11 @@ public function updateItem($itemId, $buyRequest, $params = null)
throw new LocalizedException(__($resultItem));
}
+ if ($resultItem->getDescription() != $item->getDescription()) {
+ $resultItem->setDescription($item->getDescription())->save();
+ }
+
if ($resultItem->getId() != $itemId) {
- if ($resultItem->getDescription() != $item->getDescription()) {
- $resultItem->setDescription($item->getDescription())->save();
- }
$item->isDeleted(true);
$this->setDataChanges(true);
} else {
diff --git a/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/AssertStorefrontWishListInvalidEmailsMessageActionGroup.xml b/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/AssertStorefrontWishListInvalidEmailsMessageActionGroup.xml
new file mode 100644
index 0000000000000..bdb5e702132dc
--- /dev/null
+++ b/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/AssertStorefrontWishListInvalidEmailsMessageActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontCustomerShareWishlistActionGroup.xml b/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontCustomerShareWishlistActionGroup.xml
index 1f7ac9fc85f50..57404f54a64b2 100644
--- a/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontCustomerShareWishlistActionGroup.xml
+++ b/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontCustomerShareWishlistActionGroup.xml
@@ -8,7 +8,8 @@
-
+
+
Shares the Wish List from the Storefront Wish List page. PLEASE NOTE: The details for sharing are Hardcoded using 'Wishlist'.
diff --git a/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontShareCustomerWishlistActionGroup.xml b/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontShareCustomerWishlistActionGroup.xml
new file mode 100644
index 0000000000000..6cabeeac1242f
--- /dev/null
+++ b/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontShareCustomerWishlistActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Wishlist/Test/Mftf/Data/WishlistData.xml b/app/code/Magento/Wishlist/Test/Mftf/Data/WishlistData.xml
index 4a25a8d449dd3..63b864f682455 100755
--- a/app/code/Magento/Wishlist/Test/Mftf/Data/WishlistData.xml
+++ b/app/code/Magento/Wishlist/Test/Mftf/Data/WishlistData.xml
@@ -18,4 +18,15 @@
1
10000
+
+ null
+
+
+
+ JohnDoe123456789@,JohnDoe987654321example.com,JohnDoe123456abc@@example.com
+ Sharing message.
+ 255
+ 1
+ 10000
+
diff --git a/app/code/Magento/Wishlist/Test/Mftf/Section/StorefrontCustomerWishlistShareSection.xml b/app/code/Magento/Wishlist/Test/Mftf/Section/StorefrontCustomerWishlistShareSection.xml
index 76b99ba56a327..3f16133be96a9 100644
--- a/app/code/Magento/Wishlist/Test/Mftf/Section/StorefrontCustomerWishlistShareSection.xml
+++ b/app/code/Magento/Wishlist/Test/Mftf/Section/StorefrontCustomerWishlistShareSection.xml
@@ -12,5 +12,6 @@
+
diff --git a/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistEntityTest.xml b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistEntityTest.xml
index 329978462c107..c6b6dc6886f96 100644
--- a/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistEntityTest.xml
+++ b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistEntityTest.xml
@@ -48,6 +48,12 @@
-
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistWithNotValidEmailAddressTest.xml b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistWithNotValidEmailAddressTest.xml
new file mode 100644
index 0000000000000..20881fa64f8f8
--- /dev/null
+++ b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistWithNotValidEmailAddressTest.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/composer.json b/composer.json
index d487ad5975040..25e6c6c5435bf 100644
--- a/composer.json
+++ b/composer.json
@@ -88,7 +88,7 @@
"friendsofphp/php-cs-fixer": "~2.16.0",
"lusitanian/oauth": "~0.8.10",
"magento/magento-coding-standard": "*",
- "magento/magento2-functional-testing-framework": "dev-3.0.0-RC3",
+ "magento/magento2-functional-testing-framework": "3.0.0-RC4",
"pdepend/pdepend": "~2.7.1",
"phpcompatibility/php-compatibility": "^9.3",
"phpmd/phpmd": "^2.8.0",
@@ -164,6 +164,7 @@
"magento/module-encryption-key": "*",
"magento/module-fedex": "*",
"magento/module-gift-message": "*",
+ "magento/module-gift-message-graph-ql": "*",
"magento/module-google-adwords": "*",
"magento/module-google-analytics": "*",
"magento/module-google-optimizer": "*",
@@ -214,6 +215,7 @@
"magento/module-mysql-mq": "*",
"magento/module-new-relic-reporting": "*",
"magento/module-newsletter": "*",
+ "magento/module-newsletter-graph-ql": "*",
"magento/module-offline-payments": "*",
"magento/module-offline-shipping": "*",
"magento/module-page-cache": "*",
diff --git a/composer.lock b/composer.lock
index 6a47e7e44ab69..39282cb149dc6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "e86af25d9a4a1942c437cca58f9f1efb",
+ "content-hash": "4abc523fda743ab847f07f9905bb2731",
"packages": [
{
"name": "colinmollenhour/cache-backend-file",
@@ -206,16 +206,6 @@
"ssl",
"tls"
],
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
- }
- ],
"time": "2020-04-08T08:27:21+00:00"
},
{
@@ -297,16 +287,6 @@
"dependency",
"package"
],
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
- }
- ],
"time": "2020-05-06T08:28:10+00:00"
},
{
@@ -472,12 +452,6 @@
"Xdebug",
"performance"
],
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- }
- ],
"time": "2020-03-01T12:26:26+00:00"
},
{
@@ -1331,12 +1305,6 @@
"BSD-3-Clause"
],
"description": "Replace zendframework and zfcampus packages with their Laminas Project equivalents.",
- "funding": [
- {
- "url": "https://funding.communitybridge.org/projects/laminas-project",
- "type": "community_bridge"
- }
- ],
"time": "2020-05-20T13:45:39+00:00"
},
{
@@ -2294,12 +2262,6 @@
"laminas",
"mail"
],
- "funding": [
- {
- "url": "https://funding.communitybridge.org/projects/laminas-project",
- "type": "community_bridge"
- }
- ],
"time": "2020-04-21T16:42:19+00:00"
},
{
@@ -3292,12 +3254,6 @@
"laminas",
"zf"
],
- "funding": [
- {
- "url": "https://funding.communitybridge.org/projects/laminas-project",
- "type": "community_bridge"
- }
- ],
"time": "2020-05-20T16:45:56+00:00"
},
{
@@ -3537,16 +3493,6 @@
"logging",
"psr-3"
],
- "funding": [
- {
- "url": "https://github.com/Seldaek",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
- "type": "tidelift"
- }
- ],
"time": "2020-05-22T07:31:27+00:00"
},
{
@@ -3962,20 +3908,6 @@
"x.509",
"x509"
],
- "funding": [
- {
- "url": "https://github.com/terrafrost",
- "type": "github"
- },
- {
- "url": "https://www.patreon.com/phpseclib",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
- "type": "tidelift"
- }
- ],
"time": "2020-04-04T23:17:33+00:00"
},
{
@@ -4339,16 +4271,6 @@
"parser",
"validator"
],
- "funding": [
- {
- "url": "https://github.com/Seldaek",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint",
- "type": "tidelift"
- }
- ],
"time": "2020-04-30T19:05:18+00:00"
},
{
@@ -4469,43 +4391,29 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-03-30T11:41:10+00:00"
},
{
"name": "symfony/css-selector",
- "version": "v5.0.8",
+ "version": "v5.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
- "reference": "5f8d5271303dad260692ba73dfa21777d38e124e"
+ "reference": "e544e24472d4c97b2d11ade7caacd446727c6bf9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/5f8d5271303dad260692ba73dfa21777d38e124e",
- "reference": "5f8d5271303dad260692ba73dfa21777d38e124e",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/e544e24472d4c97b2d11ade7caacd446727c6bf9",
+ "reference": "e544e24472d4c97b2d11ade7caacd446727c6bf9",
"shasum": ""
},
"require": {
- "php": "^7.2.5"
+ "php": ">=7.2.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.1-dev"
}
},
"autoload": {
@@ -4536,21 +4444,7 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2020-03-27T16:56:45+00:00"
+ "time": "2020-05-20T17:43:50+00:00"
},
{
"name": "symfony/event-dispatcher",
@@ -4620,20 +4514,6 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-03-27T16:54:36+00:00"
},
{
@@ -4696,26 +4576,26 @@
},
{
"name": "symfony/filesystem",
- "version": "v5.0.8",
+ "version": "v5.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "7cd0dafc4353a0f62e307df90b48466379c8cc91"
+ "reference": "6e4320f06d5f2cce0d96530162491f4465179157"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/7cd0dafc4353a0f62e307df90b48466379c8cc91",
- "reference": "7cd0dafc4353a0f62e307df90b48466379c8cc91",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/6e4320f06d5f2cce0d96530162491f4465179157",
+ "reference": "6e4320f06d5f2cce0d96530162491f4465179157",
"shasum": ""
},
"require": {
- "php": "^7.2.5",
+ "php": ">=7.2.5",
"symfony/polyfill-ctype": "~1.8"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.1-dev"
}
},
"autoload": {
@@ -4742,43 +4622,29 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2020-04-12T14:40:17+00:00"
+ "time": "2020-05-30T20:35:19+00:00"
},
{
"name": "symfony/finder",
- "version": "v5.0.8",
+ "version": "v5.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d"
+ "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/600a52c29afc0d1caa74acbec8d3095ca7e9910d",
- "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/4298870062bfc667cb78d2b379be4bf5dec5f187",
+ "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187",
"shasum": ""
},
"require": {
- "php": "^7.2.5"
+ "php": ">=7.2.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.1-dev"
}
},
"autoload": {
@@ -4805,21 +4671,7 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2020-03-27T16:56:45+00:00"
+ "time": "2020-05-20T17:43:50+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -4877,20 +4729,6 @@
"polyfill",
"portable"
],
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-05-12T16:14:59+00:00"
},
{
@@ -4953,20 +4791,6 @@
"portable",
"shim"
],
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-05-12T16:47:27+00:00"
},
{
@@ -5026,20 +4850,6 @@
"portable",
"shim"
],
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-05-12T16:47:27+00:00"
},
{
@@ -5095,20 +4905,6 @@
"portable",
"shim"
],
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-05-12T16:47:27+00:00"
},
{
@@ -5167,20 +4963,6 @@
"portable",
"shim"
],
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-05-12T16:47:27+00:00"
},
{
@@ -5230,20 +5012,6 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-04-15T15:56:18+00:00"
},
{
@@ -5720,16 +5488,16 @@
},
{
"name": "aws/aws-sdk-php",
- "version": "3.138.7",
+ "version": "3.140.2",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
- "reference": "6b9f3fcea4dfa6092c628c790ca6d369a75453b7"
+ "reference": "7e37960c1103ee211932be51b2282b41c948a5f0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/6b9f3fcea4dfa6092c628c790ca6d369a75453b7",
- "reference": "6b9f3fcea4dfa6092c628c790ca6d369a75453b7",
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7e37960c1103ee211932be51b2282b41c948a5f0",
+ "reference": "7e37960c1103ee211932be51b2282b41c948a5f0",
"shasum": ""
},
"require": {
@@ -5800,7 +5568,7 @@
"s3",
"sdk"
],
- "time": "2020-05-22T18:11:09+00:00"
+ "time": "2020-06-05T18:12:25+00:00"
},
{
"name": "beberlei/assert",
@@ -6018,16 +5786,16 @@
},
{
"name": "codeception/codeception",
- "version": "4.1.4",
+ "version": "4.1.5",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Codeception.git",
- "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7"
+ "reference": "24f2345329b1059f1208f65581fc632a4a6e5a55"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Codeception/Codeception/zipball/55d8d1d882fa0777e47de17b04c29b3c50fe29e7",
- "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7",
+ "url": "https://api.github.com/repos/Codeception/Codeception/zipball/24f2345329b1059f1208f65581fc632a4a6e5a55",
+ "reference": "24f2345329b1059f1208f65581fc632a4a6e5a55",
"shasum": ""
},
"require": {
@@ -6099,13 +5867,7 @@
"functional testing",
"unit testing"
],
- "funding": [
- {
- "url": "https://opencollective.com/codeception",
- "type": "open_collective"
- }
- ],
- "time": "2020-03-23T17:07:20+00:00"
+ "time": "2020-05-24T13:58:47+00:00"
},
{
"name": "codeception/lib-asserts",
@@ -6249,16 +6011,16 @@
},
{
"name": "codeception/module-webdriver",
- "version": "1.0.8",
+ "version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/Codeception/module-webdriver.git",
- "reference": "da55466876d9e73c09917f495b923395b1cdf92a"
+ "reference": "09c167817393090ce3dbce96027d94656b1963ce"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/da55466876d9e73c09917f495b923395b1cdf92a",
- "reference": "da55466876d9e73c09917f495b923395b1cdf92a",
+ "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/09c167817393090ce3dbce96027d94656b1963ce",
+ "reference": "09c167817393090ce3dbce96027d94656b1963ce",
"shasum": ""
},
"require": {
@@ -6300,7 +6062,7 @@
"browser-testing",
"codeception"
],
- "time": "2020-04-29T13:45:52+00:00"
+ "time": "2020-05-31T08:47:24+00:00"
},
{
"name": "codeception/phpunit-wrapper",
@@ -6530,22 +6292,22 @@
},
{
"name": "doctrine/annotations",
- "version": "1.10.2",
+ "version": "1.10.3",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
- "reference": "b9d758e831c70751155c698c2f7df4665314a1cb"
+ "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/annotations/zipball/b9d758e831c70751155c698c2f7df4665314a1cb",
- "reference": "b9d758e831c70751155c698c2f7df4665314a1cb",
+ "url": "https://api.github.com/repos/doctrine/annotations/zipball/5db60a4969eba0e0c197a19c077780aadbc43c5d",
+ "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"ext-tokenizer": "*",
- "php": "^7.1"
+ "php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/cache": "1.*",
@@ -6595,24 +6357,24 @@
"docblock",
"parser"
],
- "time": "2020-04-20T09:18:32+00:00"
+ "time": "2020-05-25T17:24:27+00:00"
},
{
"name": "doctrine/cache",
- "version": "1.10.0",
+ "version": "1.10.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
- "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62"
+ "reference": "35a4a70cd94e09e2259dfae7488afc6b474ecbd3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/cache/zipball/382e7f4db9a12dc6c19431743a2b096041bcdd62",
- "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62",
+ "url": "https://api.github.com/repos/doctrine/cache/zipball/35a4a70cd94e09e2259dfae7488afc6b474ecbd3",
+ "reference": "35a4a70cd94e09e2259dfae7488afc6b474ecbd3",
"shasum": ""
},
"require": {
- "php": "~7.1"
+ "php": "~7.1 || ^8.0"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
@@ -6677,7 +6439,7 @@
"redis",
"xcache"
],
- "time": "2019-11-29T15:36:20+00:00"
+ "time": "2020-05-27T16:24:54+00:00"
},
{
"name": "doctrine/inflector",
@@ -6748,20 +6510,20 @@
},
{
"name": "doctrine/instantiator",
- "version": "1.3.0",
+ "version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
- "reference": "ae466f726242e637cebdd526a7d991b9433bacf1"
+ "reference": "f350df0268e904597e3bd9c4685c53e0e333feea"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1",
- "reference": "ae466f726242e637cebdd526a7d991b9433bacf1",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea",
+ "reference": "f350df0268e904597e3bd9c4685c53e0e333feea",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
@@ -6800,24 +6562,24 @@
"constructor",
"instantiate"
],
- "time": "2019-10-21T16:45:58+00:00"
+ "time": "2020-05-29T17:27:14+00:00"
},
{
"name": "doctrine/lexer",
- "version": "1.2.0",
+ "version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
- "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6"
+ "reference": "e864bbf5904cb8f5bb334f99209b48018522f042"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6",
- "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6",
+ "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042",
+ "reference": "e864bbf5904cb8f5bb334f99209b48018522f042",
"shasum": ""
},
"require": {
- "php": "^7.2"
+ "php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
@@ -6862,7 +6624,7 @@
"parser",
"php"
],
- "time": "2019-10-30T14:39:59+00:00"
+ "time": "2020-05-25T17:44:05+00:00"
},
{
"name": "friendsofphp/php-cs-fixer",
@@ -6953,12 +6715,6 @@
}
],
"description": "A tool to automatically fix PHP code style",
- "funding": [
- {
- "url": "https://github.com/keradus",
- "type": "github"
- }
- ],
"time": "2020-04-15T18:51:10+00:00"
},
{
@@ -7217,12 +6973,6 @@
"sftp",
"storage"
],
- "funding": [
- {
- "url": "https://offset.earth/frankdejonge",
- "type": "other"
- }
- ],
"time": "2020-05-18T15:13:39+00:00"
},
{
@@ -7333,16 +7083,16 @@
},
{
"name": "magento/magento2-functional-testing-framework",
- "version": "dev-3.0.0-RC3",
+ "version": "3.0.0-RC4",
"source": {
"type": "git",
"url": "https://github.com/magento/magento2-functional-testing-framework.git",
- "reference": "aea30ae1df2fe6618478ba8813864c204561fde3"
+ "reference": "34781ccc7385993b1e5bc9182e6ddddde7f2769f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/aea30ae1df2fe6618478ba8813864c204561fde3",
- "reference": "aea30ae1df2fe6618478ba8813864c204561fde3",
+ "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/34781ccc7385993b1e5bc9182e6ddddde7f2769f",
+ "reference": "34781ccc7385993b1e5bc9182e6ddddde7f2769f",
"shasum": ""
},
"require": {
@@ -7369,7 +7119,8 @@
"symfony/finder": "^5.0",
"symfony/mime": "^5.0",
"symfony/process": "^4.4",
- "vlucas/phpdotenv": "^2.4"
+ "vlucas/phpdotenv": "^2.4",
+ "weew/helpers-array": "^1.3"
},
"replace": {
"facebook/webdriver": "^1.7.1"
@@ -7417,7 +7168,7 @@
"magento",
"testing"
],
- "time": "2020-05-22T19:17:05+00:00"
+ "time": "2020-06-08T18:17:54+00:00"
},
{
"name": "mikey179/vfsstream",
@@ -8425,20 +8176,6 @@
"MIT"
],
"description": "PHPStan - PHP Static Analysis Tool",
- "funding": [
- {
- "url": "https://github.com/ondrejmirtes",
- "type": "github"
- },
- {
- "url": "https://www.patreon.com/phpstan",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
- "type": "tidelift"
- }
- ],
"time": "2020-05-05T12:55:44+00:00"
},
{
@@ -8553,12 +8290,6 @@
"filesystem",
"iterator"
],
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
"time": "2020-04-18T05:02:12+00:00"
},
{
@@ -8707,12 +8438,6 @@
"keywords": [
"timer"
],
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
"time": "2020-04-20T06:00:37+00:00"
},
{
@@ -8762,12 +8487,6 @@
"keywords": [
"tokenizer"
],
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
"time": "2020-05-06T09:56:31+00:00"
},
{
@@ -8856,16 +8575,6 @@
"testing",
"xunit"
],
- "funding": [
- {
- "url": "https://phpunit.de/donate.html",
- "type": "custom"
- },
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
"time": "2020-05-22T13:54:05+00:00"
},
{
@@ -9006,12 +8715,6 @@
],
"description": "Collection of value objects that represent the PHP code units",
"homepage": "https://github.com/sebastianbergmann/code-unit",
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
"time": "2020-04-30T05:58:10+00:00"
},
{
@@ -9177,12 +8880,6 @@
"unidiff",
"unified diff"
],
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
"time": "2020-05-08T05:01:12+00:00"
},
{
@@ -9236,12 +8933,6 @@
"environment",
"hhvm"
],
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
"time": "2020-04-14T13:36:52+00:00"
},
{
@@ -9925,20 +9616,6 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-04-15T15:59:10+00:00"
},
{
@@ -10012,49 +9689,87 @@
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
+ "time": "2020-04-28T17:58:55+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v2.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337",
+ "reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.1-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
{
- "url": "https://github.com/fabpot",
- "type": "github"
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
},
{
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
}
],
- "time": "2020-04-28T17:58:55+00:00"
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "time": "2020-05-27T08:34:37+00:00"
},
{
"name": "symfony/http-foundation",
- "version": "v5.0.8",
+ "version": "v5.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "e47fdf8b24edc12022ba52923150ec6484d7f57d"
+ "reference": "e0d853bddc2b2cfb0d67b0b4496c03fffe1d37fa"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e47fdf8b24edc12022ba52923150ec6484d7f57d",
- "reference": "e47fdf8b24edc12022ba52923150ec6484d7f57d",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e0d853bddc2b2cfb0d67b0b4496c03fffe1d37fa",
+ "reference": "e0d853bddc2b2cfb0d67b0b4496c03fffe1d37fa",
"shasum": ""
},
"require": {
- "php": "^7.2.5",
- "symfony/mime": "^4.4|^5.0",
- "symfony/polyfill-mbstring": "~1.1"
+ "php": ">=7.2.5",
+ "symfony/deprecation-contracts": "^2.1",
+ "symfony/polyfill-mbstring": "~1.1",
+ "symfony/polyfill-php80": "^1.15"
},
"require-dev": {
"predis/predis": "~1.0",
- "symfony/expression-language": "^4.4|^5.0"
+ "symfony/cache": "^4.4|^5.0",
+ "symfony/expression-language": "^4.4|^5.0",
+ "symfony/mime": "^4.4|^5.0"
+ },
+ "suggest": {
+ "symfony/mime": "To use the file extension guesser"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.1-dev"
}
},
"autoload": {
@@ -10081,40 +9796,27 @@
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2020-04-18T20:50:06+00:00"
+ "time": "2020-05-24T12:18:07+00:00"
},
{
"name": "symfony/mime",
- "version": "v5.0.8",
+ "version": "v5.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
- "reference": "5d6c81c39225a750f3f43bee15f03093fb9aaa0b"
+ "reference": "56261f89385f9d13cf843a5101ac72131190bc91"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mime/zipball/5d6c81c39225a750f3f43bee15f03093fb9aaa0b",
- "reference": "5d6c81c39225a750f3f43bee15f03093fb9aaa0b",
+ "url": "https://api.github.com/repos/symfony/mime/zipball/56261f89385f9d13cf843a5101ac72131190bc91",
+ "reference": "56261f89385f9d13cf843a5101ac72131190bc91",
"shasum": ""
},
"require": {
- "php": "^7.2.5",
+ "php": ">=7.2.5",
"symfony/polyfill-intl-idn": "^1.10",
- "symfony/polyfill-mbstring": "^1.0"
+ "symfony/polyfill-mbstring": "^1.0",
+ "symfony/polyfill-php80": "^1.15"
},
"conflict": {
"symfony/mailer": "<4.4"
@@ -10126,7 +9828,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.1-dev"
}
},
"autoload": {
@@ -10157,21 +9859,7 @@
"mime",
"mime-type"
],
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2020-04-17T03:29:44+00:00"
+ "time": "2020-05-25T12:33:44+00:00"
},
{
"name": "symfony/options-resolver",
@@ -10225,20 +9913,6 @@
"configuration",
"options"
],
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-04-06T10:40:56+00:00"
},
{
@@ -10298,20 +9972,68 @@
"portable",
"shim"
],
- "funding": [
+ "time": "2020-05-12T16:47:27+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "v1.17.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "5e30b2799bc1ad68f7feb62b60a73743589438dd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/5e30b2799bc1ad68f7feb62b60a73743589438dd",
+ "reference": "5e30b2799bc1ad68f7feb62b60a73743589438dd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.17-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
{
- "url": "https://symfony.com/sponsor",
- "type": "custom"
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
},
{
- "url": "https://github.com/fabpot",
- "type": "github"
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
},
{
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
}
],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
"time": "2020-05-12T16:47:27+00:00"
},
{
@@ -10362,38 +10084,25 @@
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
"time": "2020-03-27T16:56:45+00:00"
},
{
"name": "symfony/yaml",
- "version": "v5.0.8",
+ "version": "v5.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "482fb4e710e5af3e0e78015f19aa716ad953392f"
+ "reference": "ea342353a3ef4f453809acc4ebc55382231d4d23"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/482fb4e710e5af3e0e78015f19aa716ad953392f",
- "reference": "482fb4e710e5af3e0e78015f19aa716ad953392f",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/ea342353a3ef4f453809acc4ebc55382231d4d23",
+ "reference": "ea342353a3ef4f453809acc4ebc55382231d4d23",
"shasum": ""
},
"require": {
- "php": "^7.2.5",
+ "php": ">=7.2.5",
+ "symfony/deprecation-contracts": "^2.1",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
@@ -10405,10 +10114,13 @@
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
+ "bin": [
+ "Resources/bin/yaml-lint"
+ ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.1-dev"
}
},
"autoload": {
@@ -10435,21 +10147,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2020-04-28T17:58:55+00:00"
+ "time": "2020-05-20T17:43:50+00:00"
},
{
"name": "thecodingmachine/safe",
@@ -10724,16 +10422,6 @@
"env",
"environment"
],
- "funding": [
- {
- "url": "https://github.com/GrahamCampbell",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
- "type": "tidelift"
- }
- ],
"time": "2020-05-02T13:38:00+00:00"
},
{
@@ -10826,7 +10514,7 @@
"minimum-stability": "stable",
"stability-flags": {
"magento/composer": 20,
- "magento/magento2-functional-testing-framework": 20
+ "magento/magento2-functional-testing-framework": 5
},
"prefer-stable": true,
"prefer-lowest": false,
@@ -10849,6 +10537,5 @@
"ext-zip": "*",
"lib-libxml": "*"
},
- "platform-dev": [],
- "plugin-api-version": "1.1.0"
+ "platform-dev": []
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php
index 6e90e85782bb2..c42450d86fd58 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php
@@ -7,8 +7,9 @@
namespace Magento\GraphQl\Customer;
+use Exception;
use Magento\Customer\Model\CustomerAuthUpdate;
-use Magento\Customer\Model\CustomerRegistry;
+use Magento\Framework\Exception\AuthenticationException;
use Magento\Integration\Api\CustomerTokenServiceInterface;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
@@ -113,7 +114,7 @@ public function testUpdateCustomer()
*/
public function testUpdateCustomerIfInputDataIsEmpty()
{
- $this->expectException(\Exception::class);
+ $this->expectException(Exception::class);
$this->expectExceptionMessage('"input" value should be specified');
$currentEmail = 'customer@example.com';
@@ -139,7 +140,7 @@ public function testUpdateCustomerIfInputDataIsEmpty()
*/
public function testUpdateCustomerIfUserIsNotAuthorized()
{
- $this->expectException(\Exception::class);
+ $this->expectException(Exception::class);
$this->expectExceptionMessage('The current customer isn\'t authorized.');
$newFirstname = 'Richard';
@@ -165,7 +166,7 @@ public function testUpdateCustomerIfUserIsNotAuthorized()
*/
public function testUpdateCustomerIfAccountIsLocked()
{
- $this->expectException(\Exception::class);
+ $this->expectException(Exception::class);
$this->expectExceptionMessage('The account is locked.');
$this->lockCustomer->execute(1);
@@ -195,7 +196,7 @@ public function testUpdateCustomerIfAccountIsLocked()
*/
public function testUpdateEmailIfPasswordIsMissed()
{
- $this->expectException(\Exception::class);
+ $this->expectException(Exception::class);
$this->expectExceptionMessage('Provide the current "password" to change "email".');
$currentEmail = 'customer@example.com';
@@ -223,7 +224,7 @@ public function testUpdateEmailIfPasswordIsMissed()
*/
public function testUpdateEmailIfPasswordIsInvalid()
{
- $this->expectException(\Exception::class);
+ $this->expectException(Exception::class);
$this->expectExceptionMessage('Invalid login or password.');
$currentEmail = 'customer@example.com';
@@ -253,8 +254,10 @@ public function testUpdateEmailIfPasswordIsInvalid()
*/
public function testUpdateEmailIfEmailAlreadyExists()
{
- $this->expectException(\Exception::class);
- $this->expectExceptionMessage('A customer with the same email address already exists in an associated website.');
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage(
+ 'A customer with the same email address already exists in an associated website.'
+ );
$currentEmail = 'customer@example.com';
$currentPassword = 'password';
@@ -281,12 +284,42 @@ public function testUpdateEmailIfEmailAlreadyExists()
$this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
}
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testUpdateEmailIfEmailIsInvalid()
+ {
+ $currentEmail = 'customer@example.com';
+ $currentPassword = 'password';
+ $invalidEmail = 'customer.example.com';
+
+ $query = <<expectException(Exception::class);
+ $this->expectExceptionMessage('"' . $invalidEmail . '" is not a valid email address.');
+
+ $this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ }
+
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
*/
public function testEmptyCustomerName()
{
- $this->expectException(\Exception::class);
+ $this->expectException(Exception::class);
$this->expectExceptionMessage('Required parameters are missing: First Name');
$currentEmail = 'customer@example.com';
@@ -310,10 +343,63 @@ public function testEmptyCustomerName()
$this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
}
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testEmptyCustomerLastName()
+ {
+ $query = <<expectException(Exception::class);
+ $this->expectExceptionMessage('Required parameters are missing: Last Name');
+
+ $this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders('customer@example.com', 'password'));
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testUpdateCustomerIfDobIsInvalid()
+ {
+ $invalidDob = 'bla-bla-bla';
+
+ $query = <<expectException(Exception::class);
+ $this->expectExceptionMessage('Invalid date');
+
+ $this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders('customer@example.com', 'password'));
+ }
+
/**
* @param string $email
* @param string $password
* @return array
+ * @throws AuthenticationException
*/
private function getCustomerAuthHeaders(string $email, string $password): array
{
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/GiftMessage/Cart/GiftMessageTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/GiftMessage/Cart/GiftMessageTest.php
new file mode 100644
index 0000000000000..8eaac6d46aa02
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/GiftMessage/Cart/GiftMessageTest.php
@@ -0,0 +1,96 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoConfigFixture default_store sales/gift_options/allow_order 1
+ * @magentoApiDataFixture Magento/GiftMessage/_files/quote_with_message.php
+ * @throws NoSuchEntityException
+ * @throws Exception
+ */
+ public function testGiftMessageForCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('message_order_21');
+ $response = $this->requestCartAndAssertResult($maskedQuoteId);
+ self::assertArrayHasKey('gift_message', $response['cart']);
+ self::assertSame('Mercutio', $response['cart']['gift_message']['to']);
+ self::assertSame('Romeo', $response['cart']['gift_message']['from']);
+ self::assertSame('I thought all for the best.', $response['cart']['gift_message']['message']);
+ }
+
+ /**
+ * @magentoConfigFixture default_store sales/gift_options/allow_order 0
+ * @magentoApiDataFixture Magento/GiftMessage/_files/quote_with_message.php
+ * @throws NoSuchEntityException
+ * @throws Exception
+ */
+ public function testGiftMessageForCartWithNotAllow()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('message_order_21');
+ $response = $this->requestCartAndAssertResult($maskedQuoteId);
+ self::assertArrayHasKey('gift_message', $response['cart']);
+ self::assertNull($response['cart']['gift_message']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @throws NoSuchEntityException
+ * @throws Exception
+ */
+ public function testGiftMessageForCartWithoutMessage()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $response = $this->requestCartAndAssertResult($maskedQuoteId);
+ self::assertArrayHasKey('gift_message', $response['cart']);
+ self::assertNull($response['cart']['gift_message']);
+ }
+
+ /**
+ * Get Gift Message Assertion
+ *
+ * @param string $quoteId
+ *
+ * @return array
+ * @throws Exception
+ */
+ private function requestCartAndAssertResult(string $quoteId)
+ {
+ $query = <<graphQlQuery($query);
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/GiftMessage/Order/GiftMessageTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/GiftMessage/Order/GiftMessageTest.php
new file mode 100644
index 0000000000000..538456884df58
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/GiftMessage/Order/GiftMessageTest.php
@@ -0,0 +1,101 @@
+customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class);
+ }
+
+ /**
+ * @magentoConfigFixture default_store sales/gift_options/allow_order 1
+ * @magentoConfigFixture default_store sales/gift_options/allow_items 1
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GiftMessage/_files/customer/order_with_message.php
+ * @throws AuthenticationException
+ * @throws Exception
+ */
+ public function testGiftMessageForOrder()
+ {
+ $query = $this->getCustomerOrdersQuery();
+ $currentEmail = 'customer@example.com';
+ $currentPassword = 'password';
+ $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ foreach ($response['customerOrders']['items'] as $order) {
+ self::assertArrayHasKey('gift_message', $order);
+ self::assertArrayHasKey('to', $order['gift_message']);
+ self::assertArrayHasKey('from', $order['gift_message']);
+ self::assertArrayHasKey('message', $order['gift_message']);
+ }
+ }
+
+ /**
+ * @magentoConfigFixture default_store sales/gift_options/allow_order 0
+ * @magentoConfigFixture default_store sales/gift_options/allow_items 0
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GiftMessage/_files/customer/order_with_message.php
+ */
+ public function testGiftMessageNotAllowForOrder()
+ {
+ $query = $this->getCustomerOrdersQuery();
+ $currentEmail = 'customer@example.com';
+ $currentPassword = 'password';
+ $this->expectException(\Exception::class);
+ $this->expectExceptionMessage('Can\'t load gift message for order');
+ $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ }
+
+ /**
+ * @param string $email
+ * @param string $password
+ * @return array
+ * @throws AuthenticationException
+ */
+ private function getCustomerAuthHeaders(string $email, string $password): array
+ {
+ $customerToken = $this->customerTokenService->createCustomerAccessToken($email, $password);
+ return ['Authorization' => 'Bearer ' . $customerToken];
+ }
+
+ /**
+ * Get Customer Orders query
+ *
+ * @return string
+ */
+ private function getCustomerOrdersQuery()
+ {
+ return <<customerAuthUpdate = Bootstrap::getObjectManager()->get(CustomerAuthUpdate::class);
+ $this->customerRegistry = Bootstrap::getObjectManager()->get(CustomerRegistry::class);
+ $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ $this->subscriberResource = $objectManager->get(SubscriberResourceModel::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testAddRegisteredCustomerEmailIntoNewsletterSubscription()
+ {
+ $query = $this->getQuery('customer@example.com');
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('subscribeEmailToNewsletter', $response);
+ self::assertNotEmpty($response['subscribeEmailToNewsletter']);
+ self::assertEquals('SUBSCRIBED', $response['subscribeEmailToNewsletter']['status']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testAddLockedCustomerEmailIntoNewsletterSubscription()
+ {
+ /* lock customer */
+ $customerSecure = $this->customerRegistry->retrieveSecureData(1);
+ $customerSecure->setLockExpires('2030-12-31 00:00:00');
+ $this->customerAuthUpdate->saveAuth(1);
+
+ $query = $this->getQuery('customer@example.com');
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('subscribeEmailToNewsletter', $response);
+ self::assertNotEmpty($response['subscribeEmailToNewsletter']);
+ self::assertEquals('SUBSCRIBED', $response['subscribeEmailToNewsletter']['status']);
+ }
+
+ /**
+ * @magentoConfigFixture default_store newsletter/subscription/confirm 1
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testSubscribeRegisteredCustomerEmailWithEnabledConfirmation()
+ {
+ $query = $this->getQuery('customer@example.com');
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('subscribeEmailToNewsletter', $response);
+ self::assertNotEmpty($response['subscribeEmailToNewsletter']);
+ self::assertEquals('NOT_ACTIVE', $response['subscribeEmailToNewsletter']['status']);
+ }
+
+ /**
+ * @magentoConfigFixture default_store customer/create_account/confirm 1
+ * @magentoApiDataFixture Magento/Customer/_files/unconfirmed_customer.php
+ * @expectedException Exception
+ * @expectedExceptionMessage The account sign-in was incorrect or your account is disabled temporarily.
+ * Please wait and try again later
+ */
+ public function testNewsletterSubscriptionWithUnconfirmedCustomer()
+ {
+ $headers = $this->getHeaderMap('unconfirmedcustomer@example.com', 'Qwert12345');
+ $query = $this->getQuery('unconfirmedcustomer@example.com');
+
+ $this->graphQlMutation($query, [], '', $headers);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testNewsletterSubscriptionWithIncorrectEmailFormat()
+ {
+ $query = $this->getQuery('customer.example.com');
+
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Enter a valid email address.' . "\n");
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Newsletter/_files/subscribers.php
+ */
+ public function testNewsletterSubscriptionWithAlreadySubscribedEmail()
+ {
+ $query = $this->getQuery('customer@example.com');
+
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('This email address is already subscribed.' . "\n");
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Newsletter/_files/three_subscribers.php
+ */
+ public function testNewsletterSubscriptionWithAnotherCustomerEmail()
+ {
+ $query = $this->getQuery('customer2@search.example.com');
+
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Cannot create a newsletter subscription.' . "\n");
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer@search.example.com'));
+ }
+
+ /**
+ * Returns a mutation query
+ *
+ * @param string $email
+ * @return string
+ */
+ private function getQuery(string $email = ''): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($username, $password);
+
+ return [
+ 'Authorization' => 'Bearer ' . $customerToken
+ ];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function tearDown(): void
+ {
+ $this->subscriberResource
+ ->getConnection()
+ ->delete(
+ $this->subscriberResource->getMainTable()
+ );
+
+ parent::tearDown();
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Newsletter/Guest/SubscribeEmailToNewsletterTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Newsletter/Guest/SubscribeEmailToNewsletterTest.php
new file mode 100644
index 0000000000000..f0a933609c762
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Newsletter/Guest/SubscribeEmailToNewsletterTest.php
@@ -0,0 +1,114 @@
+subscriberResource = $objectManager->get(SubscriberResourceModel::class);
+ }
+
+ public function testAddEmailIntoNewsletterSubscription()
+ {
+ $query = $this->getQuery('guest@example.com');
+ $response = $this->graphQlMutation($query);
+
+ self::assertArrayHasKey('subscribeEmailToNewsletter', $response);
+ self::assertNotEmpty($response['subscribeEmailToNewsletter']);
+ self::assertEquals('SUBSCRIBED', $response['subscribeEmailToNewsletter']['status']);
+ }
+
+ public function testNewsletterSubscriptionWithIncorrectEmailFormat()
+ {
+ $query = $this->getQuery('guest.example.com');
+
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Enter a valid email address.' . "\n");
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoConfigFixture default_store newsletter/subscription/allow_guest_subscribe 0
+ */
+ public function testNewsletterSubscriptionWithDisallowedGuestSubscription()
+ {
+ $query = $this->getQuery('guest@example.com');
+
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage(
+ 'Guests can not subscribe to the newsletter. You must create an account to subscribe.' . "\n"
+ );
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Newsletter/_files/guest_subscriber.php
+ */
+ public function testNewsletterSubscriptionWithAlreadySubscribedEmail()
+ {
+ $query = $this->getQuery('guest@example.com');
+
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('This email address is already subscribed.' . "\n");
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * Returns a mutation query
+ *
+ * @param string $email
+ * @return string
+ */
+ private function getQuery(string $email = ''): string
+ {
+ return <<subscriberResource
+ ->getConnection()
+ ->delete(
+ $this->subscriberResource->getMainTable()
+ );
+
+ parent::tearDown();
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php
index 337068710c31b..040215a241c47 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php
@@ -122,7 +122,9 @@ public function testSendFriendDisableAsCustomer()
public function testSendWithoutExistProduct()
{
$this->expectException(\Exception::class);
- $this->expectExceptionMessage('The product that was requested doesn\'t exist. Verify the product and try again.');
+ $this->expectExceptionMessage(
+ 'The product that was requested doesn\'t exist. Verify the product and try again.'
+ );
$productId = 2018;
$recipients = '{
@@ -290,81 +292,124 @@ public function testSendProductWithoutVisibility()
/**
* @return array
*/
- public function sendFriendsErrorsDataProvider()
+ public function sendFriendsErrorsDataProvider(): array
+ {
+ return array_merge(
+ $this->getRecipientErrors(),
+ $this->getSenderErrors()
+ );
+ }
+
+ /**
+ * @return array
+ */
+ private function getRecipientErrors(): array
{
return [
[
- 'product_id: 1
- sender: {
- name: "Name"
- email: "e@mail.com"
- message: "Lorem Ipsum"
- }
- recipients: [
- {
- name: ""
- email:"recipient1@mail.com"
- },
- {
- name: ""
- email:"recipient2@mail.com"
- }
- ]', 'Please provide Name for all of recipients.'
+ 'product_id: 1
+ sender: {
+ name: "Name"
+ email: "e@mail.com"
+ message: "Lorem Ipsum"
+ }
+ recipients: [
+ {
+ name: ""
+ email:"recipient1@mail.com"
+ },
+ {
+ name: ""
+ email:"recipient2@mail.com"
+ }
+ ]',
+ 'Please provide Name for all of recipients.'
],
[
'product_id: 1
- sender: {
- name: "Name"
- email: "e@mail.com"
- message: "Lorem Ipsum"
- }
- recipients: [
- {
- name: "Recipient Name 1"
- email:""
- },
- {
- name: "Recipient Name 2"
- email:""
- }
- ]', 'Please provide Email for all of recipients.'
+ sender: {
+ name: "Name"
+ email: "e@mail.com"
+ message: "Lorem Ipsum"
+ }
+ recipients: [
+ {
+ name: "Recipient Name 1"
+ email:""
+ },
+ {
+ name: "Recipient Name 2"
+ email:""
+ }
+ ]',
+ 'Please provide Email for all of recipients.'
+ ],
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ private function getSenderErrors(): array
+ {
+ return [
+ [
+ 'product_id: 1
+ sender: {
+ name: ""
+ email: "e@mail.com"
+ message: "Lorem Ipsum"
+ }
+ recipients: [
+ {
+ name: "Recipient Name 1"
+ email:"recipient1@mail.com"
+ },
+ {
+ name: "Recipient Name 2"
+ email:"recipient2@mail.com"
+ }
+ ]',
+ 'Please provide Name of sender.'
],
[
'product_id: 1
- sender: {
- name: ""
- email: "e@mail.com"
- message: "Lorem Ipsum"
- }
- recipients: [
- {
- name: "Recipient Name 1"
- email:"recipient1@mail.com"
- },
- {
- name: "Recipient Name 2"
- email:"recipient2@mail.com"
- }
- ]', 'Please provide Name of sender.'
+ sender: {
+ name: "Name"
+ email: ""
+ message: "Lorem Ipsum"
+ }
+ recipients: [
+ {
+ name: "Recipient Name 1"
+ email:"recipient1@mail.com"
+ },
+ {
+ name: "Recipient Name 2"
+ email:"recipient2@mail.com"
+ }
+ ]',
+ 'Please provide Email of sender.'
],
[
'product_id: 1
- sender: {
- name: "Name"
- email: "e@mail.com"
- message: ""
- }
- recipients: [
- {
- name: "Recipient Name 1"
- email:"recipient1@mail.com"
- },
- {
- name: "Recipient Name 2"
- email:"recipient2@mail.com"
- }
- ]', 'Please provide Message.'
- ]
+ sender: {
+ name: "Name"
+ email: "e@mail.com"
+ message: ""
+ }
+ recipients: [
+ {
+ name: "Recipient Name 1"
+ email:"recipient1@mail.com"
+ },
+ {
+ name: "Recipient Name 2"
+ email:"recipient2@mail.com"
+ }
+ ]',
+ 'Please provide Message.'
+ ],
];
}
diff --git a/dev/tests/integration/testsuite/Magento/AdminNotification/_files/notifications.php b/dev/tests/integration/testsuite/Magento/AdminNotification/_files/notifications.php
index 6615c24320b21..0a8f2670b5740 100644
--- a/dev/tests/integration/testsuite/Magento/AdminNotification/_files/notifications.php
+++ b/dev/tests/integration/testsuite/Magento/AdminNotification/_files/notifications.php
@@ -3,52 +3,48 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-$om = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-$message = $om->create(\Magento\AdminNotification\Model\Inbox::class);
-$message->setSeverity(
- \Magento\Framework\Notification\MessageInterface::SEVERITY_CRITICAL
-)->setTitle(
- 'Unread Critical 1'
-)->save();
-
-$message = $om->create(\Magento\AdminNotification\Model\Inbox::class);
-$message->setSeverity(\Magento\Framework\Notification\MessageInterface::SEVERITY_MAJOR)
- ->setTitle('Unread Major 1')
- ->save();
-
-$message = $om->create(\Magento\AdminNotification\Model\Inbox::class);
-$message->setSeverity(
- \Magento\Framework\Notification\MessageInterface::SEVERITY_CRITICAL
-)->setTitle(
- 'Unread Critical 2'
-)->save();
-
-$message = $om->create(\Magento\AdminNotification\Model\Inbox::class);
-$message->setSeverity(
- \Magento\Framework\Notification\MessageInterface::SEVERITY_CRITICAL
-)->setTitle(
- 'Unread Critical 3'
-)->save();
-
-$message = $om->create(\Magento\AdminNotification\Model\Inbox::class);
-$message->setSeverity(
- \Magento\Framework\Notification\MessageInterface::SEVERITY_CRITICAL
-)->setTitle(
- 'Read Critical 1'
-)->setIsRead(
- 1
-)->save();
-
-$message = $om->create(\Magento\AdminNotification\Model\Inbox::class);
-$message->setSeverity(\Magento\Framework\Notification\MessageInterface::SEVERITY_MAJOR)
- ->setTitle('Unread Major 2')
- ->save();
-
-$message = $om->create(\Magento\AdminNotification\Model\Inbox::class);
-$message->setSeverity(
- \Magento\Framework\Notification\MessageInterface::SEVERITY_CRITICAL
-)->setTitle(
- 'Removed Critical 1'
-)->setIsRemove(
- 1
-)->save();
+
+declare(strict_types=1);
+
+use Magento\AdminNotification\Model\Inbox;
+use Magento\AdminNotification\Model\ResourceModel\Inbox as InboxResource;
+use Magento\Framework\Notification\MessageInterface;
+use Magento\Framework\ObjectManagerInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+
+/** @var ObjectManagerInterface $objectManager */
+$objectManager = Bootstrap::getObjectManager();
+
+/**
+ * @var Inbox $message
+ * @var InboxResource $messageResource
+ */
+$message = $objectManager->create(Inbox::class);
+$messageResource = $objectManager->create(InboxResource::class);
+
+$message->setSeverity(MessageInterface::SEVERITY_CRITICAL)->setTitle('Unread Critical 1');
+$messageResource->save($message);
+
+$message = $objectManager->create(Inbox::class);
+$message->setSeverity(MessageInterface::SEVERITY_MAJOR)->setTitle('Unread Major 1');
+$messageResource->save($message);
+
+$message = $objectManager->create(Inbox::class);
+$message->setSeverity(MessageInterface::SEVERITY_CRITICAL)->setTitle('Unread Critical 2');
+$messageResource->save($message);
+
+$message = $objectManager->create(Inbox::class);
+$message->setSeverity(MessageInterface::SEVERITY_CRITICAL)->setTitle('Unread Critical 3');
+$messageResource->save($message);
+
+$message = $objectManager->create(Inbox::class);
+$message->setSeverity(MessageInterface::SEVERITY_CRITICAL)->setTitle('Read Critical 1')->setIsRead(1);
+$messageResource->save($message);
+
+$message = $objectManager->create(Inbox::class);
+$message->setSeverity(MessageInterface::SEVERITY_MAJOR)->setTitle('Unread Major 2');
+$messageResource->save($message);
+
+$message = $objectManager->create(Inbox::class);
+$message->setSeverity(MessageInterface::SEVERITY_CRITICAL)->setTitle('Removed Critical 1')->setIsRemove(1);
+$messageResource->save($message);
diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php
index ef5877612a3b9..2ae807f0a401b 100644
--- a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php
+++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php
@@ -4,26 +4,50 @@
* See COPYING.txt for license details.
*/
-$productModel = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
- ->create(\Magento\Catalog\Model\Product::class);
+declare(strict_types=1);
-$productModel->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Catalog\Model\Product\Type;
+use Magento\Catalog\Model\Product\Visibility;
+use Magento\Framework\ObjectManagerInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+
+/** @var ObjectManagerInterface $objectManager */
+$objectManager = Bootstrap::getObjectManager();
+
+/**
+ * @var Product $productModel
+ * @var ProductRepositoryInterface $productRepository
+ */
+$productModel = $objectManager->create(Product::class);
+$productRepository = $objectManager->create(ProductRepositoryInterface::class);
+
+$productModel->setTypeId(Type::TYPE_SIMPLE)
->setAttributeSetId(4)
->setName('AdvancedPricingSimple 1')
->setSku('AdvancedPricingSimple 1')
->setPrice(321)
- ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
- ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+ ->setVisibility(Visibility::VISIBILITY_BOTH)
+ ->setStatus(Status::STATUS_ENABLED)
->setWebsiteIds([1])
->setCategoryIds([])
->setStockData(['qty' => 100, 'is_in_stock' => 1, 'manage_stock' => 1])
- ->setIsObjectNew(true)
- ->save();
+ ->setIsObjectNew(true);
-$productModel->setName('AdvancedPricingSimple 2')
- ->setId(null)
- ->setUrlKey(null)
+$productRepository->save($productModel);
+
+$productModel = $objectManager->create(Product::class);
+$productModel->setTypeId(Type::TYPE_SIMPLE)
+ ->setAttributeSetId(4)
+ ->setName('AdvancedPricingSimple 2')
->setSku('AdvancedPricingSimple 2')
->setPrice(654)
- ->setIsObjectNew(true)
- ->save();
+ ->setVisibility(Visibility::VISIBILITY_BOTH)
+ ->setStatus(Status::STATUS_ENABLED)
+ ->setWebsiteIds([1])
+ ->setCategoryIds([])
+ ->setStockData(['qty' => 100, 'is_in_stock' => 1, 'manage_stock' => 1])
+ ->setIsObjectNew(true);
+$productRepository->save($productModel);
diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/product_with_second_website.php b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/product_with_second_website.php
index 47456de5ab07e..17b6a700e0c07 100644
--- a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/product_with_second_website.php
+++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/product_with_second_website.php
@@ -4,7 +4,12 @@
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
+use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Customer\Model\Group;
+use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
use Magento\Store\Api\WebsiteRepositoryInterface;
@@ -13,15 +18,16 @@
Resolver::getInstance()->requireDataFixture('Magento/AdvancedPricingImportExport/_files/create_products.php');
$objectManager = Bootstrap::getObjectManager();
-/** @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository */
-$attributeRepository = $objectManager
- ->get(Magento\Catalog\Api\ProductAttributeRepositoryInterface::class);
-$groupPriceAttribute = $attributeRepository->get('tier_price')
- ->setScope(Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE);
+
+/** @var ProductAttributeRepositoryInterface $attributeRepository */
+$attributeRepository = $objectManager->get(ProductAttributeRepositoryInterface::class);
+$groupPriceAttribute = $attributeRepository->get('tier_price')->setScope(ScopedAttributeInterface::SCOPE_WEBSITE);
$attributeRepository->save($groupPriceAttribute);
+
/** @var WebsiteRepositoryInterface $websiteRepository */
$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class);
$website = $websiteRepository->get('test');
+
/** @var ProductRepositoryInterface $productRepository */
$productRepository = $objectManager->create(ProductRepositoryInterface::class);
$productModel = $productRepository->get('AdvancedPricingSimple 2');
@@ -30,10 +36,10 @@
[
[
'website_id' => $website->getId(),
- 'cust_group' => \Magento\Customer\Model\Group::CUST_GROUP_ALL,
+ 'cust_group' => Group::CUST_GROUP_ALL,
'price_qty' => 3,
'price' => 5
]
]
);
-$productModel->save();
+$productRepository->save($productModel);
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Product/CompareTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Product/CompareTest.php
index 460488fdfae76..4f046eccbe59f 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Product/CompareTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Product/CompareTest.php
@@ -412,7 +412,7 @@ protected function _assertCompareListEquals(array $expectedProductIds)
$compareItems = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
\Magento\Catalog\Model\ResourceModel\Product\Compare\Item\Collection::class
);
- $compareItems->useProductItem(true);
+ $compareItems->useProductItem();
// important
$compareItems->setVisitorId(
\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_boolean_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_boolean_attribute.php
index 34dccc2284445..57b918fb5e663 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_boolean_attribute.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_boolean_attribute.php
@@ -9,6 +9,7 @@
use Magento\Eav\Api\AttributeRepositoryInterface;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
use Magento\Eav\Model\Entity\Attribute\Source\Boolean;
+use Magento\Framework\Exception\NoSuchEntityException;
use Magento\TestFramework\Helper\Bootstrap;
$objectManager = Bootstrap::getObjectManager();
@@ -19,32 +20,36 @@
/** @var $installer CategorySetup */
$installer = $objectManager->create(CategorySetup::class);
-$attribute->setData(
- [
- 'attribute_code' => 'boolean_attribute',
- 'entity_type_id' => CategorySetup::CATALOG_PRODUCT_ENTITY_TYPE_ID,
- 'is_global' => 0,
- 'is_user_defined' => 1,
- 'frontend_input' => 'boolean',
- 'is_unique' => 0,
- 'is_required' => 0,
- 'is_searchable' => 1,
- 'is_visible_in_advanced_search' => 1,
- 'is_comparable' => 0,
- 'is_filterable' => 1,
- 'is_filterable_in_search' => 1,
- 'is_used_for_promo_rules' => 0,
- 'is_html_allowed_on_front' => 1,
- 'is_visible_on_front' => 1,
- 'used_in_product_listing' => 1,
- 'used_for_sort_by' => 0,
- 'frontend_label' => ['Boolean Attribute'],
- 'backend_type' => 'int',
- 'source_model' => Boolean::class
- ]
-);
+try {
+ $attributeRepository->get(CategorySetup::CATALOG_PRODUCT_ENTITY_TYPE_ID, 'boolean_attribute');
+} catch (NoSuchEntityException $e) {
+ $attribute->setData(
+ [
+ 'attribute_code' => 'boolean_attribute',
+ 'entity_type_id' => CategorySetup::CATALOG_PRODUCT_ENTITY_TYPE_ID,
+ 'is_global' => 0,
+ 'is_user_defined' => 1,
+ 'frontend_input' => 'boolean',
+ 'is_unique' => 0,
+ 'is_required' => 0,
+ 'is_searchable' => 1,
+ 'is_visible_in_advanced_search' => 1,
+ 'is_comparable' => 0,
+ 'is_filterable' => 1,
+ 'is_filterable_in_search' => 1,
+ 'is_used_for_promo_rules' => 0,
+ 'is_html_allowed_on_front' => 1,
+ 'is_visible_on_front' => 1,
+ 'used_in_product_listing' => 1,
+ 'used_for_sort_by' => 0,
+ 'frontend_label' => ['Boolean Attribute'],
+ 'backend_type' => 'int',
+ 'source_model' => Boolean::class
+ ]
+ );
-$attributeRepository->save($attribute);
+ $attributeRepository->save($attribute);
-/* Assign attribute to attribute set */
-$installer->addAttributeToGroup('catalog_product', 'Default', 'Attributes', $attribute->getId());
+ /* Assign attribute to attribute set */
+ $installer->addAttributeToGroup('catalog_product', 'Default', 'Attributes', $attribute->getId());
+}
diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/block.php b/dev/tests/integration/testsuite/Magento/Cms/_files/block.php
index 070fd9ae2a0b3..4625c1fe3313b 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/_files/block.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/_files/block.php
@@ -3,9 +3,22 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
+use Magento\Cms\Api\BlockRepositoryInterface;
+use Magento\Cms\Model\Block;
+use Magento\Store\Model\StoreManagerInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+
+$objectManager = Bootstrap::getObjectManager();
+
+/**
+ * @var $block Block
+ * @var $blockRepository BlockRepositoryInterface
+ */
+$block = $objectManager->create(Block::class);
+$blockRepository = $objectManager->create(BlockRepositoryInterface::class);
-/** @var $block \Magento\Cms\Model\Block */
-$block = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Cms\Model\Block::class);
$block->setTitle(
'CMS Block Title'
)->setIdentifier(
@@ -20,8 +33,10 @@
1
)->setStores(
[
- \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
- \Magento\Store\Model\StoreManagerInterface::class
+ Bootstrap::getObjectManager()->get(
+ StoreManagerInterface::class
)->getStore()->getId()
]
-)->save();
+);
+
+$blockRepository->save($block);
diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store.php b/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store.php
index de4e852f807bc..825103d76ecff 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/_files/block_default_store.php
@@ -5,12 +5,20 @@
*/
declare(strict_types=1);
+use Magento\Cms\Api\BlockRepositoryInterface;
use Magento\Cms\Model\Block;
use Magento\Store\Model\Store;
use Magento\TestFramework\Helper\Bootstrap;
-/** @var $block Block */
-$block = Bootstrap::getObjectManager()->create(Block::class);
+$objectManager = Bootstrap::getObjectManager();
+
+/**
+ * @var $block Block
+ * @var $blockRepository BlockRepositoryInterface
+ */
+$block = $objectManager->create(Block::class);
+$blockRepository = $objectManager->create(BlockRepositoryInterface::class);
+
$block->setTitle(
'CMS Block Title'
)->setIdentifier(
@@ -24,4 +32,6 @@
1
)->setStores(
[Store::DEFAULT_STORE_ID]
-)->save();
+);
+
+$blockRepository->save($block);
diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/home_with_custom_handle.php b/dev/tests/integration/testsuite/Magento/Cms/_files/home_with_custom_handle.php
index 2556e0318222d..a4dd0c5fd4e56 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/_files/home_with_custom_handle.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/_files/home_with_custom_handle.php
@@ -5,6 +5,7 @@
*/
declare(strict_types=1);
+use Magento\Cms\Model\ResourceModel\Page as PageResource;
use Magento\Cms\Model\Page as PageModel;
use Magento\Cms\Model\PageFactory as PageModelFactory;
use Magento\TestFramework\Cms\Model\CustomLayoutManager;
@@ -20,11 +21,16 @@
$customLayoutName = 'page_custom_layout';
-/** @var PageModel $page */
+/**
+ * @var PageModel $page
+ * @var PageResource $pageResource
+ */
$page = $pageFactory->create(['customLayoutRepository' => $layoutRepo]);
-$page->load('home');
+$pageResource = $objectManager->create(PageResource::class);
+
+$pageResource->load($page, 'home');
$cmsPageId = (int)$page->getId();
$fakeManager->fakeAvailableFiles($cmsPageId, [$customLayoutName]);
$page->setData('layout_update_selected', $customLayoutName);
-$page->save();
+$pageResource->save($page);
diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/noroute.php b/dev/tests/integration/testsuite/Magento/Cms/_files/noroute.php
index 4c56132a12c01..6fb93a266036c 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/_files/noroute.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/_files/noroute.php
@@ -3,6 +3,22 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-$block = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Cms\Model\Page::class);
-$block->load('no-route', 'identifier');
-$block->setIsActive(0)->save();
+
+declare(strict_types=1);
+
+use Magento\Cms\Model\Page;
+use Magento\Cms\Model\ResourceModel\Page as PageResource;
+use Magento\TestFramework\Helper\Bootstrap;
+
+$objectManager = Bootstrap::getObjectManager();
+
+/**
+ * @var Page $page
+ * @var PageResource $pageResource
+ */
+$page = $objectManager->create(Page::class);
+$pageResource = $objectManager->create(PageResource::class);
+
+$pageResource->load($page, 'no-route', 'identifier');
+$page->setIsActive(0);
+$pageResource->save($page);
diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/pages.php b/dev/tests/integration/testsuite/Magento/Cms/_files/pages.php
index b2742ecd380f3..3581fdc34f8e5 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/_files/pages.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/_files/pages.php
@@ -4,8 +4,21 @@
* See COPYING.txt for license details.
*/
-/** @var $page \Magento\Cms\Model\Page */
-$page = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Cms\Model\Page::class);
+declare(strict_types=1);
+
+use Magento\Cms\Api\PageRepositoryInterface;
+use Magento\Cms\Model\Page;
+use Magento\TestFramework\Helper\Bootstrap;
+
+$objectManager = Bootstrap::getObjectManager();
+
+/**
+ * @var $page Page
+ * @var $pageRepository PageRepositoryInterface
+ */
+$page = $objectManager->create(Page::class);
+$pageRepository = $objectManager->create(PageRepositoryInterface::class);
+
$page->setTitle('Cms Page 100')
->setIdentifier('page100')
->setStores([0])
@@ -15,10 +28,10 @@
->setMetaTitle('Cms Meta title for page100')
->setMetaKeywords('Cms Meta Keywords for page100')
->setMetaDescription('Cms Meta Description for page100')
- ->setPageLayout('1column')
- ->save();
+ ->setPageLayout('1column');
+$pageRepository->save($page);
-$page = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Cms\Model\Page::class);
+$page = $objectManager->create(Page::class);
$page->setTitle('Cms Page Design Blank')
->setIdentifier('page_design_blank')
->setStores([0])
@@ -29,5 +42,5 @@
->setMetaKeywords('Cms Meta Keywords for Blank page')
->setMetaDescription('Cms Meta Description for Blank page')
->setPageLayout('1column')
- ->setCustomTheme('Magento/blank')
- ->save();
+ ->setCustomTheme('Magento/blank');
+$pageRepository->save($page);
diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/pages_with_layout_xml.php b/dev/tests/integration/testsuite/Magento/Cms/_files/pages_with_layout_xml.php
index 9734ed3abaeed..c7ea5f6380b32 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/_files/pages_with_layout_xml.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/_files/pages_with_layout_xml.php
@@ -7,16 +7,21 @@
declare(strict_types=1);
use Magento\Cms\Model\Page as PageModel;
+use Magento\Cms\Model\ResourceModel\Page as PageResource;
use Magento\Cms\Model\PageFactory as PageModelFactory;
use Magento\TestFramework\Cms\Model\CustomLayoutManager;
use Magento\TestFramework\Helper\Bootstrap;
$objectManager = Bootstrap::getObjectManager();
$pageFactory = $objectManager->get(PageModelFactory::class);
+
/** @var CustomLayoutManager $fakeManager */
$fakeManager = $objectManager->get(CustomLayoutManager::class);
$layoutRepo = $objectManager->create(PageModel\CustomLayoutRepositoryInterface::class, ['manager' => $fakeManager]);
+/** @var PageResource $pageRepository */
+$pageResource = $objectManager->create(PageResource::class);
+
/** @var PageModel $page */
$page = $pageFactory->create(['customLayoutRepository' => $layoutRepo]);
$page->setIdentifier('test_custom_layout_page_1');
@@ -25,14 +30,16 @@
$page->setLayoutUpdateXml('');
$page->setIsActive(true);
$page->setStoreId(0);
-$page->save();
+$pageResource->save($page);
+
/** @var PageModel $page2 */
$page2 = $pageFactory->create(['customLayoutRepository' => $layoutRepo]);
$page2->setIdentifier('test_custom_layout_page_2');
$page2->setTitle('Test Page 2');
$page->setIsActive(true);
$page->setStoreId(0);
-$page2->save();
+$pageResource->save($page2);
+
/** @var PageModel $page3 */
$page3 = $pageFactory->create(['customLayoutRepository' => $layoutRepo]);
$page3->setIdentifier('test_custom_layout_page_3');
@@ -41,7 +48,7 @@
$page3->setIsActive(1);
$page3->setContent('Test Page
');
$page3->setPageLayout('1column');
-$page3->save();
+$pageResource->save($page3);
$fakeManager->fakeAvailableFiles((int)$page3->getId(), ['test_selected']);
$page3->setData('layout_update_selected', 'test_selected');
-$page3->save();
+$pageResource->save($page3);
diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/pages_with_layout_xml_rollback.php b/dev/tests/integration/testsuite/Magento/Cms/_files/pages_with_layout_xml_rollback.php
index 3217b94d7392b..684b1d4356d20 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/_files/pages_with_layout_xml_rollback.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/_files/pages_with_layout_xml_rollback.php
@@ -8,25 +8,33 @@
use Magento\Cms\Model\Page as PageModel;
use Magento\Cms\Model\PageFactory as PageModelFactory;
+use Magento\Cms\Model\ResourceModel\Page as PageResource;
use Magento\TestFramework\Helper\Bootstrap;
$objectManager = Bootstrap::getObjectManager();
$pageFactory = $objectManager->get(PageModelFactory::class);
-/** @var PageModel $page */
+
+/**
+ * @var PageModel $page
+ * @var PageResource $pageResource
+ */
$page = $pageFactory->create();
-$page->load('test_custom_layout_page_1', PageModel::IDENTIFIER);
+$pageResource = $objectManager->create(PageResource::class);
+$pageResource->load($page, 'test_custom_layout_page_1', PageModel::IDENTIFIER);
if ($page->getId()) {
- $page->delete();
+ $pageResource->delete($page);
}
+
/** @var PageModel $page2 */
$page2 = $pageFactory->create();
-$page2->load('test_custom_layout_page_2', PageModel::IDENTIFIER);
+$pageResource->load($page2, 'test_custom_layout_page_2', PageModel::IDENTIFIER);
if ($page2->getId()) {
- $page2->delete();
+ $pageResource->delete($page2);
}
+
/** @var PageModel $page3 */
$page3 = $pageFactory->create();
-$page3->load('test_custom_layout_page_3', PageModel::IDENTIFIER);
+$pageResource->load($page3, 'test_custom_layout_page_3', PageModel::IDENTIFIER);
if ($page3->getId()) {
- $page3->delete();
+ $pageResource->delete($page3);
}
diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/two_cms_page_with_same_url_for_different_stores.php b/dev/tests/integration/testsuite/Magento/Cms/_files/two_cms_page_with_same_url_for_different_stores.php
index 16e4a4e521fa3..fdb042fbb18fa 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/_files/two_cms_page_with_same_url_for_different_stores.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/_files/two_cms_page_with_same_url_for_different_stores.php
@@ -5,29 +5,37 @@
*/
declare(strict_types=1);
+use Magento\Cms\Api\PageRepositoryInterface;
+use Magento\Cms\Model\Page;
use Magento\Store\Api\StoreRepositoryInterface;
+use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
Resolver::getInstance()->requireDataFixture('Magento/Store/_files/second_store.php');
-$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+$objectManager = Bootstrap::getObjectManager();
+
/** @var StoreRepositoryInterface $storeRepository */
$storeRepository = $objectManager->get(StoreRepositoryInterface::class);
$store = $storeRepository->get('fixture_second_store');
-/** @var $page \Magento\Cms\Model\Page */
-$page = $objectManager->create(\Magento\Cms\Model\Page::class);
+
+/** @var PageRepositoryInterface $pageRepository */
+$pageRepository = $objectManager->create(PageRepositoryInterface::class);
+
+/** @var $page Page */
+$page = $objectManager->create(Page::class);
$page->setTitle('First test page')
->setIdentifier('page1')
->setStores([1])
->setIsActive(1)
- ->setPageLayout('1column')
- ->save();
+ ->setPageLayout('1column');
+$pageRepository->save($page);
-/** @var $page \Magento\Cms\Model\Page */
-$page = $objectManager->create(\Magento\Cms\Model\Page::class);
+/** @var $page Page */
+$page = $objectManager->create(Page::class);
$page->setTitle('Second test page')
->setIdentifier('page1')
->setStores([$store->getId()])
->setIsActive(1)
- ->setPageLayout('1column')
- ->save();
+ ->setPageLayout('1column');
+$pageRepository->save($page);
diff --git a/dev/tests/integration/testsuite/Magento/Elasticsearch/Model/Indexer/IndexHandlerTest.php b/dev/tests/integration/testsuite/Magento/Elasticsearch/Model/Indexer/IndexHandlerTest.php
index 1eb2550dc484c..0173a643dd7bd 100644
--- a/dev/tests/integration/testsuite/Magento/Elasticsearch/Model/Indexer/IndexHandlerTest.php
+++ b/dev/tests/integration/testsuite/Magento/Elasticsearch/Model/Indexer/IndexHandlerTest.php
@@ -19,6 +19,7 @@
use Magento\Indexer\Model\Indexer;
use Magento\Framework\Search\EngineResolverInterface;
use Magento\TestModuleCatalogSearch\Model\ElasticsearchVersionChecker;
+use PHPUnit\Framework\TestCase;
/**
* Important: Please make sure that each integration test file works with unique elastic search index. In order to
@@ -29,7 +30,7 @@
* @magentoDataFixture Magento/Elasticsearch/_files/indexer.php
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class IndexHandlerTest extends \PHPUnit\Framework\TestCase
+class IndexHandlerTest extends TestCase
{
/**
* @var string
@@ -116,6 +117,9 @@ public function testReindexAll(): void
$products = $this->searchByName('Simple Product', $storeId);
$this->assertCount(5, $products);
+
+ $this->assertCount(2, $this->searchByBoolAttribute(0, $storeId));
+ $this->assertCount(3, $this->searchByBoolAttribute(1, $storeId));
}
}
@@ -266,6 +270,32 @@ private function searchByName(string $text, int $storeId): array
return $products;
}
+ /**
+ * Search docs in Elasticsearch by boolean attribute.
+ *
+ * @param int $value
+ * @param int $storeId
+ * @return array
+ */
+ private function searchByBoolAttribute(int $value, int $storeId): array
+ {
+ $index = $this->searchIndexNameResolver->getIndexName($storeId, $this->indexer->getId());
+ $searchQuery = [
+ 'index' => $index,
+ 'type' => $this->entityType,
+ 'body' => [
+ 'query' => [
+ 'query_string' => [
+ 'query' => $value,
+ 'default_field' => 'boolean_attribute',
+ ],
+ ],
+ ],
+ ];
+ $queryResult = $this->client->query($searchQuery);
+ return isset($queryResult['hits']['hits']) ? $queryResult['hits']['hits'] : [];
+ }
+
/**
* Returns installed on server search service
*
diff --git a/dev/tests/integration/testsuite/Magento/Elasticsearch/_files/indexer.php b/dev/tests/integration/testsuite/Magento/Elasticsearch/_files/indexer.php
index cf87be7e8d710..c6989c7805b4a 100644
--- a/dev/tests/integration/testsuite/Magento/Elasticsearch/_files/indexer.php
+++ b/dev/tests/integration/testsuite/Magento/Elasticsearch/_files/indexer.php
@@ -4,14 +4,27 @@
* See COPYING.txt for license details.
*/
-/** @var $objectManager \Magento\Framework\ObjectManagerInterface */
-$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Catalog\Model\Product\Visibility;
+use Magento\Framework\App\MutableScopeConfig;
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Store\Model\ScopeInterface;
+use Magento\Store\Model\Store;
+use Magento\Store\Model\StoreManagerInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
+
+Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_boolean_attribute.php');
-/** @var \Magento\Store\Model\StoreManagerInterface $storeManager */
-$storeManager = $objectManager->get(\Magento\Store\Model\StoreManagerInterface::class);
+/** @var $objectManager \Magento\Framework\ObjectManagerInterface */
+$objectManager = Bootstrap::getObjectManager();
-/** @var \Magento\Store\Model\Store $store */
-$store = $objectManager->create(\Magento\Store\Model\Store::class);
+/** @var StoreManagerInterface $storeManager */
+$storeManager = $objectManager->get(StoreManagerInterface::class);
+/** @var Store $store */
+$store = $objectManager->create(Store::class);
$storeCode = 'secondary';
if (!$store->load($storeCode)->getId()) {
@@ -23,92 +36,118 @@
->setIsActive(1);
$store->save();
- /** @var \Magento\Framework\App\MutableScopeConfig $scopeConfig */
- $scopeConfig = $objectManager->get(\Magento\Framework\App\MutableScopeConfig::class);
+ /** @var MutableScopeConfig $scopeConfig */
+ $scopeConfig = $objectManager->get(MutableScopeConfig::class);
$scopeConfig->setValue(
'general/locale/code',
'de_DE',
- \Magento\Store\Model\ScopeInterface::SCOPE_STORES,
+ ScopeInterface::SCOPE_STORES,
$store->getId()
);
}
-/** @var $productFirst \Magento\Catalog\Model\Product */
-$productFirst = $objectManager->create(\Magento\Catalog\Model\Product::class);
-$productFirst->setTypeId('simple')
- ->setAttributeSetId(4)
- ->setWebsiteIds([1])
- ->setName('Simple Product Apple')
- ->setSku('fulltext-1')
- ->setPrice(10)
- ->setMetaTitle('first meta title')
- ->setMetaKeyword('first meta keyword')
- ->setMetaDescription('first meta description')
- ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
- ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
- ->setStockData(['use_config_manage_stock' => 0])
- ->save();
+$productRepository = $objectManager->get(ProductRepositoryInterface::class);
+try {
+ $productRepository->get('fulltext-1');
+} catch (NoSuchEntityException $e) {
+ /** @var $productFirst Product */
+ $productFirst = $objectManager->create(Product::class);
+ $productFirst->setTypeId('simple')
+ ->setAttributeSetId(4)
+ ->setWebsiteIds([1])
+ ->setName('Simple Product Apple')
+ ->setSku('fulltext-1')
+ ->setPrice(10)
+ ->setMetaTitle('first meta title')
+ ->setMetaKeyword('first meta keyword')
+ ->setMetaDescription('first meta description')
+ ->setVisibility(Visibility::VISIBILITY_BOTH)
+ ->setStatus(Status::STATUS_ENABLED)
+ ->setStockData(['use_config_manage_stock' => 0])
+ ->setBooleanAttribute(1)
+ ->save();
+}
-/** @var $productSecond \Magento\Catalog\Model\Product */
-$productSecond = $objectManager->create(\Magento\Catalog\Model\Product::class);
-$productSecond->setTypeId('simple')
- ->setAttributeSetId(4)
- ->setWebsiteIds([1])
- ->setName('Simple Product Banana')
- ->setSku('fulltext-2')
- ->setPrice(20)
- ->setMetaTitle('second meta title')
- ->setMetaKeyword('second meta keyword')
- ->setMetaDescription('second meta description')
- ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
- ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
- ->setStockData(['use_config_manage_stock' => 0])
- ->save();
+try {
+ $productRepository->get('fulltext-2');
+} catch (NoSuchEntityException $e) {
+ /** @var $productSecond Product */
+ $productSecond = $objectManager->create(Product::class);
+ $productSecond->setTypeId('simple')
+ ->setAttributeSetId(4)
+ ->setWebsiteIds([1])
+ ->setName('Simple Product Banana')
+ ->setSku('fulltext-2')
+ ->setPrice(20)
+ ->setMetaTitle('second meta title')
+ ->setMetaKeyword('second meta keyword')
+ ->setMetaDescription('second meta description')
+ ->setVisibility(Visibility::VISIBILITY_BOTH)
+ ->setStatus(Status::STATUS_ENABLED)
+ ->setStockData(['use_config_manage_stock' => 0])
+ ->setBooleanAttribute(1)
+ ->save();
+}
-/** @var $productThird \Magento\Catalog\Model\Product */
-$productThird = $objectManager->create(\Magento\Catalog\Model\Product::class);
-$productThird->setTypeId('simple')
- ->setAttributeSetId(4)
- ->setWebsiteIds([1])
- ->setName('Simple Product Orange')
- ->setSku('fulltext-3')
- ->setPrice(20)
- ->setMetaTitle('third meta title')
- ->setMetaKeyword('third meta keyword')
- ->setMetaDescription('third meta description')
- ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
- ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
- ->setStockData(['use_config_manage_stock' => 0])
- ->save();
+try {
+ $productRepository->get('fulltext-3');
+} catch (NoSuchEntityException $e) {
+ /** @var $productThird Product */
+ $productThird = $objectManager->create(Product::class);
+ $productThird->setTypeId('simple')
+ ->setAttributeSetId(4)
+ ->setWebsiteIds([1])
+ ->setName('Simple Product Orange')
+ ->setSku('fulltext-3')
+ ->setPrice(20)
+ ->setMetaTitle('third meta title')
+ ->setMetaKeyword('third meta keyword')
+ ->setMetaDescription('third meta description')
+ ->setVisibility(Visibility::VISIBILITY_BOTH)
+ ->setStatus(Status::STATUS_ENABLED)
+ ->setStockData(['use_config_manage_stock' => 0])
+ ->setBooleanAttribute(1)
+ ->save();
+}
-/** @var $productFourth \Magento\Catalog\Model\Product */
-$productFourth = $objectManager->create(\Magento\Catalog\Model\Product::class);
-$productFourth->setTypeId('simple')
- ->setAttributeSetId(4)
- ->setWebsiteIds([1])
- ->setName('Simple Product Papaya')
- ->setSku('fulltext-4')
- ->setPrice(20)
- ->setMetaTitle('fourth meta title')
- ->setMetaKeyword('fourth meta keyword')
- ->setMetaDescription('fourth meta description')
- ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
- ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
- ->setStockData(['use_config_manage_stock' => 0])
- ->save();
+try {
+ $productRepository->get('fulltext-4');
+} catch (NoSuchEntityException $e) {
+ /** @var $productFourth Product */
+ $productFourth = $objectManager->create(Product::class);
+ $productFourth->setTypeId('simple')
+ ->setAttributeSetId(4)
+ ->setWebsiteIds([1])
+ ->setName('Simple Product Papaya')
+ ->setSku('fulltext-4')
+ ->setPrice(20)
+ ->setMetaTitle('fourth meta title')
+ ->setMetaKeyword('fourth meta keyword')
+ ->setMetaDescription('fourth meta description')
+ ->setVisibility(Visibility::VISIBILITY_BOTH)
+ ->setStatus(Status::STATUS_ENABLED)
+ ->setStockData(['use_config_manage_stock' => 0])
+ ->setBooleanAttribute(0)
+ ->save();
+}
-/** @var $productFifth \Magento\Catalog\Model\Product */
-$productFifth = $objectManager->create(\Magento\Catalog\Model\Product::class);
-$productFifth->setTypeId('simple')
- ->setAttributeSetId(4)
- ->setWebsiteIds([1])
- ->setName('Simple Product Cherry')
- ->setSku('fulltext-5')
- ->setPrice(20)
- ->setMetaTitle('fifth meta title')
- ->setMetaKeyword('fifth meta keyword')
- ->setMetaDescription('fifth meta description')
- ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
- ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
- ->setStockData(['use_config_manage_stock' => 0])
- ->save();
+try {
+ $productRepository->get('fulltext-5');
+} catch (NoSuchEntityException $e) {
+ /** @var $productFifth Product */
+ $productFifth = $objectManager->create(Product::class);
+ $productFifth->setTypeId('simple')
+ ->setAttributeSetId(4)
+ ->setWebsiteIds([1])
+ ->setName('Simple Product Cherry')
+ ->setSku('fulltext-5')
+ ->setPrice(20)
+ ->setMetaTitle('fifth meta title')
+ ->setMetaKeyword('fifth meta keyword')
+ ->setMetaDescription('fifth meta description')
+ ->setVisibility(Visibility::VISIBILITY_BOTH)
+ ->setStatus(Status::STATUS_ENABLED)
+ ->setStockData(['use_config_manage_stock' => 0])
+ ->setBooleanAttribute(0)
+ ->save();
+}
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceInterceptor.php.sample b/dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceInterceptor.php.sample
index 74c1522fa41f0..930c439899f03 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceInterceptor.php.sample
+++ b/dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceInterceptor.php.sample
@@ -21,11 +21,7 @@ class Interceptor extends \Magento\Framework\Code\GeneratorTest\SourceClassWithN
public function publicChildMethod(\Laminas\Code\Generator\ClassGenerator $classGenerator, $param1 = '', $param2 = '\\', $param3 = '\'', array $array = [])
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'publicChildMethod');
- if (!$pluginInfo) {
- return parent::publicChildMethod($classGenerator, $param1, $param2, $param3, $array);
- } else {
- return $this->___callPlugins('publicChildMethod', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('publicChildMethod', func_get_args(), $pluginInfo) : parent::publicChildMethod($classGenerator, $param1, $param2, $param3, $array);
}
/**
@@ -34,11 +30,7 @@ class Interceptor extends \Magento\Framework\Code\GeneratorTest\SourceClassWithN
public function publicMethodWithReference(\Laminas\Code\Generator\ClassGenerator &$classGenerator, &$param1, array &$array)
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'publicMethodWithReference');
- if (!$pluginInfo) {
- return parent::publicMethodWithReference($classGenerator, $param1, $array);
- } else {
- return $this->___callPlugins('publicMethodWithReference', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('publicMethodWithReference', func_get_args(), $pluginInfo) : parent::publicMethodWithReference($classGenerator, $param1, $array);
}
/**
@@ -47,11 +39,7 @@ class Interceptor extends \Magento\Framework\Code\GeneratorTest\SourceClassWithN
public function publicChildWithoutParameters()
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'publicChildWithoutParameters');
- if (!$pluginInfo) {
- return parent::publicChildWithoutParameters();
- } else {
- return $this->___callPlugins('publicChildWithoutParameters', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('publicChildWithoutParameters', func_get_args(), $pluginInfo) : parent::publicChildWithoutParameters();
}
/**
@@ -60,11 +48,7 @@ class Interceptor extends \Magento\Framework\Code\GeneratorTest\SourceClassWithN
public function public71($arg1, string $arg2, ?int $arg3, ?int $arg4 = null) : void
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'public71');
- if (!$pluginInfo) {
- parent::public71($arg1, $arg2, $arg3, $arg4);
- } else {
- $this->___callPlugins('public71', func_get_args(), $pluginInfo);
- }
+ $pluginInfo ? $this->___callPlugins('public71', func_get_args(), $pluginInfo) : parent::public71($arg1, $arg2, $arg3, $arg4);
}
/**
@@ -73,11 +57,7 @@ class Interceptor extends \Magento\Framework\Code\GeneratorTest\SourceClassWithN
public function public71Another(?\DateTime $arg1, $arg2 = false) : ?string
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'public71Another');
- if (!$pluginInfo) {
- return parent::public71Another($arg1, $arg2);
- } else {
- return $this->___callPlugins('public71Another', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('public71Another', func_get_args(), $pluginInfo) : parent::public71Another($arg1, $arg2);
}
/**
@@ -86,11 +66,7 @@ class Interceptor extends \Magento\Framework\Code\GeneratorTest\SourceClassWithN
public function publicWithSelf($arg = false) : \Magento\Framework\Code\GeneratorTest\SourceClassWithNamespace
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'publicWithSelf');
- if (!$pluginInfo) {
- return parent::publicWithSelf($arg);
- } else {
- return $this->___callPlugins('publicWithSelf', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('publicWithSelf', func_get_args(), $pluginInfo) : parent::publicWithSelf($arg);
}
/**
@@ -99,11 +75,7 @@ class Interceptor extends \Magento\Framework\Code\GeneratorTest\SourceClassWithN
public function publicParentMethod(\Laminas\Code\Generator\DocBlockGenerator $docBlockGenerator, $param1 = '', $param2 = '\\', $param3 = '\'', array $array = [])
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'publicParentMethod');
- if (!$pluginInfo) {
- return parent::publicParentMethod($docBlockGenerator, $param1, $param2, $param3, $array);
- } else {
- return $this->___callPlugins('publicParentMethod', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('publicParentMethod', func_get_args(), $pluginInfo) : parent::publicParentMethod($docBlockGenerator, $param1, $param2, $param3, $array);
}
/**
@@ -112,10 +84,6 @@ class Interceptor extends \Magento\Framework\Code\GeneratorTest\SourceClassWithN
public function publicParentWithoutParameters()
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'publicParentWithoutParameters');
- if (!$pluginInfo) {
- return parent::publicParentWithoutParameters();
- } else {
- return $this->___callPlugins('publicParentWithoutParameters', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('publicParentWithoutParameters', func_get_args(), $pluginInfo) : parent::publicParentWithoutParameters();
}
}
diff --git a/dev/tests/integration/testsuite/Magento/GiftMessage/_files/customer/order_with_message.php b/dev/tests/integration/testsuite/Magento/GiftMessage/_files/customer/order_with_message.php
new file mode 100644
index 0000000000000..55b38d9900acd
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GiftMessage/_files/customer/order_with_message.php
@@ -0,0 +1,102 @@
+requireDataFixture('Magento/Catalog/_files/product_simple.php');
+
+$addressData = include __DIR__ . '/../../../../Magento/Sales/_files/address_data.php';
+
+$objectManager = Bootstrap::getObjectManager();
+
+/** @var Order $order */
+/** @var Order\Payment $payment */
+/** @var Order\Item $orderItem */
+/** @var array $addressData Data for creating addresses for the orders. */
+$orders = [
+ [
+ 'increment_id' => '999999990',
+ 'state' => Order::STATE_NEW,
+ 'status' => 'processing',
+ 'grand_total' => 120.00,
+ 'subtotal' => 120.00,
+ 'base_grand_total' => 120.00,
+ 'store_id' => 1,
+ 'website_id' => 1,
+ ],
+ [
+ 'increment_id' => '999999991',
+ 'state' => Order::STATE_PROCESSING,
+ 'status' => 'processing',
+ 'grand_total' => 130.00,
+ 'base_grand_total' => 130.00,
+ 'subtotal' => 130.00,
+ 'total_paid' => 130.00,
+ 'store_id' => 1,
+ 'website_id' => 1,
+ ]
+];
+
+/** @var OrderRepositoryInterface $orderRepository */
+$orderRepository = $objectManager->create(OrderRepositoryInterface::class);
+
+$payment = $objectManager->create(\Magento\Sales\Model\Order\Payment::class);
+$payment->setMethod('checkmo');
+$productRepository = $objectManager->create(ProductRepositoryInterface::class);
+$product = $productRepository->get('simple');
+
+/** @var array $orderData */
+foreach ($orders as $orderData) {
+ /** @var Magento\Sales\Model\Order $order */
+ $order = $objectManager->create(Order::class);
+
+ // Reset addresses
+ /** @var Order\Address $billingAddress */
+ $billingAddress = $objectManager->create(OrderAddress::class, ['data' => $addressData]);
+ $billingAddress->setAddressType('billing');
+
+ $shippingAddress = clone $billingAddress;
+ $shippingAddress->setId(null)->setAddressType('shipping');
+
+ /** @var MessageResource $message */
+ $message = $objectManager->create(MessageResource::class);
+
+ /** @var Message $message */
+ $messageModel = $objectManager->create(Message::class);
+
+ $messageModel->setSender('John Doe');
+ $messageModel->setRecipient('Jane Roe');
+ $messageModel->setMessage('Gift Message Text');
+ $message->save($messageModel);
+
+ /** @var Order\Item $orderItem */
+ $orderItem = $objectManager->create(Order\Item::class);
+ $orderItem->setProductId($product->getId())
+ ->setQtyOrdered(2)
+ ->setBasePrice($product->getPrice())
+ ->setPrice($product->getPrice())
+ ->setRowTotal($product->getPrice())
+ ->setProductType('simple');
+
+ $order
+ ->setData($orderData)
+ ->addItem($orderItem)
+ ->setCustomerIsGuest(false)
+ ->setCustomerId(1)
+ ->setCustomerEmail('customer@example.com')
+ ->setBillingAddress($billingAddress)
+ ->setShippingAddress($shippingAddress)
+ ->setPayment($payment);
+ $order->setGiftMessageId($messageModel->getId());
+ $orderRepository->save($order);
+}
diff --git a/dev/tests/integration/testsuite/Magento/GiftMessage/_files/customer/order_with_message_rollback.php b/dev/tests/integration/testsuite/Magento/GiftMessage/_files/customer/order_with_message_rollback.php
new file mode 100644
index 0000000000000..5aaf728243729
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GiftMessage/_files/customer/order_with_message_rollback.php
@@ -0,0 +1,46 @@
+get(Registry::class);
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+$productRepository = $objectManager->get(ProductRepositoryInterface::class);
+$product = $productRepository->get('simple');
+$productRepository->delete($product);
+
+/** @var OrderRepositoryInterface $orderRepository */
+$orderRepository = $objectManager->get(OrderRepositoryInterface::class);
+/** @var OrderInterfaceFactory $orderFactory */
+$orderFactory = $objectManager->create(OrderInterfaceFactory::class);
+$orders = [];
+$orders[] = $orderFactory->create()->loadByIncrementId('999999990');
+$orders[] = $orderFactory->create()->loadByIncrementId('999999991');
+
+foreach ($orders as $order) {
+ if ($order->getGiftMessageId()) {
+ $message = $objectManager->create(Message::class);
+ $message->load($order->getGiftMessageId());
+ $message->delete();
+ }
+ if ($order->getId()) {
+ $orderRepository->delete($order);
+ }
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/_files/guest_subscriber.php b/dev/tests/integration/testsuite/Magento/Newsletter/_files/guest_subscriber.php
new file mode 100644
index 0000000000000..e10dcd5985a2e
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Newsletter/_files/guest_subscriber.php
@@ -0,0 +1,24 @@
+get(StoreManagerInterface::class)
+ ->getStore()
+ ->getId();
+
+/** @var Subscriber $subscriber */
+$subscriber = $objectManager->create(Subscriber::class);
+
+$subscriber->setStoreId($storeId)
+ ->setSubscriberEmail('guest@example.com')
+ ->setSubscriberStatus(Subscriber::STATUS_SUBSCRIBED)
+ ->save();
diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/_files/guest_subscriber_rollback.php b/dev/tests/integration/testsuite/Magento/Newsletter/_files/guest_subscriber_rollback.php
new file mode 100644
index 0000000000000..225f6515b5ce7
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Newsletter/_files/guest_subscriber_rollback.php
@@ -0,0 +1,33 @@
+get(Registry::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+$storeId = $objectManager->get(StoreManagerInterface::class)
+ ->getStore()
+ ->getId();
+
+/** @var Subscriber $subscriber */
+$subscriber = $objectManager->get(Subscriber::class);
+$subscriber->loadBySubscriberEmail('guest@example.com', (int)$storeId);
+if ($subscriber->getId()) {
+ $subscriber->delete();
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Sales/Cron/CleanExpiredQuotesTest.php b/dev/tests/integration/testsuite/Magento/Sales/Cron/CleanExpiredQuotesTest.php
index f6dee4c7ff0fa..f69c97a635e76 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/Cron/CleanExpiredQuotesTest.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/Cron/CleanExpiredQuotesTest.php
@@ -9,6 +9,7 @@
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Quote\Model\QuoteRepository;
+use Magento\Quote\Model\ResourceModel\Quote\CollectionFactory as QuoteCollectionFactory;
use Magento\TestFramework\Helper\Bootstrap;
/**
@@ -25,14 +26,9 @@ class CleanExpiredQuotesTest extends \PHPUnit\Framework\TestCase
private $cleanExpiredQuotes;
/**
- * @var QuoteRepository
+ * @var QuoteCollectionFactory
*/
- private $quoteRepository;
-
- /**
- * @var SearchCriteriaBuilder
- */
- private $searchCriteriaBuilder;
+ private $quoteCollectionFactory;
/**
* @inheritdoc
@@ -41,8 +37,7 @@ protected function setUp(): void
{
$objectManager = Bootstrap::getObjectManager();
$this->cleanExpiredQuotes = $objectManager->get(CleanExpiredQuotes::class);
- $this->quoteRepository = $objectManager->get(QuoteRepository::class);
- $this->searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class);
+ $this->quoteCollectionFactory = $objectManager->get(QuoteCollectionFactory::class);
}
/**
@@ -53,17 +48,43 @@ protected function setUp(): void
*/
public function testExecute()
{
- $searchCriteria = $this->searchCriteriaBuilder->create();
//Initial count - should be equal to stores number.
- $this->assertEquals(2, $this->quoteRepository->getList($searchCriteria)->getTotalCount());
+ $this->assertQuotesCount(2);
//Deleting expired quotes
$this->cleanExpiredQuotes->execute();
- $totalCount = $this->quoteRepository->getList($searchCriteria)->getTotalCount();
+
//Only 1 will be deleted for the store that has all of them expired by config (default_store)
- $this->assertEquals(
- 1,
- $totalCount
- );
+ $this->assertQuotesCount(1);
+ }
+
+ /**
+ * Check if outdated quotes are deleted.
+ *
+ * @magentoConfigFixture default_store checkout/cart/delete_quote_after -365
+ * @magentoDataFixture Magento/Sales/_files/quotes_big_amount.php
+ */
+ public function testExecuteWithBigAmountOfQuotes()
+ {
+ //Initial count - should be equal to 1000
+ $this->assertQuotesCount(1000);
+
+ //Deleting expired quotes
+ $this->cleanExpiredQuotes->execute();
+
+ //There should be no quotes anymore
+ $this->assertQuotesCount(0);
+ }
+
+ /**
+ * Optimized assert quotes count
+ * Uses collection getSize in order to get quick result
+ *
+ * @param int $expected
+ */
+ private function assertQuotesCount(int $expected): void
+ {
+ $totalCount = $this->quoteCollectionFactory->create()->getSize();
+ $this->assertEquals($expected, $totalCount);
}
}
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quotes_big_amount.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quotes_big_amount.php
new file mode 100644
index 0000000000000..c666f938d9125
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quotes_big_amount.php
@@ -0,0 +1,37 @@
+get(QuoteFactory::class);
+/** @var QuoteRepository $quoteRepository */
+$quoteRepository = $objectManager->get(QuoteRepository::class);
+/** @var StoreRepository $storeRepository */
+$storeRepository = $objectManager->get(StoreRepository::class);
+/** @var Config $appConfig */
+$appConfig = $objectManager->get(Config::class);
+$appConfig->clean();
+
+/** @var Store $defaultStore */
+$defaultStore = $storeRepository->getActiveStoreByCode('default');
+
+for ($i = 0; $i < 1000; $i++) {
+ /** @var Quote $quote */
+ $quote = $quoteFactory->create();
+ $quote->setStoreId($defaultStore->getId());
+ $quoteRepository->save($quote);
+}
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quotes_big_amount_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quotes_big_amount_rollback.php
new file mode 100644
index 0000000000000..24832a297949d
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quotes_big_amount_rollback.php
@@ -0,0 +1,34 @@
+get(Registry::class);
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var QuoteRepository $quoteRepository */
+$quoteRepository = $objectManager->get(QuoteRepository::class);
+/** @var SearchCriteriaBuilder $searchCriteriaBuilder */
+$searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class);
+$searchCriteria = $searchCriteriaBuilder->create();
+$items = $quoteRepository->getList($searchCriteria)
+ ->getItems();
+foreach ($items as $item) {
+ $quoteRepository->delete($item);
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Model/WishlistTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Model/WishlistTest.php
index 84ee7d8984cc4..cab007aa6af9c 100644
--- a/dev/tests/integration/testsuite/Magento/Wishlist/Model/WishlistTest.php
+++ b/dev/tests/integration/testsuite/Magento/Wishlist/Model/WishlistTest.php
@@ -217,6 +217,27 @@ public function testUpdateItemQtyInWishList(): void
$this->assertEquals(55, $updatedItem->getQty());
}
+ /**
+ * Update description of wishlist item
+ *
+ * @magentoDataFixture Magento/Wishlist/_files/wishlist.php
+ *
+ * @return void
+ */
+ public function testUpdateItemDescriptionInWishList(): void
+ {
+ $itemDescription = 'Test Description';
+ $wishlist = $this->getWishlistByCustomerId->execute(1);
+ $item = $this->getWishlistByCustomerId->getItemBySku(1, 'simple');
+ $item->setDescription($itemDescription);
+ $this->assertNotNull($item);
+ $buyRequest = $this->dataObjectFactory->create(['data' => ['qty' => 55]]);
+ $wishlist->updateItem($item, $buyRequest);
+ $updatedItem = $this->getWishlistByCustomerId->getItemBySku(1, 'simple');
+ $this->assertEquals(55, $updatedItem->getQty());
+ $this->assertEquals($itemDescription, $updatedItem->getDescription());
+ }
+
/**
* @return void
*/
diff --git a/dev/tests/js/jasmine/tests/lib/mage/requirejs/mixins.test.js b/dev/tests/js/jasmine/tests/lib/mage/requirejs/mixins.test.js
index 52374a24e8c68..c54473d4d757f 100644
--- a/dev/tests/js/jasmine/tests/lib/mage/requirejs/mixins.test.js
+++ b/dev/tests/js/jasmine/tests/lib/mage/requirejs/mixins.test.js
@@ -183,5 +183,31 @@ define(['rjsResolver', 'mixins'], function (resolver, mixins) {
require([name], function () {});
});
+
+ it('applies mixins for modules that have no dependencies', function (done) {
+ var name = 'tests/assets/mixins/mixins-applied-no-dependencies',
+ mixinName = 'tests/assets/mixins/mixins-applied-no-dependencies-ext';
+
+ mixins.hasMixins.and.returnValue(true);
+ mixins.getMixins.and.returnValue([mixinName]);
+
+ define(name, {
+ value: 'original'
+ });
+
+ define(mixinName, [], function () {
+ return function (module) {
+ module.value = 'changed';
+
+ return module;
+ };
+ });
+
+ require([name], function (module) {
+ expect(module.value).toBe('changed');
+
+ done();
+ });
+ });
});
});
diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpstan/blacklist/common.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpstan/blacklist/common.txt
index 1bb13d553c754..a9c65eb29c2e5 100644
--- a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpstan/blacklist/common.txt
+++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpstan/blacklist/common.txt
@@ -3,9 +3,10 @@
# Example:
# app/code/Magento/Catalog
# dev/tests/static/framework/bootstrap.php
-lib/internal/Magento/Framework/Interception/Test/Unit/Config/ConfigTest.php
lib/internal/Magento/Framework/Cache/Backend/Eaccelerator.php
lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php
+lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/InterceptorTest.php
+lib/internal/Magento/Framework/Interception/Test/Unit/Config/ConfigTest.php
dev/tests/integration/framework/deployTestModules.php
dev/tests/integration/testsuite/Magento/Framework/Filter/DirectiveProcessor/SimpleDirectiveTest.php
dev/tests/integration/testsuite/Magento/Framework/Session/ConfigTest.php
diff --git a/lib/internal/Magento/Framework/Exception/InvalidArgumentException.php b/lib/internal/Magento/Framework/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000000000..a92308ec41bde
--- /dev/null
+++ b/lib/internal/Magento/Framework/Exception/InvalidArgumentException.php
@@ -0,0 +1,14 @@
+___init();\n";
if ($constructor) {
- foreach ($constructor->getParameters() as $parameter) {
- $parameters[] = $this->_getMethodParameterInfo($parameter);
- }
+ $parameters = array_map([$this, '_getMethodParameterInfo'], $constructor->getParameters());
+
$body .= count($parameters)
? "parent::__construct({$this->_getParameterList($parameters)});"
: "parent::__construct();";
@@ -70,7 +63,7 @@ protected function _getDefaultConstructorDefinition()
/**
* Returns list of methods for class generator
*
- * @return mixed
+ * @return array
*/
protected function _getClassMethods()
{
@@ -107,10 +100,7 @@ protected function isInterceptedMethod(\ReflectionMethod $method)
*/
protected function _getMethodInfo(\ReflectionMethod $method)
{
- $parameters = [];
- foreach ($method->getParameters() as $parameter) {
- $parameters[] = $this->_getMethodParameterInfo($parameter);
- }
+ $parameters = array_map([$this, '_getMethodParameterInfo'], $method->getParameters());
$returnTypeValue = $this->getReturnTypeValue($method);
$methodInfo = [
@@ -118,22 +108,18 @@ protected function _getMethodInfo(\ReflectionMethod $method)
'parameters' => $parameters,
'body' => str_replace(
[
- '%methodName%',
+ '%method%',
'%return%',
'%parameters%'
],
[
$method->getName(),
- $returnTypeValue === 'void' ? '' : ' return',
+ $returnTypeValue === 'void' ? '' : 'return ',
$this->_getParameterList($parameters)
],
<<<'METHOD_BODY'
-$pluginInfo = $this->pluginList->getNext($this->subjectType, '%methodName%');
-if (!$pluginInfo) {
- %return% parent::%methodName%(%parameters%);
-} else {
- %return% $this->___callPlugins('%methodName%', func_get_args(), $pluginInfo);
-}
+$pluginInfo = $this->pluginList->getNext($this->subjectType, '%method%');
+%return%$pluginInfo ? $this->___callPlugins('%method%', func_get_args(), $pluginInfo) : parent::%method%(%parameters%);
METHOD_BODY
),
'returnType' => $returnTypeValue,
@@ -206,11 +192,7 @@ protected function _validateData()
if ($resultClassName !== $sourceClassName . '\\Interceptor') {
$this->_addError(
- 'Invalid Interceptor class name [' .
- $resultClassName .
- ']. Use ' .
- $sourceClassName .
- '\\Interceptor'
+ 'Invalid Interceptor class name ' . $resultClassName . '. Use ' . $sourceClassName . '\\Interceptor'
);
$result = false;
}
diff --git a/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php b/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php
index 4609fe09f1f0d..b67af21878c3d 100644
--- a/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php
+++ b/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php
@@ -5,30 +5,32 @@
*/
namespace Magento\Framework\Interception\Code;
+use Magento\Framework\Code\Reader\ArgumentsReader;
use Magento\Framework\Exception\ValidatorException;
use Magento\Framework\Phrase;
+/**
+ * @SuppressWarnings(PHPMD.NPathComplexity)
+ */
class InterfaceValidator
{
- const METHOD_BEFORE = 'before';
-
- const METHOD_AROUND = 'around';
-
- const METHOD_AFTER = 'after';
+ public const METHOD_BEFORE = 'before';
+ public const METHOD_AROUND = 'around';
+ public const METHOD_AFTER = 'after';
/**
* Arguments reader model
*
- * @var \Magento\Framework\Code\Reader\ArgumentsReader
+ * @var ArgumentsReader
*/
protected $_argumentsReader;
/**
- * @param \Magento\Framework\Code\Reader\ArgumentsReader $argumentsReader
+ * @param ArgumentsReader $argumentsReader
*/
- public function __construct(\Magento\Framework\Code\Reader\ArgumentsReader $argumentsReader = null)
+ public function __construct(ArgumentsReader $argumentsReader = null)
{
- $this->_argumentsReader = $argumentsReader ?: new \Magento\Framework\Code\Reader\ArgumentsReader();
+ $this->_argumentsReader = $argumentsReader ?? new ArgumentsReader();
}
/**
@@ -50,7 +52,7 @@ public function validate($pluginClass, $interceptedType)
$type = new \ReflectionClass($interceptedType);
foreach ($plugin->getMethods(\ReflectionMethod::IS_PUBLIC) as $pluginMethod) {
- /** @var $pluginMethod \ReflectionMethod */
+ /** @var \ReflectionMethod $pluginMethod */
$originMethodName = $this->getOriginMethodName($pluginMethod->getName());
if ($originMethodName === null) {
continue;
@@ -63,19 +65,11 @@ public function validate($pluginClass, $interceptedType)
)
);
}
- $originMethod = $type->getMethod($originMethodName);
$pluginMethodParameters = $this->getMethodParameters($pluginMethod);
- $originMethodParameters = $this->getMethodParameters($originMethod);
-
- $methodType = $this->getMethodType($pluginMethod->getName());
-
$subject = array_shift($pluginMethodParameters);
- if (!$this->_argumentsReader->isCompatibleType(
- $subject['type'],
- $interceptedType
- ) || $subject['type'] === null
- ) {
+ if ($subject['type'] === null
+ || !$this->_argumentsReader->isCompatibleType($subject['type'], $interceptedType)) {
throw new ValidatorException(
new Phrase(
'Invalid [%1] $%2 type in %3::%4. It must be compatible with %5',
@@ -84,45 +78,50 @@ public function validate($pluginClass, $interceptedType)
);
}
- switch ($methodType) {
- case self::METHOD_BEFORE:
- $this->validateMethodsParameters(
- $pluginMethodParameters,
- $originMethodParameters,
- $pluginClass,
- $pluginMethod->getName()
- );
- break;
- case self::METHOD_AROUND:
- $proceed = array_shift($pluginMethodParameters);
- if (!$this->_argumentsReader->isCompatibleType($proceed['type'], '\\Closure')) {
- throw new ValidatorException(
- new Phrase(
- 'Invalid [%1] $%2 type in %3::%4. It must be compatible with \\Closure',
- [$proceed['type'], $proceed['name'], $pluginClass, $pluginMethod->getName()]
- )
- );
- }
- $this->validateMethodsParameters(
- $pluginMethodParameters,
- $originMethodParameters,
- $pluginClass,
- $pluginMethod->getName()
+ $originMethod = $type->getMethod($originMethodName);
+ $originMethodParameters = $this->getMethodParameters($originMethod);
+ $methodType = $this->getMethodType($pluginMethod->getName());
+
+ if (self::METHOD_AFTER === $methodType && count($pluginMethodParameters) > 1) {
+ // remove result
+ array_shift($pluginMethodParameters);
+ $matchedParameters = array_intersect_key($originMethodParameters, $pluginMethodParameters);
+ $this->validateMethodsParameters(
+ $pluginMethodParameters,
+ $matchedParameters,
+ $pluginClass,
+ $pluginMethod->getName()
+ );
+ continue;
+ }
+
+ if (self::METHOD_BEFORE === $methodType) {
+ $this->validateMethodsParameters(
+ $pluginMethodParameters,
+ $originMethodParameters,
+ $pluginClass,
+ $pluginMethod->getName()
+ );
+ continue;
+ }
+
+ if (self::METHOD_AROUND === $methodType) {
+ $proceed = array_shift($pluginMethodParameters);
+ if (!$this->_argumentsReader->isCompatibleType($proceed['type'], '\\Closure')) {
+ throw new ValidatorException(
+ new Phrase(
+ 'Invalid [%1] $%2 type in %3::%4. It must be compatible with \\Closure',
+ [$proceed['type'], $proceed['name'], $pluginClass, $pluginMethod->getName()]
+ )
);
- break;
- case self::METHOD_AFTER:
- if (count($pluginMethodParameters) > 1) {
- // remove result
- array_shift($pluginMethodParameters);
- $matchedParameters = array_intersect_key($originMethodParameters, $pluginMethodParameters);
- $this->validateMethodsParameters(
- $pluginMethodParameters,
- $matchedParameters,
- $pluginClass,
- $pluginMethod->getName()
- );
- }
- break;
+ }
+ $this->validateMethodsParameters(
+ $pluginMethodParameters,
+ $originMethodParameters,
+ $pluginClass,
+ $pluginMethod->getName()
+ );
+ continue;
}
}
}
@@ -170,8 +169,7 @@ protected function validateMethodsParameters(array $pluginParameters, array $ori
protected function getParametersType(\ReflectionParameter $parameter)
{
$parameterClass = $parameter->getClass();
- $type = $parameterClass ? '\\' . $parameterClass->getName() : ($parameter->isArray() ? 'array' : null);
- return $type;
+ return $parameterClass ? '\\' . $parameterClass->getName() : ($parameter->isArray() ? 'array' : null);
}
/**
@@ -183,17 +181,16 @@ protected function getParametersType(\ReflectionParameter $parameter)
*/
protected function getOriginMethodName($pluginMethodName)
{
- switch ($this->getMethodType($pluginMethodName)) {
- case self::METHOD_BEFORE:
- case self::METHOD_AROUND:
- return lcfirst(substr($pluginMethodName, 6));
+ $methodType = $this->getMethodType($pluginMethodName);
- case self::METHOD_AFTER:
- return lcfirst(substr($pluginMethodName, 5));
-
- default:
- return null;
+ if (self::METHOD_AFTER === $methodType) {
+ return lcfirst(substr($pluginMethodName, 5));
+ }
+ if (self::METHOD_BEFORE === $methodType || self::METHOD_AROUND === $methodType) {
+ return lcfirst(substr($pluginMethodName, 6));
}
+
+ return null;
}
/**
@@ -205,12 +202,14 @@ protected function getOriginMethodName($pluginMethodName)
*/
protected function getMethodType($pluginMethodName)
{
- if (substr($pluginMethodName, 0, 6) == self::METHOD_BEFORE) {
+ if (0 === strpos($pluginMethodName, self::METHOD_AFTER)) {
+ return self::METHOD_AFTER;
+ }
+ if (0 === strpos($pluginMethodName, self::METHOD_BEFORE)) {
return self::METHOD_BEFORE;
- } elseif (substr($pluginMethodName, 0, 6) == self::METHOD_AROUND) {
+ }
+ if (0 === strpos($pluginMethodName, self::METHOD_AROUND)) {
return self::METHOD_AROUND;
- } elseif (substr($pluginMethodName, 0, 5) == self::METHOD_AFTER) {
- return self::METHOD_AFTER;
}
return null;
diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/Interceptor.txt b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/Interceptor.txt
index fe9b4dad7022e..87646be998c0a 100644
--- a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/Interceptor.txt
+++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/Interceptor.txt
@@ -18,11 +18,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\Sample
public function getValue()
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'getValue');
- if (!$pluginInfo) {
- return parent::getValue();
- } else {
- return $this->___callPlugins('getValue', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('getValue', func_get_args(), $pluginInfo) : parent::getValue();
}
/**
@@ -31,11 +27,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\Sample
public function setValue($value)
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'setValue');
- if (!$pluginInfo) {
- return parent::setValue($value);
- } else {
- return $this->___callPlugins('setValue', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('setValue', func_get_args(), $pluginInfo) : parent::setValue($value);
}
/**
@@ -44,11 +36,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\Sample
public function & getReference()
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'getReference');
- if (!$pluginInfo) {
- return parent::getReference();
- } else {
- return $this->___callPlugins('getReference', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('getReference', func_get_args(), $pluginInfo) : parent::getReference();
}
/**
@@ -57,11 +45,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\Sample
public function firstVariadicParameter(... $variadicValue)
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'firstVariadicParameter');
- if (!$pluginInfo) {
- return parent::firstVariadicParameter(... $variadicValue);
- } else {
- return $this->___callPlugins('firstVariadicParameter', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('firstVariadicParameter', func_get_args(), $pluginInfo) : parent::firstVariadicParameter(... $variadicValue);
}
/**
@@ -70,11 +54,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\Sample
public function secondVariadicParameter($value, ... $variadicValue)
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'secondVariadicParameter');
- if (!$pluginInfo) {
- return parent::secondVariadicParameter($value, ... $variadicValue);
- } else {
- return $this->___callPlugins('secondVariadicParameter', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('secondVariadicParameter', func_get_args(), $pluginInfo) : parent::secondVariadicParameter($value, ... $variadicValue);
}
/**
@@ -83,10 +63,6 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\Sample
public function byRefVariadic(&... $variadicValue)
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'byRefVariadic');
- if (!$pluginInfo) {
- return parent::byRefVariadic(... $variadicValue);
- } else {
- return $this->___callPlugins('byRefVariadic', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('byRefVariadic', func_get_args(), $pluginInfo) : parent::byRefVariadic(... $variadicValue);
}
}
diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/TInterceptor.txt b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/TInterceptor.txt
index 71ea5b0475cfc..5ff09d204c5ef 100644
--- a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/TInterceptor.txt
+++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/_files/TInterceptor.txt
@@ -18,11 +18,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\TSample
public function returnVoid() : void
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'returnVoid');
- if (!$pluginInfo) {
- parent::returnVoid();
- } else {
- $this->___callPlugins('returnVoid', func_get_args(), $pluginInfo);
- }
+ $pluginInfo ? $this->___callPlugins('returnVoid', func_get_args(), $pluginInfo) : parent::returnVoid();
}
/**
@@ -31,11 +27,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\TSample
public function getNullableValue() : ?string
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'getNullableValue');
- if (!$pluginInfo) {
- return parent::getNullableValue();
- } else {
- return $this->___callPlugins('getNullableValue', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('getNullableValue', func_get_args(), $pluginInfo) : parent::getNullableValue();
}
/**
@@ -44,11 +36,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\TSample
public function getValue() : string
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'getValue');
- if (!$pluginInfo) {
- return parent::getValue();
- } else {
- return $this->___callPlugins('getValue', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('getValue', func_get_args(), $pluginInfo) : parent::getValue();
}
/**
@@ -57,11 +45,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\TSample
public function setValue(string $value)
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'setValue');
- if (!$pluginInfo) {
- return parent::setValue($value);
- } else {
- return $this->___callPlugins('setValue', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('setValue', func_get_args(), $pluginInfo) : parent::setValue($value);
}
/**
@@ -70,11 +54,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\TSample
public function typeHintedFirstVariadicParameter(string ... $variadicValue)
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'typeHintedFirstVariadicParameter');
- if (!$pluginInfo) {
- return parent::typeHintedFirstVariadicParameter(... $variadicValue);
- } else {
- return $this->___callPlugins('typeHintedFirstVariadicParameter', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('typeHintedFirstVariadicParameter', func_get_args(), $pluginInfo) : parent::typeHintedFirstVariadicParameter(... $variadicValue);
}
/**
@@ -83,11 +63,7 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\TSample
public function typeHintedSecondVariadicParameter(string $value, string ... $variadicValue)
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'typeHintedSecondVariadicParameter');
- if (!$pluginInfo) {
- return parent::typeHintedSecondVariadicParameter($value, ... $variadicValue);
- } else {
- return $this->___callPlugins('typeHintedSecondVariadicParameter', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('typeHintedSecondVariadicParameter', func_get_args(), $pluginInfo) : parent::typeHintedSecondVariadicParameter($value, ... $variadicValue);
}
/**
@@ -96,10 +72,6 @@ class Interceptor extends \Magento\Framework\Interception\Code\Generator\TSample
public function byRefTypeHintedVariadic(string &... $variadicValue)
{
$pluginInfo = $this->pluginList->getNext($this->subjectType, 'byRefTypeHintedVariadic');
- if (!$pluginInfo) {
- return parent::byRefTypeHintedVariadic(... $variadicValue);
- } else {
- return $this->___callPlugins('byRefTypeHintedVariadic', func_get_args(), $pluginInfo);
- }
+ return $pluginInfo ? $this->___callPlugins('byRefTypeHintedVariadic', func_get_args(), $pluginInfo) : parent::byRefTypeHintedVariadic(... $variadicValue);
}
}
diff --git a/lib/web/mage/gallery/gallery.js b/lib/web/mage/gallery/gallery.js
index 02ba72f64127b..6309fa267ea93 100644
--- a/lib/web/mage/gallery/gallery.js
+++ b/lib/web/mage/gallery/gallery.js
@@ -270,7 +270,10 @@ define([
next: $t('Next'),
previous: $t('Previous')
}),
- mainImageIndex;
+ mainImageIndex,
+ $element = settings.$element,
+ $fotoramaElement,
+ $fotoramaStage;
if (settings.breakpoints) {
_.each(_.values(settings.breakpoints), function (breakpoint) {
@@ -285,19 +288,38 @@ define([
settings.breakpoints = breakpoints;
}
- _.extend(config, config.options);
- config.options = undefined;
-
- config.click = false;
- config.breakpoints = null;
+ _.extend(config, config.options,
+ {
+ options: undefined,
+ click: false,
+ breakpoints: null
+ }
+ );
settings.currentConfig = config;
- settings.$element.css('min-height', settings.$element.height());
- settings.$element.html(tpl);
- settings.$element.removeClass('_block-content-loading');
- settings.$elementF = $(settings.$element.children()[0]);
- settings.$elementF.fotorama(config);
- settings.$element.css('min-height', '');
- settings.fotoramaApi = settings.$elementF.data('fotorama');
+
+ $element
+ .css('min-height', settings.$element.height())
+ .append(tpl);
+
+ $fotoramaElement = $element.find('[data-gallery-role="gallery"]');
+
+ $fotoramaStage = $fotoramaElement.find('.fotorama__stage');
+ $fotoramaStage.css('position', 'absolute');
+
+ $fotoramaElement.fotorama(config);
+ $fotoramaElement.find('.fotorama__stage__frame.fotorama__active')
+ .one('f:load', function () {
+ // Remove placeholder when main gallery image loads.
+ $element.find('.gallery-placeholder__image').remove();
+ $element
+ .removeClass('_block-content-loading')
+ .css('min-height', '');
+
+ $fotoramaStage.css('position', '');
+ });
+ settings.$elementF = $fotoramaElement;
+ settings.fotoramaApi = $fotoramaElement.data('fotorama');
+
$.extend(true, config, this.startConfig);
mainImageIndex = getMainImageIndex(config.data);
diff --git a/lib/web/mage/gallery/gallery.less b/lib/web/mage/gallery/gallery.less
index 10fba50fe239b..86ccdb858bf19 100644
--- a/lib/web/mage/gallery/gallery.less
+++ b/lib/web/mage/gallery/gallery.less
@@ -395,6 +395,11 @@
position: absolute;
top: 0;
width: @fotorama-arw-size;
+
+ ._block-content-loading & {
+ opacity: 0;
+ }
+
.fotorama__arr__arr {
&:extend(.fotorama-sprite);
.fotorama-abs-center();
diff --git a/lib/web/mage/polyfill.js b/lib/web/mage/polyfill.js
index 94232b29404fa..478b6544bd379 100644
--- a/lib/web/mage/polyfill.js
+++ b/lib/web/mage/polyfill.js
@@ -1,19 +1,21 @@
-try {
- if (!window.localStorage || !window.sessionStorage) {
- throw new Error();
- }
+(function (root, doc) {
+ 'use strict';
+
+ var Storage;
- localStorage.setItem('storage_test', 1);
- localStorage.removeItem('storage_test');
-} catch (e) {
- (function () {
- 'use strict';
+ try {
+ if (!root.localStorage || !root.sessionStorage) {
+ throw new Error();
+ }
+ localStorage.setItem('storage_test', 1);
+ localStorage.removeItem('storage_test');
+ } catch (e) {
/**
* Returns a storage object to shim local or sessionStorage
* @param {String} type - either 'local' or 'session'
*/
- var Storage = function (type) {
+ Storage = function (type) {
var data;
/**
@@ -32,7 +34,7 @@ try {
} else {
expires = '';
}
- document.cookie = name + '=' + value + expires + '; path=/';
+ doc.cookie = name + '=' + value + expires + '; path=/';
}
/**
@@ -41,7 +43,7 @@ try {
*/
function readCookie(name) {
var nameEQ = name + '=',
- ca = document.cookie.split(';'),
+ ca = doc.cookie.split(';'),
i = 0,
c;
@@ -70,11 +72,11 @@ try {
return 'localstorage';
}
- if (!window.name) {
- window.name = new Date().getTime();
+ if (!root.name) {
+ root.name = new Date().getTime();
}
- return 'sessionStorage' + window.name;
+ return 'sessionStorage' + root.name;
}
/**
@@ -170,7 +172,7 @@ try {
};
};
- window.localStorage.prototype = window.localStorage = new Storage('local');
- window.sessionStorage.prototype = window.sessionStorage = new Storage('session');
- })();
-}
+ root.localStorage.prototype = root.localStorage = new Storage('local');
+ root.sessionStorage.prototype = root.sessionStorage = new Storage('session');
+ }
+})(window, document);
diff --git a/lib/web/mage/requirejs/mixins.js b/lib/web/mage/requirejs/mixins.js
index 613605038f4b9..cb5ee8e462054 100644
--- a/lib/web/mage/requirejs/mixins.js
+++ b/lib/web/mage/requirejs/mixins.js
@@ -232,9 +232,12 @@ require([
* from it every time require call happens.
*/
defContext.defQueue.shift = function () {
- var queueItem = Array.prototype.shift.call(this);
+ var queueItem = Array.prototype.shift.call(this),
+ lastDeps = queueItem && queueItem[1];
- queueItem[1] = processNames(queueItem[1], defContext);
+ if (Array.isArray(lastDeps)) {
+ queueItem[1] = processNames(queueItem[1], defContext);
+ }
return queueItem;
};