diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml index 1438958b92b6..730df90b31be 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml @@ -24,6 +24,10 @@ + + + + diff --git a/app/code/Magento/CatalogInventory/Test/Mftf/ActionGroup/AdminAssertDisabledQtyActionGroup.xml b/app/code/Magento/CatalogInventory/Test/Mftf/ActionGroup/AdminAssertDisabledQtyActionGroup.xml new file mode 100644 index 000000000000..27c4a93577a0 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Test/Mftf/ActionGroup/AdminAssertDisabledQtyActionGroup.xml @@ -0,0 +1,19 @@ + + + + + + + Goes to the 'Quantity' field and assert disabled attribute. + + + + + + diff --git a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php index da465f5bdd3d..789befcfec8b 100644 --- a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php +++ b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php @@ -1,11 +1,10 @@ meta = $this->arrayManager->merge( $fieldsetPath . '/children', $this->meta, - ['container_quantity_and_stock_status_qty' => $container] + ['quantity_and_stock_status_qty' => $container] ); } } diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml index 7d5cecee9290..20b71608cd03 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml @@ -20,7 +20,7 @@ - + diff --git a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurableQty.php b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurableQty.php index 7d337c57d7e7..055891ff79c6 100644 --- a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurableQty.php +++ b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurableQty.php @@ -3,9 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\ConfigurableProduct\Ui\DataProvider\Product\Form\Modifier; use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; +use Magento\Catalog\Model\Locator\LocatorInterface; /** * Data provider for quantity in the Configurable products @@ -16,7 +19,22 @@ class ConfigurableQty extends AbstractModifier const CODE_QTY_CONTAINER = 'quantity_and_stock_status_qty'; /** - * {@inheritdoc} + * @var LocatorInterface + */ + private $locator; + + /** + * ConfigurableQty constructor + * + * @param LocatorInterface $locator + */ + public function __construct(LocatorInterface $locator) + { + $this->locator = $locator; + } + + /** + * @inheritdoc */ public function modifyData(array $data) { @@ -24,13 +42,14 @@ public function modifyData(array $data) } /** - * {@inheritdoc} + * @inheritdoc */ public function modifyMeta(array $meta) { if ($groupCode = $this->getGroupCodeByField($meta, self::CODE_QTY_CONTAINER)) { $parentChildren = &$meta[$groupCode]['children']; - if (!empty($parentChildren[self::CODE_QTY_CONTAINER])) { + $isConfigurable = $this->locator->getProduct()->getTypeId() === 'configurable'; + if (!empty($parentChildren[self::CODE_QTY_CONTAINER]) && $isConfigurable) { $parentChildren[self::CODE_QTY_CONTAINER] = array_replace_recursive( $parentChildren[self::CODE_QTY_CONTAINER], [ diff --git a/app/code/Magento/GiftMessage/Test/Mftf/Section/StorefrontCheckoutCartGiftMessageSection.xml b/app/code/Magento/GiftMessage/Test/Mftf/Section/StorefrontCheckoutCartGiftMessageSection.xml new file mode 100644 index 000000000000..b1f6f35ba5d9 --- /dev/null +++ b/app/code/Magento/GiftMessage/Test/Mftf/Section/StorefrontCheckoutCartGiftMessageSection.xml @@ -0,0 +1,12 @@ + + + +
+ +
+
\ No newline at end of file diff --git a/app/code/Magento/Multishipping/Block/Checkout/Shipping.php b/app/code/Magento/Multishipping/Block/Checkout/Shipping.php index 77981c736b9e..99450fc53807 100644 --- a/app/code/Magento/Multishipping/Block/Checkout/Shipping.php +++ b/app/code/Magento/Multishipping/Block/Checkout/Shipping.php @@ -3,10 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Multishipping\Block\Checkout; use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Quote\Model\Quote\Address; +use Magento\Store\Model\ScopeInterface; /** * Mustishipping checkout shipping @@ -67,6 +70,8 @@ public function getCheckout() } /** + * Add page title and prepare layout + * * @return $this */ protected function _prepareLayout() @@ -78,6 +83,8 @@ protected function _prepareLayout() } /** + * Retrieves addresses + * * @return Address[] */ public function getAddresses() @@ -86,6 +93,8 @@ public function getAddresses() } /** + * Returns count of addresses + * * @return mixed */ public function getAddressCount() @@ -99,6 +108,8 @@ public function getAddressCount() } /** + * Retrieves the address items + * * @param Address $address * @return \Magento\Framework\DataObject[] */ @@ -106,7 +117,7 @@ public function getAddressItems($address) { $items = []; foreach ($address->getAllItems() as $item) { - if ($item->getParentItemId()) { + if ($item->getParentItemId() || !$item->getQuoteItemId()) { continue; } $item->setQuoteItem($this->getCheckout()->getQuote()->getItemById($item->getQuoteItemId())); @@ -118,6 +129,8 @@ public function getAddressItems($address) } /** + * Retrieves the address shipping method + * * @param Address $address * @return mixed */ @@ -127,6 +140,8 @@ public function getAddressShippingMethod($address) } /** + * Retrieves address shipping rates + * * @param Address $address * @return mixed */ @@ -137,22 +152,20 @@ public function getShippingRates($address) } /** + * Retrieves the carrier name by the code + * * @param string $carrierCode * @return string */ public function getCarrierName($carrierCode) { - if ($name = $this->_scopeConfig->getValue( - 'carriers/' . $carrierCode . '/title', - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ) - ) { - return $name; - } - return $carrierCode; + $name = $this->_scopeConfig->getValue('carriers/' . $carrierCode . '/title', ScopeInterface::SCOPE_STORE); + return $name ?: $carrierCode; } /** + * Retrieves the address edit url + * * @param Address $address * @return string */ @@ -162,6 +175,8 @@ public function getAddressEditUrl($address) } /** + * Retrieves the url for items edition + * * @return string */ public function getItemsEditUrl() @@ -170,6 +185,8 @@ public function getItemsEditUrl() } /** + * Retrieves the url for the post action + * * @return string */ public function getPostActionUrl() @@ -178,6 +195,8 @@ public function getPostActionUrl() } /** + * Retrieves the back url + * * @return string */ public function getBackUrl() @@ -186,6 +205,8 @@ public function getBackUrl() } /** + * Returns converted and formatted price + * * @param Address $address * @param float $price * @param bool $flag @@ -202,7 +223,7 @@ public function getShippingPrice($address, $price, $flag) } /** - * Retrieve text for items box + * Retrieves text for items box * * @param \Magento\Framework\DataObject $addressEntity * @return string diff --git a/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php b/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php index 4ef36a7c8b6f..b450232395b8 100644 --- a/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php +++ b/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php @@ -3,34 +3,48 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Multishipping\Model\Cart\Controller; +use Magento\Checkout\Controller\Cart; +use Magento\Checkout\Model\Session; +use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Multishipping\Model\Checkout\Type\Multishipping\State; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Model\Quote; + +/** + * Cleans shipping addresses and item assignments after MultiShipping flow + */ class CartPlugin { /** - * @var \Magento\Quote\Api\CartRepositoryInterface + * @var CartRepositoryInterface */ private $cartRepository; /** - * @var \Magento\Checkout\Model\Session + * @var Session */ private $checkoutSession; /** - * @var \Magento\Customer\Api\AddressRepositoryInterface + * @var AddressRepositoryInterface */ private $addressRepository; /** - * @param \Magento\Quote\Api\CartRepositoryInterface $cartRepository - * @param \Magento\Checkout\Model\Session $checkoutSession - * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param CartRepositoryInterface $cartRepository + * @param Session $checkoutSession + * @param AddressRepositoryInterface $addressRepository */ public function __construct( - \Magento\Quote\Api\CartRepositoryInterface $cartRepository, - \Magento\Checkout\Model\Session $checkoutSession, - \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + CartRepositoryInterface $cartRepository, + Session $checkoutSession, + AddressRepositoryInterface $addressRepository ) { $this->cartRepository = $cartRepository; $this->checkoutSession = $checkoutSession; @@ -38,20 +52,19 @@ public function __construct( } /** - * @param \Magento\Checkout\Controller\Cart $subject - * @param \Magento\Framework\App\RequestInterface $request + * Cleans shipping addresses and item assignments after MultiShipping flow + * + * @param Cart $subject + * @param RequestInterface $request * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @throws LocalizedException */ - public function beforeDispatch( - \Magento\Checkout\Controller\Cart $subject, - \Magento\Framework\App\RequestInterface $request - ) { - /** @var \Magento\Quote\Model\Quote $quote */ + public function beforeDispatch(Cart $subject, RequestInterface $request) + { + /** @var Quote $quote */ $quote = $this->checkoutSession->getQuote(); - - // Clear shipping addresses and item assignments after MultiShipping flow - if ($quote->isMultipleShippingAddresses()) { + if ($quote->isMultipleShippingAddresses() && $this->isCheckoutComplete()) { foreach ($quote->getAllShippingAddresses() as $address) { $quote->removeAddress($address->getId()); } @@ -59,12 +72,20 @@ public function beforeDispatch( $shippingAddress = $quote->getShippingAddress(); $defaultShipping = $quote->getCustomer()->getDefaultShipping(); if ($defaultShipping) { - $defaultCustomerAddress = $this->addressRepository->getById( - $defaultShipping - ); + $defaultCustomerAddress = $this->addressRepository->getById($defaultShipping); $shippingAddress->importCustomerAddressData($defaultCustomerAddress); } $this->cartRepository->save($quote); } } + + /** + * Checks whether the checkout flow is complete + * + * @return bool + */ + private function isCheckoutComplete() : bool + { + return (bool) ($this->checkoutSession->getStepData(State::STEP_SHIPPING)['is_complete'] ?? true); + } } diff --git a/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontMultishippingCheckoutActionGroup.xml b/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontMultishippingCheckoutActionGroup.xml new file mode 100644 index 000000000000..c5dee010239d --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontMultishippingCheckoutActionGroup.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection.xml b/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection.xml index dddf26683164..e6f328249371 100644 --- a/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection.xml +++ b/app/code/Magento/Multishipping/Test/Mftf/Section/MultishippingSection.xml @@ -16,10 +16,17 @@
+
+
+ + + + +
diff --git a/app/code/Magento/Multishipping/Test/Mftf/Section/StorefrontCheckoutShippingMultipleAddressesSection.xml b/app/code/Magento/Multishipping/Test/Mftf/Section/StorefrontCheckoutShippingMultipleAddressesSection.xml new file mode 100644 index 000000000000..34427bda9334 --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Mftf/Section/StorefrontCheckoutShippingMultipleAddressesSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontProcessMultishippingCheckoutWhenCartPageIsOpenedInAnotherTabTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontProcessMultishippingCheckoutWhenCartPageIsOpenedInAnotherTabTest.xml new file mode 100644 index 000000000000..fd79d4d954cd --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontProcessMultishippingCheckoutWhenCartPageIsOpenedInAnotherTabTest.xml @@ -0,0 +1,117 @@ + + + + + + + + + + <description value="Process multishipping checkout when Cart page is opened in another tab"/> + <severity value="MAJOR"/> + <testCaseId value="MC-17871"/> + <useCaseId value="MC-17469"/> + <group value="multishipping"/> + </annotations> + <before> + <!-- Login as Admin --> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <!-- Set configurations --> + <magentoCLI command="config:set multishipping/options/checkout_multiple 1" stepKey="allowShippingToMultipleAddresses"/> + <!-- Create two simple products --> + <createData entity="ApiCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createFirstProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="_defaultProduct" stepKey="createSecondProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="Simple_US_Customer_Multiple_Addresses" stepKey="createCustomerWithMultipleAddresses"/> + </before> + <after> + <!-- Delete created data --> + <actionGroup ref="logout" stepKey="logout"/> + <deleteData createDataKey="createFirstProduct" stepKey="deleteFirstProduct"/> + <deleteData createDataKey="createSecondProduct" stepKey="deleteSecondProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createCustomerWithMultipleAddresses" stepKey="deleteCustomer"/> + </after> + <!-- Login to the Storefront as created customer --> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginAsCustomer"> + <argument name="Customer" value="$$createCustomerWithMultipleAddresses$$"/> + </actionGroup> + <!-- Add two products to the Shopping Cart --> + <amOnPage url="{{StorefrontProductPage.url($$createFirstProduct.name$$)}}" stepKey="amOnStorefrontProductFirstPage"/> + <waitForPageLoad stepKey="waitForTheFirstProduct"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddProductToCart"> + <argument name="product" value="$$createFirstProduct$$"/> + <argument name="productCount" value="1"/> + </actionGroup> + <amOnPage url="{{StorefrontProductPage.url($$createSecondProduct.name$$)}}" stepKey="amOnStorefrontSecondProductPage"/> + <waitForPageLoad stepKey="waitForPageLoadForTheSecondProduct"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddSecondProductToCart"> + <argument name="product" value="$$createSecondProduct$$"/> + <argument name="productCount" value="2"/> + </actionGroup> + <amOnPage url="{{CheckoutCartPage.url}}" stepKey="amOnShoppingCartPage"/> + <!-- Click 'Check Out with Multiple Addresses' --> + <waitForPageLoad stepKey="waitForSecondPageLoad"/> + <actionGroup ref="StorefrontGoCheckoutWithMultipleAddresses" stepKey="goCheckoutWithMultipleAddresses"/> + <!-- Select different addresses and click 'Go to Shipping Information' --> + <actionGroup ref="StorefrontCheckoutShippingSelectMultipleAddressesActionGroup" stepKey="selectMultipleAddresses"> + <argument name="firstAddress" value="{{UK_Not_Default_Address.street[0]}}"/> + <argument name="secondAddress" value="{{US_Address_NY.street[1]}}"/> + </actionGroup> + <waitForPageLoad stepKey="waitPageLoad"/> + <!-- Open the Cart page in another browser window and go back --> + <openNewTab stepKey="openNewTab"/> + <amOnPage url="{{CheckoutCartPage.url}}" stepKey="amOnShoppingCartPageNewTab"/> + <actionGroup ref="AssertStorefrontCheckoutCartItemsActionGroup" stepKey="assertFirstProductItemInCheckOutCart"> + <argument name="productName" value="$$createFirstProduct.name$$"/> + <argument name="productSku" value="$$createFirstProduct.sku$$"/> + <argument name="productPrice" value="$$createFirstProduct.price$$"/> + <argument name="subtotal" value="$$createFirstProduct.price$$" /> + <argument name="qty" value="1"/> + </actionGroup> + <actionGroup ref="AssertStorefrontCheckoutCartItemsActionGroup" stepKey="assertSecondProductItemInCheckOutCart"> + <argument name="productName" value="$$createSecondProduct.name$$"/> + <argument name="productSku" value="$$createSecondProduct.sku$$"/> + <argument name="productPrice" value="$$createSecondProduct.price$$"/> + <argument name="subtotal" value="$$createSecondProduct.price$$" /> + <argument name="qty" value="1"/> + </actionGroup> + <switchToNextTab stepKey="switchToNextTab"/> + <!-- Click 'Continue to Billing Information' and 'Go to Review Your Order' --> + <actionGroup ref="StorefrontGoToBillingInformationActionGroup" stepKey="goToBillingInformation"/> + <see selector="{{ShipmentFormSection.shippingAddress}}" userInput="{{US_Address_NY.city}}" stepKey="seeBillingAddress"/> + <waitForElementVisible selector="{{StorefrontMultipleShippingMethodSection.goToReviewYourOrderButton}}" stepKey="waitForGoToReviewYourOrderVisible" /> + <click selector="{{StorefrontMultipleShippingMethodSection.goToReviewYourOrderButton}}" stepKey="clickToGoToReviewYourOrderButton"/> + <!-- Click 'Place Order' --> + <actionGroup ref="PlaceOrderActionGroup" stepKey="placeOrder"/> + <see selector="{{StorefrontMultipleShippingMethodSection.successMessage}}" userInput="Successfully ordered" stepKey="seeSuccessMessage"/> + <grabTextFrom selector="{{StorefrontMultipleShippingMethodSection.orderId('1')}}" stepKey="grabFirstOrderId"/> + <grabTextFrom selector="{{StorefrontMultipleShippingMethodSection.orderId('2')}}" stepKey="grabSecondOrderId"/> + <!-- Go to My Account > My Orders --> + <amOnPage url="{{StorefrontCustomerOrdersHistoryPage.url}}" stepKey="goToMyOrdersPage"/> + <waitForPageLoad stepKey="waitForMyOrdersPageLoad"/> + <seeElement selector="{{StorefrontCustomerOrdersGridSection.orderView({$grabFirstOrderId})}}" stepKey="seeFirstOrder"/> + <seeElement selector="{{StorefrontCustomerOrdersGridSection.orderView({$grabSecondOrderId})}}" stepKey="seeSecondOrder"/> + <waitForPageLoad stepKey="waitForOrderPageLoad"/> + <!-- Go to Admin > Sales > Orders --> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> + <actionGroup ref="searchAdminDataGridByKeyword" stepKey="searchFirstOrder"> + <argument name="keyword" value="$grabFirstOrderId"/> + </actionGroup> + <seeElement selector="{{AdminOrdersGridSection.orderId({$grabFirstOrderId})}}" stepKey="seeAdminFirstOrder"/> + <actionGroup ref="searchAdminDataGridByKeyword" stepKey="searchSecondOrder"> + <argument name="keyword" value="$grabSecondOrderId"/> + </actionGroup> + <seeElement selector="{{AdminOrdersGridSection.orderId({$grabSecondOrderId})}}" stepKey="seeAdminSecondOrder"/> + </test> +</tests> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml index ace64cdaa103..a18ca0c41556 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml @@ -39,5 +39,6 @@ <element name="changeOrderStatus" type="button" selector="//div[contains(concat(' ',normalize-space(@class),' '),' row-gutter ')]//span[text()='{{status}}']" parameterized="true" timeout="30"/> <element name="viewLink" type="text" selector="//td/div[contains(.,'{{orderID}}')]/../..//a[@class='action-menu-item']" parameterized="true"/> <element name="selectOrderID" type="checkbox" selector="//td/div[text()='{{orderId}}']/../preceding-sibling::td//input" parameterized="true" timeout="60"/> + <element name="orderId" type="text" selector="//table[contains(@class, 'data-grid')]//div[contains(text(), '{{orderId}}')]" parameterized="true"/> </section> </sections> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml index 525e6b47374a..028dfc6d109e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml @@ -31,7 +31,7 @@ </category_ids> <quantity_and_stock_status composite="1"> <qty> - <selector>fieldset[data-index="container_quantity_and_stock_status_qty"] [name="product[quantity_and_stock_status][qty]"]</selector> + <selector>fieldset[data-index="quantity_and_stock_status_qty"] [name="product[quantity_and_stock_status][qty]"]</selector> </qty> <is_in_stock> <selector>[data-index="quantity_and_stock_status"] [name="product[quantity_and_stock_status][is_in_stock]"]</selector> diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_out_of_stock_without_categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_out_of_stock_without_categories.php new file mode 100644 index 000000000000..6ae4af61bc51 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_out_of_stock_without_categories.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\TestFramework\ObjectManager; + +Bootstrap::getInstance()->reinitialize(); + +/** @var ObjectManager $objectManager */ +$objectManager = Bootstrap::getObjectManager(); + +/** @var $product Product */ +$product = $objectManager->create(Product::class); +$product->isObjectNew(true); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setId(1) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('simple') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription('Short description') + ->setTaxClassId(0) + ->setDescription('Description with <b>html tag</b>') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 0, + 'is_qty_decimal' => 0, + 'is_in_stock' => 0, + ] + )->setCanSaveCustomOptions(true) + ->setHasOptions(true); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_out_of_stock_without_categories_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_out_of_stock_without_categories_rollback.php new file mode 100644 index 000000000000..4c858f322f8a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_out_of_stock_without_categories_rollback.php @@ -0,0 +1,8 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +include __DIR__ . '/product_simple_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_for_second_store.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_for_second_store.php new file mode 100644 index 000000000000..d8c56b7bf6f4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_for_second_store.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Customer\Api\CustomerRepositoryInterface; + +require __DIR__ . '/customer.php'; + +$objectManager = Bootstrap::getObjectManager(); +$repository = $objectManager->create(CustomerRepositoryInterface::class); +$customer = $repository->get('customer@example.com'); +$customer->setStoreId(2); +$repository->save($customer); diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_for_second_store_rollback.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_for_second_store_rollback.php new file mode 100644 index 000000000000..61cce9dbcc8d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_for_second_store_rollback.php @@ -0,0 +1,8 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +include __DIR__ . '/customer_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/Model/ObserverTest.php b/dev/tests/integration/testsuite/Magento/ProductAlert/Model/ObserverTest.php index 0fc98d8d8380..0f19edc349e8 100644 --- a/dev/tests/integration/testsuite/Magento/ProductAlert/Model/ObserverTest.php +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/Model/ObserverTest.php @@ -3,60 +3,122 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\ProductAlert\Model; +use Magento\Customer\Api\AccountManagementInterface; +use Magento\Customer\Model\Session; +use Magento\Framework\App\Area; +use Magento\Framework\Locale\Resolver; +use Magento\Framework\Module\Dir\Reader; +use Magento\Framework\Phrase; +use Magento\Framework\Phrase\Renderer\Translate as PhraseRendererTranslate; +use Magento\Framework\Phrase\RendererInterface; +use Magento\Framework\Translate; +use Magento\Store\Model\StoreRepository; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\CacheCleaner; +use Magento\TestFramework\Mail\Template\TransportBuilderMock; +use Magento\TestFramework\ObjectManager; + /** + * Test for Magento\ProductAlert\Model\Observer + * * @magentoAppIsolation enabled + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ObserverTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Framework\ObjectManagerInterface + * @var ObjectManager */ protected $_objectManager; /** - * @var \Magento\Customer\Model\Session + * @var Observer */ - protected $_customerSession; + private $observer; /** - * @var \Magento\Customer\Helper\View + * @var TransportBuilderMock */ - protected $_customerViewHelper; + private $transportBuilder; + /** + * @inheritDoc + */ public function setUp() { - $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->_customerSession = $this->_objectManager->get( - \Magento\Customer\Model\Session::class - ); - $service = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Customer\Api\AccountManagementInterface::class - ); + Bootstrap::getInstance()->loadArea(Area::AREA_FRONTEND); + $this->_objectManager = Bootstrap::getObjectManager(); + $this->observer = $this->_objectManager->get(Observer::class); + $this->transportBuilder = $this->_objectManager->get(TransportBuilderMock::class); + $service = $this->_objectManager->create(AccountManagementInterface::class); $customer = $service->authenticate('customer@example.com', 'password'); - $this->_customerSession->setCustomerDataAsLoggedIn($customer); - $this->_customerViewHelper = $this->_objectManager->create(\Magento\Customer\Helper\View::class); + $customerSession = $this->_objectManager->get(Session::class); + $customerSession->setCustomerDataAsLoggedIn($customer); } /** - * @magentoConfigFixture current_store catalog/productalert/allow_price 1 + * Test process() method * + * @magentoConfigFixture current_store catalog/productalert/allow_price 1 * @magentoDataFixture Magento/ProductAlert/_files/product_alert.php */ public function testProcess() { - \Magento\TestFramework\Helper\Bootstrap::getInstance()->loadArea(\Magento\Framework\App\Area::AREA_FRONTEND); - $observer = $this->_objectManager->get(\Magento\ProductAlert\Model\Observer::class); - $observer->process(); - - /** @var \Magento\TestFramework\Mail\Template\TransportBuilderMock $transportBuilder */ - $transportBuilder = $this->_objectManager->get( - \Magento\TestFramework\Mail\Template\TransportBuilderMock::class - ); + $this->observer->process(); $this->assertContains( 'John Smith,', - $transportBuilder->getSentMessage()->getRawMessage() + $this->transportBuilder->getSentMessage()->getRawMessage() ); } + + /** + * Check translations for product alerts + * + * @magentoDbIsolation enabled + * @magentoAppArea frontend + * @magentoConfigFixture current_store catalog/productalert/allow_price 1 + * @magentoDataFixture Magento/Store/_files/second_store.php + * @magentoConfigFixture fixture_second_store_store general/locale/code pt_BR + * @magentoDataFixture Magento/ProductAlert/_files/product_alert_with_store.php + */ + public function testProcessPortuguese() + { + // get second store + $storeRepository = $this->_objectManager->create(StoreRepository::class); + $secondStore = $storeRepository->get('fixture_second_store'); + + // check if Portuguese language is specified for the second store + CacheCleaner::cleanAll(); + $storeResolver = $this->_objectManager->get(Resolver::class); + $storeResolver->emulate($secondStore->getId()); + $this->assertEquals('pt_BR', $storeResolver->getLocale()); + + // set translation data and check it + $modulesReader = $this->createPartialMock(Reader::class, ['getModuleDir']); + $modulesReader->expects($this->any()) + ->method('getModuleDir') + ->willReturn(dirname(__DIR__) . '/_files/i18n'); + /** @var Translate $translator */ + $translator = $this->_objectManager->create(Translate::class, ['modulesReader' => $modulesReader]); + $translation = [ + 'Price change alert! We wanted you to know that prices have changed for these products:' => + 'Alerta de mudanca de preco! Queriamos que voce soubesse que os precos mudaram para esses produtos:' + ]; + $translator->loadData(); + $this->assertEquals($translation, $translator->getData()); + $this->_objectManager->addSharedInstance($translator, Translate::class); + $this->_objectManager->removeSharedInstance(PhraseRendererTranslate::class); + Phrase::setRenderer($this->_objectManager->create(RendererInterface::class)); + + // dispatch process() method and check sent message + $this->observer->process(); + $message = $this->transportBuilder->getSentMessage()->getRawMessage(); + $expectedText = array_shift($translation); + $this->assertContains('/frontend/Magento/luma/pt_BR/', $message); + $this->assertContains(substr($expectedText, 0, 50), $message); + } } diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/i18n/pt_BR.csv b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/i18n/pt_BR.csv new file mode 100644 index 000000000000..0c8218a78923 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/i18n/pt_BR.csv @@ -0,0 +1 @@ +"Price change alert! We wanted you to know that prices have changed for these products:","Alerta de mudanca de preco! Queriamos que voce soubesse que os precos mudaram para esses produtos:",Magento_ProductAlert diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_with_store.php b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_with_store.php new file mode 100644 index 000000000000..38f00d49f1d4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_with_store.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\ProductAlert\Model\Price; +use Magento\ProductAlert\Model\Stock; + +require __DIR__ . '/../../../Magento/Customer/_files/customer_for_second_store.php'; +require __DIR__ . '/../../../Magento/Catalog/_files/product_simple_out_of_stock_without_categories.php'; + +$objectManager = Bootstrap::getObjectManager(); +$price = $objectManager->create(Price::class); +$price->setCustomerId($customer->getId()) + ->setProductId($product->getId()) + ->setPrice($product->getPrice()+1) + ->setWebsiteId(1) + ->setStoreId(2); +$price->save(); + +$stock = $objectManager->create(Stock::class); +$stock->setCustomerId($customer->getId()) + ->setProductId($product->getId()) + ->setWebsiteId(1) + ->setStoreId(2); +$stock->save();