From b0aaa76cc3b577211401e9097b67eb3ea504e28a Mon Sep 17 00:00:00 2001 From: Arnob Saha Date: Sat, 7 Nov 2020 22:22:40 -0600 Subject: [PATCH 01/32] MC-38846: Custom address attributes are missing on checkout (Shipping address grid & Payment step) - Adding plugin to convert int to boolean --- .../frontend/web/js/model/address-converter.js | 15 +++++++++++++-- .../Model/Address/CustomAttributesProcessor.php | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js index a59ea7101f16c..d296999c88b53 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js @@ -27,7 +27,8 @@ define([ // clone address form data to new object var addressData = $.extend(true, {}, formData), region, - regionName = addressData.region; + regionName = addressData.region, + customAttributes; if (mageUtils.isObject(addressData.street)) { addressData.street = this.objectToArray(addressData.street); @@ -64,10 +65,20 @@ define([ addressData['custom_attributes'] = _.map( addressData['custom_attributes'], function (value, key) { - return { + customAttributes = { 'attribute_code': key, 'value': value }; + + if (typeof value === 'boolean') { + customAttributes = { + 'attribute_code': key, + 'value': value, + 'label': value === true ? 'Yes' : 'No' + }; + } + + return customAttributes; } ); } diff --git a/app/code/Magento/Customer/Model/Address/CustomAttributesProcessor.php b/app/code/Magento/Customer/Model/Address/CustomAttributesProcessor.php index d6e63e11ee453..0fd72a591899a 100644 --- a/app/code/Magento/Customer/Model/Address/CustomAttributesProcessor.php +++ b/app/code/Magento/Customer/Model/Address/CustomAttributesProcessor.php @@ -71,7 +71,7 @@ private function getAttributeLabels(array $customAttribute, string $customAttrib { $attributeOptionLabels = []; - if (!empty($customAttribute['value'])) { + if (isset($customAttribute['value']) && $customAttribute['value'] != null) { $customAttributeValues = explode(',', $customAttribute['value']); $attributeOptions = $this->attributeOptionManager->getItems( \Magento\Customer\Model\Indexer\Address\AttributeProvider::ENTITY, From 78f828567a008fc0a7c507457872219598a02af6 Mon Sep 17 00:00:00 2001 From: Buba Suma Date: Fri, 6 Nov 2020 17:17:16 -0600 Subject: [PATCH 02/32] MC-37729: Subtotal Cart Price Rule excludes product tax for fixed amount - Add "Subtotal (Incl. Tax)" to cart price rule condition - Add MFTF test --- .../Model/Rule/Condition/Address.php | 2 + .../Data/SalesRuleAddressConditionsData.xml | 1 + ...teCartPriceRuleWithSubtotalInclTaxTest.xml | 90 +++++++++++++++++++ .../Unit/Model/Rule/Condition/AddressTest.php | 65 ++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithSubtotalInclTaxTest.xml create mode 100644 app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/AddressTest.php diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Address.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Address.php index cf6301cb31a9c..62c1cc086048b 100644 --- a/app/code/Magento/SalesRule/Model/Rule/Condition/Address.php +++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Address.php @@ -62,6 +62,7 @@ public function loadAttributeOptions() { $attributes = [ 'base_subtotal_with_discount' => __('Subtotal (Excl. Tax)'), + 'base_subtotal_total_incl_tax' => __('Subtotal (Incl. Tax)'), 'base_subtotal' => __('Subtotal'), 'total_qty' => __('Total Items Quantity'), 'weight' => __('Total Weight'), @@ -99,6 +100,7 @@ public function getInputType() { switch ($this->getAttribute()) { case 'base_subtotal': + case 'base_subtotal_total_incl_tax': case 'weight': case 'total_qty': return 'numeric'; diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleAddressConditionsData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleAddressConditionsData.xml index cc695b347c4fb..727222213b118 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleAddressConditionsData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleAddressConditionsData.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> Magento\SalesRule\Model\Rule\Condition\Address|base_subtotal + Magento\SalesRule\Model\Rule\Condition\Address|base_subtotal_total_incl_tax Magento\SalesRule\Model\Rule\Condition\Address|total_qty Magento\SalesRule\Model\Rule\Condition\Address|weight Magento\SalesRule\Model\Rule\Condition\Address|shipping_method diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithSubtotalInclTaxTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithSubtotalInclTaxTest.xml new file mode 100644 index 0000000000000..a52e8e10459e5 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithSubtotalInclTaxTest.xml @@ -0,0 +1,90 @@ + + + + + + + + <description value="Test that cart price rule with Subtotal Incl Tax works correctly"/> + <severity value="CRITICAL"/> + <useCaseId value="MC-37729"/> + <testCaseId value="MC-38971"/> + <group value="SalesRule"/> + </annotations> + <before> + <!--Login to backend--> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <!--Create tax rate for US-CA-*--> + <createData entity="defaultTaxRate" stepKey="taxRate"/> + <!--Create tax rule--> + <actionGroup ref="AdminCreateTaxRuleActionGroup" stepKey="createTaxRule"> + <argument name="taxRate" value="$$taxRate$$"/> + <argument name="taxRule" value="SimpleTaxRule"/> + </actionGroup> + <!--Create simple product--> + <createData entity="SimpleProduct2" stepKey="product"> + <field key="price">100</field> + </createData> + <!--Create cart price rule with no coupon and 50% discount--> + <createData entity="ApiCartRule" stepKey="createCartPriceRule"/> + <!--Add "subtotal incl tax > 100" condition to cart price rule--> + <amOnPage url="{{AdminCartPriceRuleEditPage.url($$createCartPriceRule.rule_id$$)}}" stepKey="openEditRule"/> + <actionGroup ref="SetCartAttributeConditionForCartPriceRuleActionGroup" stepKey="setCartAttributeConditionForCartPriceRule"> + <argument name="attributeName" value="{{SalesRuleAddressConditions.base_subtotal_total_incl_tax}}"/> + <argument name="operatorType" value="greater than"/> + <argument name="value" value="100"/> + </actionGroup> + </before> + <after> + <!--Delete tax rule--> + <actionGroup ref="AdminDeleteTaxRule" stepKey="deleteTaxRule"> + <argument name="taxRuleCode" value="{{SimpleTaxRule.code}}" /> + </actionGroup> + <!--Delete tax rate--> + <deleteData createDataKey="taxRate" stepKey="deleteTaxRate"/> + <!--Delete product--> + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <!--Delete cart price rule--> + <deleteData createDataKey="createCartPriceRule" stepKey="deleteCartPriceRule"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <!--Open product --> + <actionGroup ref="StorefrontOpenProductEntityPageActionGroup" stepKey="openProduct2Page"> + <argument name="product" value="$$product$$"/> + </actionGroup> + <!--Add to cart --> + <actionGroup ref="StorefrontAddToTheCartActionGroup" stepKey="product2AddToCart"/> + <!--Click on mini cart--> + <actionGroup ref="StorefrontClickOnMiniCartActionGroup" stepKey="clickOnMiniCart"/> + <!--Click on view and edit cart link--> + <actionGroup ref="ClickViewAndEditCartFromMiniCartActionGroup" stepKey="goToShoppingCartFromMinicart"/> + <waitForPageLoad stepKey="waitForViewAndEditCartToOpen"/> + <!--Assert that tax and discount are not applied by default--> + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="AssertTaxAndDiscountIsNotApplied"> + <argument name="subtotal" value="$100.00"/> + <argument name="shipping" value="$5.00"/> + <argument name="shippingMethod" value="Flat Rate - Fixed"/> + <argument name="total" value="$105.00"/> + </actionGroup> + <dontSee selector="{{CheckoutCartSummarySection.discountAmount}}" stepKey="assertDiscountIsNotApplied"/> + <!--Open "Estimate Shipping and Tax" section and fill US-CA address --> + <actionGroup ref="StorefrontCartEstimateShippingAndTaxActionGroup" stepKey="fillEstimateShippingAndTaxSection"> + <argument name="estimateAddress" value="EstimateAddressCalifornia"/> + </actionGroup> + <!--Assert that tax and discount are applied by to total amount--> + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="AssertTaxAndDiscountIsApplied"> + <argument name="subtotal" value="$100.00"/> + <argument name="shipping" value="$5.00"/> + <argument name="shippingMethod" value="Flat Rate - Fixed"/> + <argument name="total" value="$60.00"/> + </actionGroup> + <see selector="{{CheckoutCartSummarySection.discountAmount}}" userInput="-$50.00" stepKey="assertDiscountIsApplied"/> + </test> +</tests> diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/AddressTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/AddressTest.php new file mode 100644 index 0000000000000..70036c06922c5 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/AddressTest.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\SalesRule\Test\Unit\Model\Rule\Condition; + +use Magento\SalesRule\Model\Rule\Condition\Address; +use PHPUnit\Framework\TestCase; + +/** + * Test for address rule condition + */ +class AddressTest extends TestCase +{ + /** + * @var Address + */ + private $model; + + /** + * @inheritDoc + */ + protected function setUp(): void + { + parent::setUp(); + $context = $this->createMock(\Magento\Rule\Model\Condition\Context::class); + $directoryCountry = $this->createMock(\Magento\Directory\Model\Config\Source\Country::class); + $directoryAllregion = $this->createMock(\Magento\Directory\Model\Config\Source\Allregion::class); + $shippingAllmethods = $this->createMock(\Magento\Shipping\Model\Config\Source\Allmethods::class); + $paymentAllmethods = $this->createMock(\Magento\Payment\Model\Config\Source\Allmethods::class); + $this->model = new Address( + $context, + $directoryCountry, + $directoryAllregion, + $shippingAllmethods, + $paymentAllmethods + ); + } + + /** + * Test that all attributes are present in options list + */ + public function testLoadAttributeOptions(): void + { + $attributes = [ + 'base_subtotal_with_discount', + 'base_subtotal_total_incl_tax', + 'base_subtotal', + 'total_qty', + 'weight', + 'payment_method', + 'shipping_method', + 'postcode', + 'region', + 'region_id', + 'country_id', + ]; + + $this->model->loadAttributeOptions(); + $this->assertEquals($attributes, array_keys($this->model->getAttributeOption())); + } +} From 55172bfd643757335ddc79723527ee4f20a3b449 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Wed, 11 Nov 2020 13:22:04 -0600 Subject: [PATCH 03/32] MC-38746: Performance degradation due to multiple calls of /guest-carts/{cart_id}/totals-information endpoint - Reverted #18700 PR that causes redundant calls of totals-information web-api --- .../view/frontend/web/js/model/cart/estimate-service.js | 1 - .../frontend/js/model/cart/estimate-service.test.js | 7 ------- 2 files changed, 8 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/estimate-service.js b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/estimate-service.js index fd12eed76ed50..71e6c39b4e319 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/estimate-service.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/estimate-service.js @@ -80,5 +80,4 @@ define([ quote.shippingAddress.subscribe(estimateTotalsAndUpdateRates); quote.shippingMethod.subscribe(estimateTotalsShipping); quote.billingAddress.subscribe(estimateTotalsBilling); - customerData.get('cart').subscribe(estimateTotalsShipping); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/estimate-service.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/estimate-service.test.js index ce9c98c9d2560..3d8325a3ecd54 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/estimate-service.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/estimate-service.test.js @@ -150,12 +150,5 @@ define([ }); expect(mocks['Magento_Checkout/js/model/cart/totals-processor/default'].estimateTotals).toHaveBeenCalled(); }); - - it('test subscribe when cart data was changed', function () { - mocks['Magento_Customer/js/customer-data'].get('cart')({ - dataId: 2 - }); - expect(mocks['Magento_Checkout/js/model/cart/totals-processor/default'].estimateTotals).toHaveBeenCalled(); - }); }); }); From f6bb0228a30f9c12059cce724a522257d6f50d14 Mon Sep 17 00:00:00 2001 From: Arnob Saha <arnobsh@gmail.com> Date: Thu, 12 Nov 2020 11:04:04 -0600 Subject: [PATCH 04/32] MC-38915: Unable to change Customer Group on new customers created via an admin order when Enable Automatic Assignment to Customer Group is enabled - Updating group_id based on the vat validation on customer --- .../Observer/AfterAddressSaveObserver.php | 11 +- .../Observer/AfterAddressSaveObserverTest.php | 2 +- .../Adminhtml/Order/Create/Form/Account.php | 84 ++++++++--- .../Order/Create/Form/AccountTest.php | 137 +++++++++++++++++- 4 files changed, 202 insertions(+), 32 deletions(-) diff --git a/app/code/Magento/Customer/Observer/AfterAddressSaveObserver.php b/app/code/Magento/Customer/Observer/AfterAddressSaveObserver.php index af0a04827d30f..33290306e4843 100644 --- a/app/code/Magento/Customer/Observer/AfterAddressSaveObserver.php +++ b/app/code/Magento/Customer/Observer/AfterAddressSaveObserver.php @@ -141,7 +141,8 @@ public function execute(Observer $observer) if ($customerAddress->getVatId() == '' || !$this->_customerVat->isCountryInEU($customerAddress->getCountry()) ) { - $defaultGroupId = $this->_groupManagement->getDefaultGroup($customer->getStore())->getId(); + $defaultGroupId = $customer->getGroupId() ? $customer->getGroupId() : + $this->_groupManagement->getDefaultGroup($customer->getStore())->getId(); if (!$customer->getDisableAutoGroupChange() && $customer->getGroupId() != $defaultGroupId) { $customer->setGroupId($defaultGroupId); $customer->save(); @@ -216,8 +217,8 @@ protected function _canProcessAddress($address) protected function _isDefaultBilling($address) { return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultBilling() - || $address->getIsPrimaryBilling() - || $address->getIsDefaultBilling(); + || $address->getIsPrimaryBilling() + || $address->getIsDefaultBilling(); } /** @@ -229,8 +230,8 @@ protected function _isDefaultBilling($address) protected function _isDefaultShipping($address) { return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultShipping() - || $address->getIsPrimaryShipping() - || $address->getIsDefaultShipping(); + || $address->getIsPrimaryShipping() + || $address->getIsDefaultShipping(); } /** diff --git a/app/code/Magento/Customer/Test/Unit/Observer/AfterAddressSaveObserverTest.php b/app/code/Magento/Customer/Test/Unit/Observer/AfterAddressSaveObserverTest.php index f72cbbc281e90..146cecb09351f 100644 --- a/app/code/Magento/Customer/Test/Unit/Observer/AfterAddressSaveObserverTest.php +++ b/app/code/Magento/Customer/Test/Unit/Observer/AfterAddressSaveObserverTest.php @@ -341,7 +341,7 @@ public function testAfterAddressSaveDefaultGroup( $customer->expects($this->once()) ->method('getDisableAutoGroupChange') ->willReturn(false); - $customer->expects($this->once()) + $customer->expects($this->exactly(2)) ->method('getGroupId') ->willReturn(null); $customer->expects($this->once()) diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php index e6a209b541198..9bb71d837cade 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php @@ -6,11 +6,24 @@ namespace Magento\Sales\Block\Adminhtml\Order\Create\Form; +use Magento\Backend\Block\Template\Context; +use Magento\Backend\Model\Session\Quote; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterface; use Magento\Customer\Api\GroupManagementInterface; +use Magento\Customer\Model\Metadata\Form; use Magento\Framework\Api\ExtensibleDataObjectConverter; use Magento\Framework\App\ObjectManager; use Magento\Framework\Data\Form\Element\AbstractElement; +use Magento\Framework\Data\FormFactory; +use Magento\Customer\Model\Metadata\FormFactory as MetadataFormFactory; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Phrase; use Magento\Framework\Pricing\PriceCurrencyInterface; +use Magento\Framework\Reflection\DataObjectProcessor; +use Magento\Sales\Model\AdminOrder\Create; +use Magento\Store\Model\ScopeInterface; /** * Create order account form @@ -25,46 +38,48 @@ class Account extends AbstractForm /** * Metadata form factory * - * @var \Magento\Customer\Model\Metadata\FormFactory + * @var MetadataFormFactory */ protected $_metadataFormFactory; /** * Customer repository * - * @var \Magento\Customer\Api\CustomerRepositoryInterface + * @var CustomerRepositoryInterface */ protected $customerRepository; /** - * @var \Magento\Framework\Api\ExtensibleDataObjectConverter + * @var ExtensibleDataObjectConverter */ protected $_extensibleDataObjectConverter; + private const XML_PATH_EMAIL_REQUIRED_CREATE_ORDER = 'customer/create_account/email_required_create_order'; + /** - * @param \Magento\Backend\Block\Template\Context $context - * @param \Magento\Backend\Model\Session\Quote $sessionQuote - * @param \Magento\Sales\Model\AdminOrder\Create $orderCreate + * @param Context $context + * @param Quote $sessionQuote + * @param Create $orderCreate * @param PriceCurrencyInterface $priceCurrency - * @param \Magento\Framework\Data\FormFactory $formFactory - * @param \Magento\Framework\Reflection\DataObjectProcessor $dataObjectProcessor - * @param \Magento\Customer\Model\Metadata\FormFactory $metadataFormFactory - * @param \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository + * @param FormFactory $formFactory + * @param DataObjectProcessor $dataObjectProcessor + * @param MetadataFormFactory $metadataFormFactory + * @param CustomerRepositoryInterface $customerRepository * @param ExtensibleDataObjectConverter $extensibleDataObjectConverter * @param array $data * @param GroupManagementInterface|null $groupManagement * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( - \Magento\Backend\Block\Template\Context $context, - \Magento\Backend\Model\Session\Quote $sessionQuote, - \Magento\Sales\Model\AdminOrder\Create $orderCreate, + Context $context, + Quote $sessionQuote, + Create $orderCreate, PriceCurrencyInterface $priceCurrency, - \Magento\Framework\Data\FormFactory $formFactory, - \Magento\Framework\Reflection\DataObjectProcessor $dataObjectProcessor, - \Magento\Customer\Model\Metadata\FormFactory $metadataFormFactory, - \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, - \Magento\Framework\Api\ExtensibleDataObjectConverter $extensibleDataObjectConverter, + FormFactory $formFactory, + DataObjectProcessor $dataObjectProcessor, + MetadataFormFactory $metadataFormFactory, + CustomerRepositoryInterface $customerRepository, + ExtensibleDataObjectConverter $extensibleDataObjectConverter, array $data = [], ?GroupManagementInterface $groupManagement = null ) { @@ -103,7 +118,7 @@ public function getHeaderCssClass() /** * Return header text * - * @return \Magento\Framework\Phrase + * @return Phrase */ public function getHeaderText() { @@ -114,10 +129,12 @@ public function getHeaderText() * Prepare Form and add elements to form * * @return $this + * @throws LocalizedException + * @throws NoSuchEntityException */ protected function _prepareForm() { - /** @var \Magento\Customer\Model\Metadata\Form $customerForm */ + /** @var Form $customerForm */ $customerForm = $this->_metadataFormFactory->create('customer', 'adminhtml_checkout'); // prepare customer attributes to show @@ -170,6 +187,8 @@ protected function _addAdditionalFormElementData(AbstractElement $element) * Return Form Elements values * * @return array + * @throws LocalizedException + * @throws NoSuchEntityException */ public function getFormValues() { @@ -183,7 +202,7 @@ public function getFormValues() ? $this->_extensibleDataObjectConverter->toFlatArray( $customer, [], - \Magento\Customer\Api\Data\CustomerInterface::class + CustomerInterface::class ) : []; foreach ($this->getQuote()->getData() as $key => $value) { @@ -193,7 +212,7 @@ public function getFormValues() } if (array_key_exists('group_id', $data) && empty($data['group_id'])) { - $data['group_id'] = $this->groupManagement->getDefaultGroup($this->getQuote()->getStoreId())->getId(); + $data['group_id'] = $this->getSelectedGroupId(); } if ($this->getQuote()->getCustomerEmail()) { @@ -208,6 +227,8 @@ public function getFormValues() * * @param array $attributes * @return array + * @throws LocalizedException + * @throws NoSuchEntityException */ private function extractValuesFromAttributes(array $attributes): array { @@ -231,7 +252,24 @@ private function isEmailRequiredToCreateOrder() { return $this->_scopeConfig->getValue( self::XML_PATH_EMAIL_REQUIRED_CREATE_ORDER, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ScopeInterface::SCOPE_STORE ); } + + /** + * Retrieve selected group id + * + * @return string + * @throws LocalizedException + * @throws NoSuchEntityException + */ + private function getSelectedGroupId(): string + { + $selectedGroupId = $this->groupManagement->getDefaultGroup($this->getQuote()->getStoreId())->getId(); + $orderDetails = $this->getRequest()->getParam('order'); + if (!empty($orderDetails) && !empty($orderDetails['account']['group_id'])) { + $selectedGroupId = $orderDetails['account']['group_id']; + } + return $selectedGroupId; + } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Form/AccountTest.php b/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Form/AccountTest.php index 861559acd8c20..b7e3ffcf9cd9d 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Form/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Form/AccountTest.php @@ -9,6 +9,7 @@ namespace Magento\Sales\Block\Adminhtml\Order\Create\Form; +use Magento\Backend\Block\Template\Context; use Magento\Backend\Model\Session\Quote as SessionQuote; use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Customer\Api\Data\AttributeMetadataInterface; @@ -17,6 +18,7 @@ use Magento\Customer\Model\Data\Option; use Magento\Customer\Model\Metadata\Form; use Magento\Customer\Model\Metadata\FormFactory; +use Magento\Framework\App\RequestInterface as Request; use Magento\Framework\View\LayoutInterface; use Magento\Quote\Model\Quote; use Magento\Store\Model\StoreManagerInterface; @@ -107,7 +109,7 @@ public function testGetFormWithCustomer() ); } - self::assertRegExp( + self::assertMatchesRegularExpression( '/<option value="'.$customerGroup.'".*?selected="selected"\>Wholesale\<\/option\>/is', $content, 'The Customer Group specified for the chosen customer should be selected.' @@ -150,13 +152,13 @@ public function testGetFormWithUserDefinedAttribute() $form->setUseContainer(true); $content = $form->toHtml(); - self::assertRegExp( + self::assertMatchesRegularExpression( '/\<option value="1".*?selected="selected"\>Yes\<\/option\>/is', $content, 'Default value for user defined custom attribute should be selected.' ); - self::assertRegExp( + self::assertMatchesRegularExpression( '/<option value="3".*?selected="selected"\>Retailer\<\/option\>/is', $content, 'The Customer Group specified for the chosen store should be selected.' @@ -203,6 +205,135 @@ public function testGetFormWithDefaultCustomerGroup() ); } + /** + * Test for get form with customer group based on vat id validation + * + * @dataProvider getDataForVatValidatedCustomer + * @param int $defaultCustomerGroupId + * @param int $vatValidatedCustomerGroupId + * @param array $customerDetails + * @param array $orderDetails + * @return void + */ + public function testGetFormWithVatValidatedCustomerGroup( + int $defaultCustomerGroupId, + int $vatValidatedCustomerGroupId, + array $customerDetails, + array $orderDetails + ): void { + $contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $requestMock = $this->getMockBuilder(Request::class) + ->getMockForAbstractClass(); + $contextMock->expects($this->once()) + ->method('getRequest') + ->willReturn($requestMock); + $requestMock->expects($this->any()) + ->method('getParam') + ->willReturn($orderDetails); + + $quote = $this->objectManager->create(Quote::class); + $quote->setCustomerGroupId($defaultCustomerGroupId); + $quote->setData($customerDetails); + + $this->session = $this->getMockBuilder(SessionQuote::class) + ->disableOriginalConstructor() + ->setMethods(['getCustomerId', 'getQuote']) + ->getMock(); + $this->session->method('getQuote') + ->willReturn($quote); + $this->session->method('getCustomerId') + ->willReturn($customerDetails['customer_id']); + + $formFactory = $this->getFormFactoryMock(); + $this->objectManager->addSharedInstance($formFactory, FormFactory::class); + + /** @var LayoutInterface $layout */ + $layout = $this->objectManager->get(LayoutInterface::class); + $accountBlock = $layout->createBlock( + Account::class, + 'address_block' . rand(), + [ + 'context' => $contextMock, + 'sessionQuote' => $this->session + ] + ); + + $form = $accountBlock->getForm(); + + self::assertEquals( + $vatValidatedCustomerGroupId, + $form->getElement('group_id')->getValue(), + 'The Customer Group specified for the chosen customer should be selected.' + ); + } + + /** + * Data provider for vat validated customer group id + * + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getDataForVatValidatedCustomer(): array + { + return [ + 'Validated customer group id when its set in quote' => [ + 'defaultCustomerGroupId' => 0, + 'vatValidatedCustomerGroupId' => 3, + 'customerDetails' => [ + 'entity_id' => '35', + 'store_id' => 1, + 'created_at' => '2020-11-09 01:03:35', + 'updated_at' => '2020-11-09 05:44:07', + 'customer_id' => 1, + 'customer_tax_class_id' => '3', + 'customer_group_id' => 3, + 'customer_email' => 'test@test.com', + 'customer_prefix' => null, + 'customer_firstname' => null, + 'customer_middlename' => null, + 'customer_lastname' => null, + 'customer_suffix' => null, + 'customer_dob' => null, + ], + 'orderDetails' => [ + 'account' => [ + 'group_id' => 3, + 'email' => 'test@test.com' + ] + ] + ], + 'Validated customer group id when its set in request' => [ + 'defaultCustomerGroupId' => 0, + 'vatValidatedCustomerGroupId' => 3, + 'customerDetails' => [ + 'entity_id' => '35', + 'store_id' => 1, + 'created_at' => '2020-11-09 01:03:35', + 'updated_at' => '2020-11-09 05:44:07', + 'customer_id' => 1, + 'customer_tax_class_id' => '3', + 'customer_group_id' => null, + 'customer_email' => 'test@test.com', + 'customer_prefix' => null, + 'customer_firstname' => null, + 'customer_middlename' => null, + 'customer_lastname' => null, + 'customer_suffix' => null, + 'customer_dob' => null, + ], + 'orderDetails' => [ + 'account' => [ + 'group_id' => 3, + 'email' => 'test@test.com' + ] + ] + ] + ]; + } + /** * Creates a mock for Form object. * From 94d21ef40b8636a73ab46b72d7ad521ab5a75907 Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Fri, 13 Nov 2020 00:22:57 -0600 Subject: [PATCH 05/32] MC-38576: Apply default quantity for Bundle product options when there is large amount of options - fixed - modified mftf test --- .../Mftf/Test/AdminAddBundleItemsTest.xml | 23 +++++++++++++++++++ .../web/js/components/bundle-option-qty.js | 20 +++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddBundleItemsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddBundleItemsTest.xml index 26119c5267d86..39d026ac74731 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddBundleItemsTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddBundleItemsTest.xml @@ -59,6 +59,18 @@ </actionGroup> <checkOption selector="{{AdminAddProductsToOptionPanel.firstCheckbox}}" stepKey="selectFirstGridRow2"/> <click selector="{{AdminAddProductsToOptionPanel.addSelectedProducts}}" stepKey="clickAddSelectedBundleProducts"/> + <!-- Check that Bundle Options initialized with default quantity --> + <grabValueFrom selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '0')}}" stepKey="grabbedFirstBundleOptionQuantity"/> + <assertEquals stepKey="assertFirstBundleOptionDefaultQuantity"> + <expectedResult type="string">1</expectedResult> + <actualResult type="string">$grabbedFirstBundleOptionQuantity</actualResult> + </assertEquals> + <grabValueFrom selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '1')}}" stepKey="grabbedSecondBundleOptionQuantity"/> + <assertEquals stepKey="assertSecondBundleOptionDefaultQuantity"> + <expectedResult type="string">1</expectedResult> + <actualResult type="string">$grabbedSecondBundleOptionQuantity</actualResult> + </assertEquals> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '0')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillProductDefaultQty1"/> <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '1')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillProductDefaultQty2"/> @@ -108,6 +120,17 @@ </actionGroup> <checkOption selector="{{AdminProductFormBundleSection.firstProductOption}}" stepKey="selectNewFirstGridRow2"/> <click selector="{{AdminAddProductsToOptionPanel.addSelectedProducts}}" stepKey="clickAddNewSelectedBundleProducts"/> + <!-- Check that existing Bundle Options do not loose user input quantity values --> + <grabValueFrom selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '0')}}" stepKey="grabbedFirstBundleOptionQuantityAfterUserInput"/> + <assertEquals stepKey="assertFirstBundleOptionDefaultQuantityAfterUserInput"> + <expectedResult type="string">{{BundleProduct.defaultQuantity}}</expectedResult> + <actualResult type="string">$grabbedFirstBundleOptionQuantityAfterUserInput</actualResult> + </assertEquals> + <grabValueFrom selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '1')}}" stepKey="grabbedSecondBundleOptionQuantityAfterUserInput"/> + <assertEquals stepKey="assertSecondBundleOptionDefaultQuantityAfterUserInput"> + <expectedResult type="string">{{BundleProduct.defaultQuantity}}</expectedResult> + <actualResult type="string">$grabbedSecondBundleOptionQuantityAfterUserInput</actualResult> + </assertEquals> <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '2')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillNewProductDefaultQty1"/> <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '3')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillNewProductDefaultQty2"/> diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js index e61def6e962a4..1190d96d03bc4 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js @@ -17,6 +17,25 @@ define([ } }, + /** + * + * @inheritdoc + */ + setInitialValue:function () { + this.initialValue = this.getInitialValue(); + if (this.initialValue === undefined || this.initialValue === '') { + this.initialValue = 1; + } + + if (this.value.peek() !== this.initialValue) { + this.value(this.initialValue); + } + + this.on('value', this.onUpdate.bind(this)); + this.isUseDefault(this.disabled()); + return this; + }, + /** * @inheritdoc */ @@ -33,6 +52,5 @@ define([ return !this.visible() ? false : notEqual; } - }); }); From ffba6aaa87dcef232bb8337d9bab03d63cbdab50 Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Fri, 13 Nov 2020 01:05:38 -0600 Subject: [PATCH 06/32] MC-38576 Apply default quantity for Bundle product options when there is large amount of options - fixed static test fail --- .../view/adminhtml/web/js/components/bundle-option-qty.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js index 1190d96d03bc4..8009e47426ffa 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js @@ -21,7 +21,7 @@ define([ * * @inheritdoc */ - setInitialValue:function () { + setInitialValue: function () { this.initialValue = this.getInitialValue(); if (this.initialValue === undefined || this.initialValue === '') { this.initialValue = 1; From 09b41aef042dbc2a37d4b9739eda008195185d73 Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Fri, 13 Nov 2020 01:09:51 -0600 Subject: [PATCH 07/32] MC-38576 Apply default quantity for Bundle product options when there is large amount of options - doc comment block --- .../Bundle/view/adminhtml/web/js/components/bundle-option-qty.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js index 8009e47426ffa..e430fecbb028a 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js @@ -18,7 +18,6 @@ define([ }, /** - * * @inheritdoc */ setInitialValue: function () { From c06db23994728390d6a7e60d9f6e7b2bbc86a315 Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Fri, 13 Nov 2020 01:56:30 -0600 Subject: [PATCH 08/32] MC-38576 Apply default quantity for Bundle product options when there is large amount of options - static failure new lines --- .../view/adminhtml/web/js/components/bundle-option-qty.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js index e430fecbb028a..5904b20a5dabe 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js @@ -22,6 +22,7 @@ define([ */ setInitialValue: function () { this.initialValue = this.getInitialValue(); + if (this.initialValue === undefined || this.initialValue === '') { this.initialValue = 1; } @@ -32,6 +33,7 @@ define([ this.on('value', this.onUpdate.bind(this)); this.isUseDefault(this.disabled()); + return this; }, From 17afad594c06cdbbf1ec9c6e8cf072775956426c Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Thu, 19 Nov 2020 12:04:47 +0200 Subject: [PATCH 09/32] MC-37502: Create automated test for "Move Order to Archive" --- ...order_with_invoice_shipment_creditmemo.php | 143 ++++++++++++++++++ ...h_invoice_shipment_creditmemo_rollback.php | 43 ++++++ 2 files changed, 186 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php new file mode 100644 index 0000000000000..4a2c28b3d0fd3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php @@ -0,0 +1,143 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Framework\DB\Transaction; +use Magento\Sales\Api\CreditmemoItemRepositoryInterface; +use Magento\Sales\Api\CreditmemoRepositoryInterface; +use Magento\Sales\Api\Data\CreditmemoItemInterfaceFactory; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\Data\OrderInterfaceFactory; +use Magento\Sales\Api\Data\OrderItemInterface; +use Magento\Sales\Api\Data\OrderPaymentInterfaceFactory; +use Magento\Sales\Api\InvoiceManagementInterface; +use Magento\Sales\Api\Data\OrderItemInterfaceFactory; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Address; +use Magento\Sales\Model\Order\AddressFactory; +use Magento\Sales\Api\Data\OrderAddressInterfaceFactory; +use Magento\Sales\Model\Order\Creditmemo; +use Magento\Sales\Model\Order\CreditmemoFactory; +use Magento\Sales\Model\Order\ShipmentFactory; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Sales/_files/default_rollback.php'); +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$productRepository->cleanCache(); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +/** @var InvoiceManagementInterface $invoiceService */ +$invoiceService = $objectManager->get(InvoiceManagementInterface::class); +/** @var ShipmentFactory $shipmentFactory */ +$shipmentFactory = $objectManager->get(ShipmentFactory::class); +/** @var CreditmemoFactory $creditmemoFactory */ +$creditmemoFactory = $objectManager->get(CreditmemoFactory::class); +/** @var CreditmemoItemInterfaceFactory $creditmemoItemFactory */ +$creditmemoItemFactory = $objectManager->get(CreditmemoItemInterfaceFactory::class); +/** @var CreditmemoRepositoryInterface $creditmemoRepository */ +$creditmemoRepository = $objectManager->get(CreditmemoRepositoryInterface::class); +/** @var CreditmemoItemRepositoryInterface $creditmemoItemRepository */ +$creditmemoItemRepository = $objectManager->get(CreditmemoItemRepositoryInterface::class); +$addressData = [ + AddressInterface::REGION => 'CA', + AddressInterface::REGION_ID => '12', + AddressInterface::POSTCODE => '11111', + AddressInterface::LASTNAME => 'lastname', + AddressInterface::FIRSTNAME => 'firstname', + AddressInterface::STREET => 'street', + AddressInterface::CITY => 'Los Angeles', + CustomerInterface::EMAIL => 'admin@example.com', + AddressInterface::TELEPHONE => '11111111', + AddressInterface::COUNTRY_ID => 'US' +]; +$product = $productRepository->get('simple'); +$addressFactory = $objectManager->get(AddressFactory::class); +$billingAddress = $addressFactory->create(['data' => $addressData]); +$billingAddress->setAddressType(Address::TYPE_BILLING); +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType(Address::TYPE_SHIPPING); +/** @var OrderPaymentInterfaceFactory $paymentFactory */ +$paymentFactory = $objectManager->get(OrderPaymentInterfaceFactory::class); +$payment = $paymentFactory->create(); +$payment->setMethod('checkmo') + ->setAdditionalInformation('last_trans_id', '11122') + ->setAdditionalInformation('metadata', ['type' => 'free', 'fraudulent' => false]); +/** @var OrderItemInterface $orderItem */ +$orderItem = $objectManager->get(OrderItemInterfaceFactory::class)->create(); +$orderItem->setProductId($product->getId()) + ->setQtyOrdered(2) + ->setBasePrice($product->getPrice()) + ->setPrice($product->getPrice()) + ->setRowTotal($product->getPrice()) + ->setProductType('simple') + ->setName($product->getName()) + ->setSku($product->getSku()) + ->setName('Test item'); +/** @var OrderInterface $order */ +$order = $objectManager->get(OrderInterfaceFactory::class)->create(); +$order->setIncrementId('100000001') + ->setState(Order::STATE_PROCESSING) + ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_PROCESSING)) + ->setSubtotal(100) + ->setGrandTotal(100) + ->setBaseSubtotal(100) + ->setBaseGrandTotal(100) + ->setOrderCurrencyCode('USD') + ->setBaseCurrencyCode('USD') + ->setCustomerIsGuest(true) + ->setCustomerEmail('customer@null.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->addItem($orderItem) + ->setPayment($payment); +$orderRepository->save($order); + +$invoice = $invoiceService->prepareInvoice($order); +$invoice->register(); +$invoice->setIncrementId($order->getIncrementId()); +$order = $invoice->getOrder(); +$order->setIsInProcess(true); +$transactionSave = $objectManager->create(Transaction::class); +$transactionSave->addObject($invoice)->addObject($order)->save(); + +$items = []; +foreach ($order->getItems() as $item) { + $items[$item->getId()] = $item->getQtyOrdered(); +} + +$shipment = $objectManager->get(ShipmentFactory::class)->create($order, $items); +$shipment->register(); +$shipment->setIncrementId($order->getIncrementId()); +$transactionSave = $objectManager->create(Transaction::class); +$transactionSave->addObject($shipment)->addObject($order)->save(); +/** @var CreditmemoFactory $creditmemoFactory */ +$creditmemoFactory = $objectManager->get(CreditmemoFactory::class); +$creditmemo = $creditmemoFactory->createByOrder($order, $order->getData()); +$creditmemo->setOrder($order); +$creditmemo->setState(Creditmemo::STATE_OPEN); +$creditmemo->setIncrementId($order->getIncrementId()); +$creditmemoRepository->save($creditmemo); + +$orderItem->setName('Test item') + ->setQtyRefunded(2) + ->setQtyInvoiced(2) + ->setOriginalPrice($product->getPrice()); +$creditItem = $creditmemoItemFactory->create(); +$creditItem->setCreditmemo($creditmemo) + ->setName('Creditmemo item') + ->setOrderItemId($orderItem->getId()) + ->setQty(2) + ->setPrice($product->getPrice()); +$creditmemoItemRepository->save($creditItem); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php new file mode 100644 index 0000000000000..56670ecc2a470 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Registry; +use Magento\Sales\Api\CreditmemoRepositoryInterface; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\Data\OrderInterfaceFactory; +use Magento\Sales\Api\InvoiceRepositoryInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Api\ShipmentRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +$objectManager = Bootstrap::getObjectManager(); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +/** @var InvoiceRepositoryInterface $invoiceRepository */ +$invoiceRepository = $objectManager->get(InvoiceRepositoryInterface::class); +/** @var ShipmentRepositoryInterface $shipmentRepository */ +$shipmentRepository = $objectManager->get(ShipmentRepositoryInterface::class); +/** @var CreditmemoRepositoryInterface $creditmemoRepository */ +$creditmemoRepository = $objectManager->get(CreditmemoRepositoryInterface::class); +/** @var OrderInterface $order */ +$order = $objectManager->get(OrderInterfaceFactory::class)->create()->loadByIncrementId('100000001'); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +foreach ($order->getInvoiceCollection() as $invoice) { + $invoiceRepository->delete($invoice); +} + +$orderRepository->delete($order); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php'); From 6d56b4d3609243147be73a89bdf3e74ccfede7fb Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Thu, 19 Nov 2020 13:19:33 +0200 Subject: [PATCH 10/32] MC-37500: Create automated test for "Shipment Sales Archive" --- .../Section/AdminShipmentsGridFiltersSection.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml new file mode 100644 index 0000000000000..6e5b197286bf3 --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminShipmentsGridFiltersSection"> + <element name="orderNum" type="input" selector="input[name='order_increment_id']"/> + </section> +</sections> From e6357812c2dc27d9c47dab42c422cf876a374b0a Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Thu, 19 Nov 2020 14:59:51 +0200 Subject: [PATCH 11/32] MC-37502: Create automated test for "Move Order to Archive" --- .../Sales/_files/order_with_invoice_shipment_creditmemo.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php index 4a2c28b3d0fd3..f84a8b65e13fd 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php @@ -9,6 +9,7 @@ use Magento\Customer\Api\Data\AddressInterface; use Magento\Customer\Api\Data\CustomerInterface; use Magento\Framework\DB\Transaction; +use Magento\OfflinePayments\Model\Checkmo; use Magento\Sales\Api\CreditmemoItemRepositoryInterface; use Magento\Sales\Api\CreditmemoRepositoryInterface; use Magento\Sales\Api\Data\CreditmemoItemInterfaceFactory; @@ -60,9 +61,10 @@ AddressInterface::CITY => 'Los Angeles', CustomerInterface::EMAIL => 'admin@example.com', AddressInterface::TELEPHONE => '11111111', - AddressInterface::COUNTRY_ID => 'US' + AddressInterface::COUNTRY_ID => 'US', ]; $product = $productRepository->get('simple'); +/** @var AddressFactory $addressFactory */ $addressFactory = $objectManager->get(AddressFactory::class); $billingAddress = $addressFactory->create(['data' => $addressData]); $billingAddress->setAddressType(Address::TYPE_BILLING); @@ -71,7 +73,7 @@ /** @var OrderPaymentInterfaceFactory $paymentFactory */ $paymentFactory = $objectManager->get(OrderPaymentInterfaceFactory::class); $payment = $paymentFactory->create(); -$payment->setMethod('checkmo') +$payment->setMethod(Checkmo::PAYMENT_METHOD_CHECKMO_CODE) ->setAdditionalInformation('last_trans_id', '11122') ->setAdditionalInformation('metadata', ['type' => 'free', 'fraudulent' => false]); /** @var OrderItemInterface $orderItem */ From 5b2ab2fdcff76aafec82935856fc2e2a45087777 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Fri, 20 Nov 2020 16:28:05 +0200 Subject: [PATCH 12/32] MC-37502: Create automated test for "Move Order to Archive" --- .../_files/order_with_invoice_shipment_creditmemo.php | 8 ++++++-- .../order_with_invoice_shipment_creditmemo_rollback.php | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php index f84a8b65e13fd..c95b21c1433bf 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo.php @@ -27,6 +27,7 @@ use Magento\Sales\Model\Order\Creditmemo; use Magento\Sales\Model\Order\CreditmemoFactory; use Magento\Sales\Model\Order\ShipmentFactory; +use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Workaround\Override\Fixture\Resolver; @@ -34,6 +35,8 @@ Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php'); $objectManager = Bootstrap::getObjectManager(); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); /** @var ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->get(ProductRepositoryInterface::class); $productRepository->cleanCache(); @@ -89,7 +92,7 @@ ->setName('Test item'); /** @var OrderInterface $order */ $order = $objectManager->get(OrderInterfaceFactory::class)->create(); -$order->setIncrementId('100000001') +$order->setIncrementId('100000111') ->setState(Order::STATE_PROCESSING) ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_PROCESSING)) ->setSubtotal(100) @@ -103,7 +106,8 @@ ->setBillingAddress($billingAddress) ->setShippingAddress($shippingAddress) ->addItem($orderItem) - ->setPayment($payment); + ->setPayment($payment) + ->setStoreId($storeManager->getStore('default')->getId()); $orderRepository->save($order); $invoice = $invoiceService->prepareInvoice($order); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php index 56670ecc2a470..f9330bc99ac14 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php @@ -40,4 +40,7 @@ $registry->unregister('isSecureArea'); $registry->register('isSecureArea', false); +$creditMemoGridAggregator = $objectManager->get(\CreditmemoGridAggregator::class); +$creditMemoGridAggregator->purge('100000111', 'order_increment_id'); + Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php'); From 1d3b89515cd95a1077fda05f91a96535d6b44809 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Fri, 20 Nov 2020 16:49:30 +0200 Subject: [PATCH 13/32] MC-37922: Html tag <br> visible in message --- .../ImportExport/Controller/Adminhtml/ImportResult.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php b/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php index 6da90efa4592c..86fae141d1470 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php @@ -69,12 +69,16 @@ protected function addErrorMessages( if ($errorAggregator->getErrorsCount()) { $message = ''; $counter = 0; + $unescapedMessages = []; foreach ($this->getErrorMessages($errorAggregator) as $error) { - $message .= (++$counter) . '. ' . $error . '<br>'; + $unescapedMessages[] = (++$counter) . '. ' . $error; if ($counter >= self::LIMIT_ERRORS_MESSAGE) { break; } } + foreach ($unescapedMessages as $unescapedMessage) { + $message .= $resultBlock->escapeHtml($unescapedMessage) . '<br>'; + } if ($errorAggregator->hasFatalExceptions()) { foreach ($this->getSystemExceptions($errorAggregator) as $error) { $message .= $error->getErrorMessage() @@ -90,7 +94,7 @@ protected function addErrorMessages( . '<a href="' . $this->createDownloadUrlImportHistoryFile($this->createErrorReport($errorAggregator)) . '">' . __('Download full report') . '</a><br>' - . '<div class="import-error-list">' . $resultBlock->escapeHtml($message) . '</div></div>' + . '<div class="import-error-list">' . $message . '</div></div>' ); } catch (\Exception $e) { foreach ($this->getErrorMessages($errorAggregator) as $errorMessage) { From 36debb3d05e13b07b27a057d8ea6a311f67a830e Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Sat, 21 Nov 2020 12:12:01 +0200 Subject: [PATCH 14/32] MC-37504: Create automated test for "Mass Action Archive Order" --- .../Magento/Sales/_files/order_closed.php | 148 ++++++++++++++++++ .../Sales/_files/order_closed_rollback.php | 46 ++++++ .../Magento/Sales/_files/order_complete.php | 116 ++++++++++++++ .../Sales/_files/order_complete_rollback.php | 40 +++++ .../_files/order_state_hold_rollback.php | 10 ++ 5 files changed, 360 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_closed.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_closed_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_complete.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_complete_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_state_hold_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed.php new file mode 100644 index 0000000000000..1708d89881592 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed.php @@ -0,0 +1,148 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Framework\DB\Transaction; +use Magento\OfflinePayments\Model\Checkmo; +use Magento\Sales\Api\CreditmemoItemRepositoryInterface; +use Magento\Sales\Api\CreditmemoRepositoryInterface; +use Magento\Sales\Api\Data\CreditmemoItemInterfaceFactory; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\Data\OrderInterfaceFactory; +use Magento\Sales\Api\Data\OrderItemInterface; +use Magento\Sales\Api\Data\OrderPaymentInterfaceFactory; +use Magento\Sales\Api\InvoiceManagementInterface; +use Magento\Sales\Api\Data\OrderItemInterfaceFactory; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Address; +use Magento\Sales\Model\Order\AddressFactory; +use Magento\Sales\Api\Data\OrderAddressInterfaceFactory; +use Magento\Sales\Model\Order\Creditmemo; +use Magento\Sales\Model\Order\CreditmemoFactory; +use Magento\Sales\Model\Order\ShipmentFactory; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$productRepository->cleanCache(); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +/** @var InvoiceManagementInterface $invoiceService */ +$invoiceService = $objectManager->get(InvoiceManagementInterface::class); +/** @var ShipmentFactory $shipmentFactory */ +$shipmentFactory = $objectManager->get(ShipmentFactory::class); +/** @var CreditmemoFactory $creditmemoFactory */ +$creditmemoFactory = $objectManager->get(CreditmemoFactory::class); +/** @var CreditmemoItemInterfaceFactory $creditmemoItemFactory */ +$creditmemoItemFactory = $objectManager->get(CreditmemoItemInterfaceFactory::class); +/** @var CreditmemoRepositoryInterface $creditmemoRepository */ +$creditmemoRepository = $objectManager->get(CreditmemoRepositoryInterface::class); +/** @var CreditmemoItemRepositoryInterface $creditmemoItemRepository */ +$creditmemoItemRepository = $objectManager->get(CreditmemoItemRepositoryInterface::class); +$addressData = [ + AddressInterface::REGION => 'CA', + AddressInterface::REGION_ID => '12', + AddressInterface::POSTCODE => '11111', + AddressInterface::LASTNAME => 'lastname', + AddressInterface::FIRSTNAME => 'firstname', + AddressInterface::STREET => 'street', + AddressInterface::CITY => 'Los Angeles', + CustomerInterface::EMAIL => 'admin@example.com', + AddressInterface::TELEPHONE => '11111111', + AddressInterface::COUNTRY_ID => 'US', +]; +$product = $productRepository->get('simple'); +/** @var AddressFactory $addressFactory */ +$addressFactory = $objectManager->get(AddressFactory::class); +$billingAddress = $addressFactory->create(['data' => $addressData]); +$billingAddress->setAddressType(Address::TYPE_BILLING); +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType(Address::TYPE_SHIPPING); +/** @var OrderPaymentInterfaceFactory $paymentFactory */ +$paymentFactory = $objectManager->get(OrderPaymentInterfaceFactory::class); +$payment = $paymentFactory->create(); +$payment->setMethod(Checkmo::PAYMENT_METHOD_CHECKMO_CODE) + ->setAdditionalInformation('last_trans_id', '11122') + ->setAdditionalInformation('metadata', ['type' => 'free', 'fraudulent' => false]); +/** @var OrderItemInterface $orderItem */ +$orderItem = $objectManager->get(OrderItemInterfaceFactory::class)->create(); +$orderItem->setProductId($product->getId()) + ->setQtyOrdered(2) + ->setBasePrice($product->getPrice()) + ->setPrice($product->getPrice()) + ->setRowTotal($product->getPrice()) + ->setProductType('simple') + ->setName($product->getName()) + ->setSku($product->getSku()) + ->setName('Test item'); +/** @var OrderInterface $order */ +$order = $objectManager->get(OrderInterfaceFactory::class)->create(); +$order->setIncrementId('100001111') + ->setState(Order::STATE_PROCESSING) + ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_PROCESSING)) + ->setSubtotal(100) + ->setGrandTotal(100) + ->setBaseSubtotal(100) + ->setBaseGrandTotal(100) + ->setOrderCurrencyCode('USD') + ->setBaseCurrencyCode('USD') + ->setCustomerIsGuest(true) + ->setCustomerEmail('customer@null.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->addItem($orderItem) + ->setPayment($payment) + ->setStoreId($storeManager->getStore('default')->getId()); +$orderRepository->save($order); + +$invoice = $invoiceService->prepareInvoice($order); +$invoice->register(); +$invoice->setIncrementId($order->getIncrementId()); +$order = $invoice->getOrder(); +$order->setIsInProcess(true); +$transactionSave = $objectManager->create(Transaction::class); +$transactionSave->addObject($invoice)->addObject($order)->save(); + +$items = []; +foreach ($order->getItems() as $item) { + $items[$item->getId()] = $item->getQtyOrdered(); +} + +$shipment = $objectManager->get(ShipmentFactory::class)->create($order, $items); +$shipment->register(); +$shipment->setIncrementId($order->getIncrementId()); +$transactionSave = $objectManager->create(Transaction::class); +$transactionSave->addObject($shipment)->addObject($order)->save(); +/** @var CreditmemoFactory $creditmemoFactory */ +$creditmemoFactory = $objectManager->get(CreditmemoFactory::class); +$creditmemo = $creditmemoFactory->createByOrder($order, $order->getData()); +$creditmemo->setOrder($order); +$creditmemo->setState(Creditmemo::STATE_OPEN); +$creditmemo->setIncrementId($order->getIncrementId()); +$creditmemoRepository->save($creditmemo); + +$orderItem->setName('Test item') + ->setQtyRefunded(2) + ->setQtyInvoiced(2) + ->setOriginalPrice($product->getPrice()); +$creditItem = $creditmemoItemFactory->create(); +$creditItem->setCreditmemo($creditmemo) + ->setName('Creditmemo item') + ->setOrderItemId($orderItem->getId()) + ->setQty(2) + ->setPrice($product->getPrice()); +$creditmemoItemRepository->save($creditItem); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed_rollback.php new file mode 100644 index 0000000000000..13263fd442713 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed_rollback.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Registry; +use Magento\Sales\Api\CreditmemoRepositoryInterface; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\Data\OrderInterfaceFactory; +use Magento\Sales\Api\InvoiceRepositoryInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Api\ShipmentRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +$objectManager = Bootstrap::getObjectManager(); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +/** @var InvoiceRepositoryInterface $invoiceRepository */ +$invoiceRepository = $objectManager->get(InvoiceRepositoryInterface::class); +/** @var ShipmentRepositoryInterface $shipmentRepository */ +$shipmentRepository = $objectManager->get(ShipmentRepositoryInterface::class); +/** @var CreditmemoRepositoryInterface $creditmemoRepository */ +$creditmemoRepository = $objectManager->get(CreditmemoRepositoryInterface::class); +/** @var OrderInterface $order */ +$order = $objectManager->get(OrderInterfaceFactory::class)->create()->loadByIncrementId('100001111'); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +foreach ($order->getInvoiceCollection() as $invoice) { + $invoiceRepository->delete($invoice); +} + +$orderRepository->delete($order); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +$creditMemoGridAggregator = $objectManager->get(\CreditmemoGridAggregator::class); +$creditMemoGridAggregator->purge('100000111', 'order_increment_id'); + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php'); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_complete.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_complete.php new file mode 100644 index 0000000000000..bb8f028b41380 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_complete.php @@ -0,0 +1,116 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Framework\DB\Transaction; +use Magento\OfflinePayments\Model\Checkmo; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\Data\OrderInterfaceFactory; +use Magento\Sales\Api\Data\OrderItemInterface; +use Magento\Sales\Api\Data\OrderPaymentInterfaceFactory; +use Magento\Sales\Api\InvoiceManagementInterface; +use Magento\Sales\Api\Data\OrderItemInterfaceFactory; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Address; +use Magento\Sales\Model\Order\AddressFactory; +use Magento\Sales\Model\Order\ShipmentFactory; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Sales/_files/default_rollback.php'); +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$productRepository->cleanCache(); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +/** @var InvoiceManagementInterface $invoiceService */ +$invoiceService = $objectManager->get(InvoiceManagementInterface::class); +/** @var ShipmentFactory $shipmentFactory */ +$shipmentFactory = $objectManager->get(ShipmentFactory::class); +$addressData = [ + AddressInterface::REGION => 'CA', + AddressInterface::REGION_ID => '12', + AddressInterface::POSTCODE => '11111', + AddressInterface::LASTNAME => 'lastname', + AddressInterface::FIRSTNAME => 'firstname', + AddressInterface::STREET => 'street', + AddressInterface::CITY => 'Los Angeles', + CustomerInterface::EMAIL => 'admin@example.com', + AddressInterface::TELEPHONE => '11111111', + AddressInterface::COUNTRY_ID => 'US', +]; +$product = $productRepository->get('simple'); +/** @var AddressFactory $addressFactory */ +$addressFactory = $objectManager->get(AddressFactory::class); +$billingAddress = $addressFactory->create(['data' => $addressData]); +$billingAddress->setAddressType(Address::TYPE_BILLING); +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType(Address::TYPE_SHIPPING); +/** @var OrderPaymentInterfaceFactory $paymentFactory */ +$paymentFactory = $objectManager->get(OrderPaymentInterfaceFactory::class); +$payment = $paymentFactory->create(); +$payment->setMethod(Checkmo::PAYMENT_METHOD_CHECKMO_CODE) + ->setAdditionalInformation('last_trans_id', '11122') + ->setAdditionalInformation('metadata', ['type' => 'free', 'fraudulent' => false]); +/** @var OrderItemInterface $orderItem */ +$orderItem = $objectManager->get(OrderItemInterfaceFactory::class)->create(); +$orderItem->setProductId($product->getId()) + ->setQtyOrdered(2) + ->setBasePrice($product->getPrice()) + ->setPrice($product->getPrice()) + ->setRowTotal($product->getPrice()) + ->setProductType('simple') + ->setName($product->getName()) + ->setSku($product->getSku()) + ->setName('Test item'); +/** @var OrderInterface $order */ +$order = $objectManager->get(OrderInterfaceFactory::class)->create(); +$order->setIncrementId('100000333') + ->setState(Order::STATE_PROCESSING) + ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_PROCESSING)) + ->setSubtotal(100) + ->setGrandTotal(100) + ->setBaseSubtotal(100) + ->setBaseGrandTotal(100) + ->setOrderCurrencyCode('USD') + ->setBaseCurrencyCode('USD') + ->setCustomerIsGuest(true) + ->setCustomerEmail('customer@null.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->addItem($orderItem) + ->setPayment($payment) + ->setStoreId($storeManager->getStore('default')->getId()); +$orderRepository->save($order); + +$invoice = $invoiceService->prepareInvoice($order); +$invoice->register(); +$invoice->setIncrementId($order->getIncrementId()); +$order = $invoice->getOrder(); +$order->setIsInProcess(true); +$transactionSave = $objectManager->create(Transaction::class); +$transactionSave->addObject($invoice)->addObject($order)->save(); + +$items = []; +foreach ($order->getItems() as $item) { + $items[$item->getId()] = $item->getQtyOrdered(); +} + +$shipment = $objectManager->get(ShipmentFactory::class)->create($order, $items); +$shipment->register(); +$shipment->setIncrementId($order->getIncrementId()); +$transactionSave = $objectManager->create(Transaction::class); +$transactionSave->addObject($shipment)->addObject($order)->save(); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_complete_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_complete_rollback.php new file mode 100644 index 0000000000000..06a36c16b90f7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_complete_rollback.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Registry; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\Data\OrderInterfaceFactory; +use Magento\Sales\Api\InvoiceRepositoryInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Api\ShipmentRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +$objectManager = Bootstrap::getObjectManager(); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +/** @var InvoiceRepositoryInterface $invoiceRepository */ +$invoiceRepository = $objectManager->get(InvoiceRepositoryInterface::class); +/** @var ShipmentRepositoryInterface $shipmentRepository */ +$shipmentRepository = $objectManager->get(ShipmentRepositoryInterface::class); +/** @var OrderInterface $order */ +$order = $objectManager->get(OrderInterfaceFactory::class)->create()->loadByIncrementId('100000333'); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +foreach ($order->getInvoiceCollection() as $invoice) { + $invoiceRepository->delete($invoice); +} + +$orderRepository->delete($order); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php'); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_state_hold_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_state_hold_rollback.php new file mode 100644 index 0000000000000..07d468289f5b4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_state_hold_rollback.php @@ -0,0 +1,10 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Sales/_files/order_rollback.php'); From 4508c482a2ea3116832679223245ae91e37a60f5 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Mon, 23 Nov 2020 11:36:32 +0200 Subject: [PATCH 15/32] MC-37502: Create automated test for "Move Order to Archive" --- .../_files/order_with_invoice_shipment_creditmemo_rollback.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php index f9330bc99ac14..123d44c4610d0 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_shipment_creditmemo_rollback.php @@ -25,7 +25,7 @@ /** @var CreditmemoRepositoryInterface $creditmemoRepository */ $creditmemoRepository = $objectManager->get(CreditmemoRepositoryInterface::class); /** @var OrderInterface $order */ -$order = $objectManager->get(OrderInterfaceFactory::class)->create()->loadByIncrementId('100000001'); +$order = $objectManager->get(OrderInterfaceFactory::class)->create()->loadByIncrementId('100000111'); /** @var Registry $registry */ $registry = $objectManager->get(Registry::class); $registry->unregister('isSecureArea'); From f4320523eaf3c59cd0fc61088f3a0d51170b90f4 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Mon, 23 Nov 2020 20:43:54 +0200 Subject: [PATCH 16/32] MC-37504: Create automated test for "Mass Action Archive Order" --- .../testsuite/Magento/Sales/_files/order_closed_rollback.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed_rollback.php index 13263fd442713..4567294cec0a6 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_closed_rollback.php @@ -41,6 +41,6 @@ $registry->register('isSecureArea', false); $creditMemoGridAggregator = $objectManager->get(\CreditmemoGridAggregator::class); -$creditMemoGridAggregator->purge('100000111', 'order_increment_id'); +$creditMemoGridAggregator->purge('100001111', 'order_increment_id'); Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php'); From 3f820e6a1662cc168163b3fb4f03eb2140beb3a8 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Tue, 24 Nov 2020 17:50:43 +0200 Subject: [PATCH 17/32] MC-37922: Html tag <br> visible in message --- .../Controller/Adminhtml/ImportResult.php | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php b/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php index 86fae141d1470..ed0bb3a7aa09f 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php @@ -9,6 +9,8 @@ use Magento\ImportExport\Model\Import\Entity\AbstractEntity; use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface; use Magento\ImportExport\Model\History as ModelHistory; +use Magento\Framework\Escaper; +use Magento\Framework\App\ObjectManager; /** * Import controller @@ -37,22 +39,31 @@ abstract class ImportResult extends Import */ protected $reportHelper; + /** + * @var Escaper|null + */ + protected $escaper; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\ImportExport\Model\Report\ReportProcessorInterface $reportProcessor * @param \Magento\ImportExport\Model\History $historyModel * @param \Magento\ImportExport\Helper\Report $reportHelper + * @param Escaper|null $escaper */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\ImportExport\Model\Report\ReportProcessorInterface $reportProcessor, \Magento\ImportExport\Model\History $historyModel, - \Magento\ImportExport\Helper\Report $reportHelper + \Magento\ImportExport\Helper\Report $reportHelper, + Escaper $escaper = null ) { parent::__construct($context); $this->reportProcessor = $reportProcessor; $this->historyModel = $historyModel; $this->reportHelper = $reportHelper; + $this->escaper = $escaper + ?? ObjectManager::getInstance()->get(Escaper::class); } /** @@ -69,22 +80,20 @@ protected function addErrorMessages( if ($errorAggregator->getErrorsCount()) { $message = ''; $counter = 0; - $unescapedMessages = []; + $escapedMessages = []; foreach ($this->getErrorMessages($errorAggregator) as $error) { - $unescapedMessages[] = (++$counter) . '. ' . $error; + $escapedMessages[] = (++$counter) . '. ' . $this->escaper->escapeHtml($error); if ($counter >= self::LIMIT_ERRORS_MESSAGE) { break; } } - foreach ($unescapedMessages as $unescapedMessage) { - $message .= $resultBlock->escapeHtml($unescapedMessage) . '<br>'; - } + $message .= implode('<br>', $escapedMessages); if ($errorAggregator->hasFatalExceptions()) { foreach ($this->getSystemExceptions($errorAggregator) as $error) { - $message .= $error->getErrorMessage() + $message .= $this->escaper->escapeHtml($error->getErrorMessage()) . ' <a href="#" onclick="$(this).next().show();$(this).hide();return false;">' . __('Show more') . '</a><div style="display:none;">' . __('Additional data') . ': ' - . $error->getErrorDescription() . '</div>'; + . $this->escaper->escapeHtml($error->getErrorDescription()) . '</div>'; } } try { From a07160eba32e4bd0431901f0b7c8171de2a663de Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 25 Nov 2020 00:15:56 +0200 Subject: [PATCH 18/32] MC-37500: Create automated test for "Shipment Sales Archive" --- app/code/Magento/Sales/Test/Mftf/Page/AdminShipmentPage.xml | 1 + .../Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename app/code/Magento/{Shipping => Sales}/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml (80%) diff --git a/app/code/Magento/Sales/Test/Mftf/Page/AdminShipmentPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/AdminShipmentPage.xml index d35a8ab5c4538..41d58bb61942a 100644 --- a/app/code/Magento/Sales/Test/Mftf/Page/AdminShipmentPage.xml +++ b/app/code/Magento/Sales/Test/Mftf/Page/AdminShipmentPage.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="AdminShipmentPage" url="sales/shipment/" area="admin" module="Magento_Sales"> <section name="AdminShipmentGridSection"/> + <section name="AdminShipmentsGridFiltersSection"/> </page> </pages> diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml similarity index 80% rename from app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml rename to app/code/Magento/Sales/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml index 6e5b197286bf3..ad1ec54e213ee 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminShipmentsGridFiltersSection.xml @@ -9,6 +9,6 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminShipmentsGridFiltersSection"> - <element name="orderNum" type="input" selector="input[name='order_increment_id']"/> + <element name="orderNumber" type="input" selector="input[name='order_increment_id']"/> </section> </sections> From db7cab675b788f3b9d55b1a6a79a2371b494ed34 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 25 Nov 2020 10:48:18 +0200 Subject: [PATCH 19/32] MC-37922: Html tag <br> visible in message --- .../ImportExport/Controller/Adminhtml/ImportResult.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php b/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php index ed0bb3a7aa09f..4092879e23622 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php @@ -87,16 +87,16 @@ protected function addErrorMessages( break; } } - $message .= implode('<br>', $escapedMessages); if ($errorAggregator->hasFatalExceptions()) { foreach ($this->getSystemExceptions($errorAggregator) as $error) { - $message .= $this->escaper->escapeHtml($error->getErrorMessage()) + $escapedMessages[] = $this->escaper->escapeHtml($error->getErrorMessage()) . ' <a href="#" onclick="$(this).next().show();$(this).hide();return false;">' . __('Show more') . '</a><div style="display:none;">' . __('Additional data') . ': ' . $this->escaper->escapeHtml($error->getErrorDescription()) . '</div>'; } } try { + $message .= implode('<br>', $escapedMessages); $resultBlock->addNotice( '<strong>' . __('Following Error(s) has been occurred during importing process:') . '</strong><br>' . '<div class="import-error-wrapper">' . __('Only the first 100 errors are shown. ') From 945f2bd9b74eb54238217629623124a10f55fa26 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 25 Nov 2020 12:12:17 +0200 Subject: [PATCH 20/32] MC-37922: Html tag <br> visible in message --- .../_files/invalid_catalog_products.csv | 3 + .../Controller/Adminhtml/ImportResultTest.php | 87 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/_files/invalid_catalog_products.csv create mode 100644 dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/ImportResultTest.php diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/_files/invalid_catalog_products.csv b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/_files/invalid_catalog_products.csv new file mode 100644 index 0000000000000..f873a7c89ee53 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/_files/invalid_catalog_products.csv @@ -0,0 +1,3 @@ +sku,_store,_attribute_set,product_type,categories,_product_websites,color,cost,country_of_manufacture,created_at,custom_design,custom_design_from,custom_design_to,custom_layout_update,description,gallery,gift_message_available,gift_wrapping_available,gift_wrapping_price,has_options,image,image_label,is_returnable,manufacturer,meta_description,meta_keyword,meta_title,minimal_price,msrp,msrp_display_actual_price_type,name,news_from_date,news_to_date,options_container,page_layout,price,quantity_and_stock_status,related_tgtr_position_behavior,related_tgtr_position_limit,required_options,short_description,small_image,small_image_label,special_from_date,special_price,special_to_date,status,tax_class_id,thumbnail,thumbnail_label,updated_at,upsell_tgtr_position_behavior,upsell_tgtr_position_limit,url_key,url_path,visibility,weight,qty,min_qty,use_config_min_qty,is_qty_decimal,backorders,use_config_backorders,min_sale_qty,use_config_min_sale_qty,max_sale_qty,use_config_max_sale_qty,is_in_stock,notify_stock_qty,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,_related_sku,_related_position,_crosssell_sku,_crosssell_position,_upsell_sku,_upsell_position,_tier_price_website,_tier_price_customer_group,_tier_price_qty,_tier_price_price,_media_attribute_id,_media_image,_media_label,_media_position,_media_is_disabled,_associated_sku,_associated_default_qty,_associated_position +"",,Default,simple,,base,,,,"2014-12-25 19:52:47",,,,,,,,,,0,,,"No",,"simple product 1 ","simple product 1","simple product 1",,,,"simple product 1",,,"Block after Info Column",,100.0000,"In Stock",,,0,,,,,,,1,2,,,"2014-12-25 19:52:47",,,simple-product-1,,"catalog, search",,123.0000,0.0000,1,0,0,1,1.0000,1,0.0000,1,1,,1,1,0,1,0.0000,1,0,0,1,,,,,,,,,,,,,,,,,, +"",,Default,simple,,base,,,,"2014-12-25 19:53:14",,,,,,,,,,0,,,"No",,"simple product 2 ","simple product 2","simple product 2",,,,"simple product 2",,,"Block after Info Column",,200.0000,"In Stock",,,0,,,,,,,1,2,,,"2014-12-25 19:53:14",,,simple-product-2,,"catalog, search",,234.0000,0.0000,1,0,0,1,1.0000,1,0.0000,1,1,,1,1,0,1,0.0000,1,0,0,1,,,,,,,,,,,,,,,,,, diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/ImportResultTest.php b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/ImportResultTest.php new file mode 100644 index 0000000000000..ccd9e29e90a18 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/ImportResultTest.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\ImportExport\Controller\Adminhtml; + +use Magento\Framework\Filesystem\DirectoryList; +use Magento\Framework\HTTP\Adapter\FileTransferFactory; +use Magento\ImportExport\Model\Import; +use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface; +use Magento\ImportExport\Controller\Adminhtml\Import\HttpFactoryMock; + +/** + * @magentoAppArea adminhtml + */ +class ImportResultTest extends \Magento\TestFramework\TestCase\AbstractBackendController +{ + /** + * @dataProvider validationDataProvider + * @param string $fileName + * @param string $mimeType + * @param string $delimiter + * @throws \Magento\Framework\Exception\FileSystemException + * @backupGlobals enabled + * @magentoDbIsolation enabled + * @SuppressWarnings(PHPMD.Superglobals) + */ + public function testAddErrorMessages(string $fileName, string $mimeType, string $delimiter): void + { + $validationStrategy = ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR; + + $this->getRequest()->setParam('isAjax', true); + $this->getRequest()->setMethod('POST'); + $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; + + /** @var $formKey \Magento\Framework\Data\Form\FormKey */ + $formKey = $this->_objectManager->get(\Magento\Framework\Data\Form\FormKey::class); + $this->getRequest()->setPostValue('form_key', $formKey->getFormKey()); + $this->getRequest()->setPostValue('entity', 'catalog_product'); + $this->getRequest()->setPostValue('behavior', 'append'); + $this->getRequest()->setPostValue(Import::FIELD_NAME_VALIDATION_STRATEGY, $validationStrategy); + $this->getRequest()->setPostValue(Import::FIELD_NAME_ALLOWED_ERROR_COUNT, 0); + $this->getRequest()->setPostValue('_import_field_separator', $delimiter); + + /** @var \Magento\TestFramework\App\Filesystem $filesystem */ + $filesystem = $this->_objectManager->get(\Magento\Framework\Filesystem::class); + $tmpDir = $filesystem->getDirectoryWrite(DirectoryList::SYS_TMP); + $subDir = str_replace('\\', '_', __CLASS__); + $tmpDir->create($subDir); + $target = $tmpDir->getAbsolutePath("{$subDir}/{$fileName}"); + copy(__DIR__ . "/Import/_files/{$fileName}", $target); + + $_FILES = [ + 'import_file' => [ + 'name' => $fileName, + 'type' => $mimeType, + 'tmp_name' => $target, + 'error' => 0, + 'size' => filesize($target) + ] + ]; + + $this->_objectManager->configure( + [ + 'preferences' => [FileTransferFactory::class => HttpFactoryMock::class] + ] + ); + + $this->dispatch('backend/admin/import/validate'); + $this->assertStringNotContainsString('<br>', $this->getResponse()->getBody()); + } + + /** + * @return array + */ + public function validationDataProvider(): array + { + return [ + [ + 'file_name' => 'invalid_catalog_products.csv', + 'mime-type' => 'text/csv', + 'delimiter' => ',', + ], + ]; + } +} From 90bc5df2b7d7de91c98603a5f9e720b02ba4d348 Mon Sep 17 00:00:00 2001 From: engcom-Kilo <mikola.malevanec@transoftgroup.com> Date: Wed, 18 Nov 2020 10:14:02 +0200 Subject: [PATCH 21/32] MC-33687: Fatal error if admin enters wrong values for some customer attribute and uploads file. --- .../Controller/Adminhtml/Index/Save.php | 33 +++--- .../DataProviderWithDefaultAddresses.php | 15 ++- .../Magento/Customer/Model/FileProcessor.php | 102 +++++++++++------- .../Customer/Model/Metadata/Form/Image.php | 14 +-- .../AdminFillCustomerMainDataActionGroup.xml | 26 +++++ .../Controller/Adminhtml/Index/SaveTest.php | 69 +++++++----- .../Test/Unit/Model/FileProcessorTest.php | 47 ++++---- 7 files changed, 189 insertions(+), 117 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFillCustomerMainDataActionGroup.xml diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php index 192a0f1362ecd..cc8531214c7da 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Customer\Controller\Adminhtml\Index; use Magento\Backend\App\Action\Context; @@ -40,6 +41,7 @@ use Magento\Framework\Math\Random; use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Framework\Registry; +use Magento\Framework\Validator\Exception; use Magento\Framework\View\Result\LayoutFactory; use Magento\Framework\View\Result\PageFactory; use Magento\Newsletter\Model\SubscriberFactory; @@ -243,10 +245,10 @@ protected function _extractData( /** * Saves default_billing and default_shipping flags for customer address * - * @deprecated 102.0.1 must be removed because addresses are save separately for now * @param array $addressIdList * @param array $extractedCustomerData * @return array + * @deprecated 102.0.1 must be removed because addresses are save separately for now */ protected function saveDefaultFlags(array $addressIdList, array &$extractedCustomerData) { @@ -286,9 +288,9 @@ protected function saveDefaultFlags(array $addressIdList, array &$extractedCusto /** * Reformat customer addresses data to be compatible with customer service interface * - * @deprecated 102.0.1 addresses are saved separately for now * @param array $extractedCustomerData * @return array + * @deprecated 102.0.1 addresses are saved separately for now */ protected function _extractCustomerAddressData(array &$extractedCustomerData) { @@ -318,6 +320,7 @@ public function execute() { $returnToEdit = false; $customerId = $this->getCurrentCustomerId(); + $customer = $this->customerDataFactory->create(); if ($this->getRequest()->getPostValue()) { try { @@ -335,8 +338,6 @@ public function execute() $customerData['id'] = $customerId; } - /** @var CustomerInterface $customer */ - $customer = $this->customerDataFactory->create(); $this->dataObjectHelper->populateWithArray( $customer, $customerData, @@ -353,7 +354,7 @@ public function execute() try { $this->customerAccountManagement->validateCustomerStoreIdByWebsiteId($customer); } catch (LocalizedException $exception) { - throw new LocalizedException(__("The Store View selected for sending Welcome email from". + throw new LocalizedException(__("The Store View selected for sending Welcome email from" . " is not related to the customer's associated website.")); } } @@ -361,7 +362,6 @@ public function execute() // Save customer if ($customerId) { $this->_customerRepository->save($customer); - $this->getEmailNotification()->credentialsChanged($customer, $currentCustomer->getEmail()); } else { $customer = $this->customerAccountManagement->createAccount($customer); @@ -386,13 +386,13 @@ public function execute() __('Something went wrong while saving the customer.') ); $returnToEdit = false; - } catch (\Magento\Framework\Validator\Exception $exception) { + } catch (Exception $exception) { $messages = $exception->getMessages(); if (empty($messages)) { $messages = $exception->getMessage(); } $this->_addSessionErrorMessages($messages); - $this->_getSession()->setCustomerFormData($this->retrieveFormattedFormData()); + $this->_getSession()->setCustomerFormData($this->retrieveFormattedFormData($customer)); $returnToEdit = true; } catch (AbstractAggregateException $exception) { $errors = $exception->getErrors(); @@ -401,18 +401,18 @@ public function execute() $messages[] = $error->getMessage(); } $this->_addSessionErrorMessages($messages); - $this->_getSession()->setCustomerFormData($this->retrieveFormattedFormData()); + $this->_getSession()->setCustomerFormData($this->retrieveFormattedFormData($customer)); $returnToEdit = true; } catch (LocalizedException $exception) { $this->_addSessionErrorMessages($exception->getMessage()); - $this->_getSession()->setCustomerFormData($this->retrieveFormattedFormData()); + $this->_getSession()->setCustomerFormData($this->retrieveFormattedFormData($customer)); $returnToEdit = true; } catch (\Exception $exception) { $this->messageManager->addExceptionMessage( $exception, __('Something went wrong while saving the customer.') ); - $this->_getSession()->setCustomerFormData($this->retrieveFormattedFormData()); + $this->_getSession()->setCustomerFormData($this->retrieveFormattedFormData($customer)); $returnToEdit = true; } } @@ -553,21 +553,16 @@ private function disableAddressValidation($customer) /** * Retrieve formatted form data * + * @param CustomerInterface $customer * @return array */ - private function retrieveFormattedFormData(): array + private function retrieveFormattedFormData(CustomerInterface $customer): array { $originalRequestData = $this->getRequest()->getPostValue(); + $customerData = $this->customerMapper->toFlatArray($customer); /* Customer data filtration */ if (isset($originalRequestData['customer'])) { - $customerData = $this->_extractData( - 'adminhtml_customer', - CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, - [], - 'customer' - ); - $customerData = array_intersect_key($customerData, $originalRequestData['customer']); $originalRequestData['customer'] = array_merge($originalRequestData['customer'], $customerData); } diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index 604295cc0c078..a82af07342abb 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -8,11 +8,13 @@ use Magento\Customer\Model\Address; use Magento\Customer\Model\Customer; +use Magento\Customer\Model\CustomerFactory; use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory as CustomerCollectionFactory; use Magento\Directory\Model\CountryFactory; use Magento\Eav\Model\Config; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; use Magento\Eav\Model\Entity\Type; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Session\SessionManagerInterface; use Magento\Customer\Model\FileUploaderDataResolver; @@ -66,6 +68,11 @@ class DataProviderWithDefaultAddresses extends AbstractDataProvider */ private $attributeMetadataResolver; + /** + * @var CustomerFactory + */ + private $customerFactory; + /** * @param string $name * @param string $primaryFieldName @@ -79,6 +86,7 @@ class DataProviderWithDefaultAddresses extends AbstractDataProvider * @param bool $allowToShowHiddenAttributes * @param array $meta * @param array $data + * @param CustomerFactory $customerFactory * @throws LocalizedException * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -94,7 +102,8 @@ public function __construct( AttributeMetadataResolver $attributeMetadataResolver, $allowToShowHiddenAttributes = true, array $meta = [], - array $data = [] + array $data = [], + CustomerFactory $customerFactory = null ) { parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); $this->collection = $customerCollectionFactory->create(); @@ -107,6 +116,7 @@ public function __construct( $this->meta['customer']['children'] = $this->getAttributesMeta( $eavConfig->getEntityType('customer') ); + $this->customerFactory = $customerFactory ?: ObjectManager::getInstance()->get(CustomerFactory::class); } /** @@ -142,9 +152,10 @@ public function getData(): array $this->loadedData[$customer->getId()] = $result; } - $data = $this->session->getCustomerFormData(); if (!empty($data)) { + $customer = $this->customerFactory->create(); + $this->fileUploaderDataResolver->overrideFileUploaderData($customer, $data['customer']); $customerId = $data['customer']['entity_id'] ?? null; $this->loadedData[$customerId] = $data; $this->session->unsCustomerFormData(); diff --git a/app/code/Magento/Customer/Model/FileProcessor.php b/app/code/Magento/Customer/Model/FileProcessor.php index c596f8c313ab3..02bfe78be535c 100644 --- a/app/code/Magento/Customer/Model/FileProcessor.php +++ b/app/code/Magento/Customer/Model/FileProcessor.php @@ -7,6 +7,18 @@ namespace Magento\Customer\Model; +use Magento\Customer\Api\AddressMetadataInterface; +use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\File\Mime; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\WriteInterface; +use Magento\Framework\Url\EncoderInterface; +use Magento\Framework\UrlInterface; +use Magento\MediaStorage\Model\File\Uploader; +use Magento\MediaStorage\Model\File\UploaderFactory; + /** * Processor class for work with uploaded files */ @@ -18,22 +30,22 @@ class FileProcessor const TMP_DIR = 'tmp'; /** - * @var \Magento\Framework\Filesystem\Directory\WriteInterface + * @var WriteInterface */ private $mediaDirectory; /** - * @var \Magento\MediaStorage\Model\File\UploaderFactory + * @var UploaderFactory */ private $uploaderFactory; /** - * @var \Magento\Framework\UrlInterface + * @var UrlInterface */ private $urlBuilder; /** - * @var \Magento\Framework\Url\EncoderInterface + * @var EncoderInterface */ private $urlEncoder; @@ -48,29 +60,29 @@ class FileProcessor private $allowedExtensions = []; /** - * @var \Magento\Framework\File\Mime + * @var Mime */ private $mime; /** - * @param \Magento\Framework\Filesystem $filesystem - * @param \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory - * @param \Magento\Framework\UrlInterface $urlBuilder - * @param \Magento\Framework\Url\EncoderInterface $urlEncoder + * @param Filesystem $filesystem + * @param UploaderFactory $uploaderFactory + * @param UrlInterface $urlBuilder + * @param EncoderInterface $urlEncoder * @param string $entityTypeCode - * @param \Magento\Framework\File\Mime $mime + * @param Mime $mime * @param array $allowedExtensions */ public function __construct( - \Magento\Framework\Filesystem $filesystem, - \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory, - \Magento\Framework\UrlInterface $urlBuilder, - \Magento\Framework\Url\EncoderInterface $urlEncoder, + Filesystem $filesystem, + UploaderFactory $uploaderFactory, + UrlInterface $urlBuilder, + EncoderInterface $urlEncoder, $entityTypeCode, - \Magento\Framework\File\Mime $mime, + Mime $mime, array $allowedExtensions = [] ) { - $this->mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA); + $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); $this->uploaderFactory = $uploaderFactory; $this->urlBuilder = $urlBuilder; $this->urlEncoder = $urlEncoder; @@ -91,8 +103,7 @@ public function getBase64EncodedData($fileName) $fileContent = $this->mediaDirectory->readFile($filePath); - $encodedContent = base64_encode($fileContent); - return $encodedContent; + return base64_encode($fileContent); } /** @@ -105,8 +116,7 @@ public function getStat($fileName) { $filePath = $this->entityTypeCode . '/' . ltrim($fileName, '/'); - $result = $this->mediaDirectory->stat($filePath); - return $result; + return $this->mediaDirectory->stat($filePath); } /** @@ -120,8 +130,7 @@ public function getMimeType($fileName) $filePath = $this->entityTypeCode . '/' . ltrim($fileName, '/'); $absoluteFilePath = $this->mediaDirectory->getAbsolutePath($filePath); - $result = $this->mime->getMimeType($absoluteFilePath); - return $result; + return $this->mime->getMimeType($absoluteFilePath); } /** @@ -134,8 +143,7 @@ public function isExist($fileName) { $filePath = $this->entityTypeCode . '/' . ltrim($fileName, '/'); - $result = $this->mediaDirectory->isExist($filePath); - return $result; + return $this->mediaDirectory->isExist($filePath); } /** @@ -149,13 +157,13 @@ public function getViewUrl($filePath, $type) { $viewUrl = ''; - if ($this->entityTypeCode == \Magento\Customer\Api\AddressMetadataInterface::ENTITY_TYPE_ADDRESS) { + if ($this->entityTypeCode == AddressMetadataInterface::ENTITY_TYPE_ADDRESS) { $filePath = $this->entityTypeCode . '/' . ltrim($filePath, '/'); - $viewUrl = $this->urlBuilder->getBaseUrl(['_type' => \Magento\Framework\UrlInterface::URL_TYPE_MEDIA]) + $viewUrl = $this->urlBuilder->getBaseUrl(['_type' => UrlInterface::URL_TYPE_MEDIA]) . $this->mediaDirectory->getRelativePath($filePath); } - if ($this->entityTypeCode == \Magento\Customer\Api\CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) { + if ($this->entityTypeCode == CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) { $viewUrl = $this->urlBuilder->getUrl( 'customer/index/viewfile', [$type => $this->urlEncoder->encode(ltrim($filePath, '/'))] @@ -170,11 +178,11 @@ public function getViewUrl($filePath, $type) * * @param string $fileId * @return \string[] - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ public function saveTemporaryFile($fileId) { - /** @var \Magento\MediaStorage\Model\File\Uploader $uploader */ + /** @var Uploader $uploader */ $uploader = $this->uploaderFactory->create(['fileId' => $fileId]); $uploader->setFilesDispersion(false); $uploader->setFilenamesCaseSensitivity(false); @@ -188,7 +196,7 @@ public function saveTemporaryFile($fileId) $result = $uploader->save($path); unset($result['path']); if (!$result) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('File can not be saved to the destination folder.') ); } @@ -201,28 +209,32 @@ public function saveTemporaryFile($fileId) * * @param string $fileName * @return string - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ public function moveTemporaryFile($fileName) { + if (!$this->isFileTemporary($fileName)) { + return $fileName; + } + $fileName = ltrim($fileName, '/'); - $dispersionPath = \Magento\MediaStorage\Model\File\Uploader::getDispersionPath($fileName); + $dispersionPath = Uploader::getDispersionPath($fileName); $destinationPath = $this->entityTypeCode . $dispersionPath; if (!$this->mediaDirectory->create($destinationPath)) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('Unable to create directory %1.', $destinationPath) ); } if (!$this->mediaDirectory->isWritable($destinationPath)) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('Destination folder is not writable or does not exists.') ); } - $destinationFileName = \Magento\MediaStorage\Model\File\Uploader::getNewFileName( + $destinationFileName = Uploader::getNewFileName( $this->mediaDirectory->getAbsolutePath($destinationPath) . '/' . $fileName ); @@ -238,8 +250,7 @@ public function moveTemporaryFile($fileName) ); } - $fileName = $dispersionPath . '/' . $destinationFileName; - return $fileName; + return $dispersionPath . '/' . $destinationFileName; } /** @@ -252,7 +263,20 @@ public function removeUploadedFile($fileName) { $filePath = $this->entityTypeCode . '/' . ltrim($fileName, '/'); - $result = $this->mediaDirectory->delete($filePath); - return $result; + return $this->mediaDirectory->delete($filePath); + } + + /** + * Verify if given file temporary. + * + * @param string $fileName + * @return bool + */ + private function isFileTemporary(string $fileName): bool + { + $tmpFile = $this->entityTypeCode . '/' . self::TMP_DIR . '/' . ltrim($fileName, '/'); + $destinationFile = $this->entityTypeCode . '/' . ltrim($fileName, '/'); + + return $this->mediaDirectory->isExist($tmpFile) && !$this->mediaDirectory->isExist($destinationFile); } } diff --git a/app/code/Magento/Customer/Model/Metadata/Form/Image.php b/app/code/Magento/Customer/Model/Metadata/Form/Image.php index d023db1454906..b5bfe00c23384 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/Image.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/Image.php @@ -16,15 +16,15 @@ use Magento\Framework\Api\ArrayObjectSearch; use Magento\Framework\Api\Data\ImageContentInterface; use Magento\Framework\Api\Data\ImageContentInterfaceFactory; +use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\FileSystemException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\File\UploaderFactory; use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\WriteFactory; use Magento\Framework\Filesystem\Directory\WriteInterface; use Magento\Framework\Filesystem\Io\File as IoFileSystem; -use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\Filesystem\Directory\WriteFactory; use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; use Magento\Framework\Url\EncoderInterface; @@ -54,8 +54,6 @@ class Image extends File private $mediaEntityTmpDirectory; /** - * Constructor - * * @param TimezoneInterface $localeDate * @param LoggerInterface $logger * @param AttributeMetadataInterface $attribute @@ -207,13 +205,11 @@ protected function _validateByRules($value) protected function processUiComponentValue(array $value) { if ($this->_entityTypeCode == AddressMetadataInterface::ENTITY_TYPE_ADDRESS) { - $result = $this->processCustomerAddressValue($value); - return $result; + return $this->processCustomerAddressValue($value); } if ($this->_entityTypeCode == CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) { - $result = $this->processCustomerValue($value); - return $result; + return $this->processCustomerValue($value); } return $this->_value; @@ -267,6 +263,6 @@ protected function processCustomerValue(array $value) return $imageContentDataObject; } - return $this->_value; + return $this->_value ?: $value['file']; } } diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFillCustomerMainDataActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFillCustomerMainDataActionGroup.xml new file mode 100644 index 0000000000000..dc7d68faf362d --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFillCustomerMainDataActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminFillCustomerMainDataActionGroup"> + <annotations> + <description>Fill customer main required data. Starts on customer creation/edit page.</description> + </annotations> + + <arguments> + <argument name="firstName" type="string" defaultValue="{{Simple_US_Customer.firstname}}"/> + <argument name="lastName" type="string" defaultValue="{{Simple_US_Customer.lastname}}"/> + <argument name="email" type="string" defaultValue="{{Simple_US_Customer.email}}"/> + </arguments> + <waitForElementVisible selector="{{AdminCustomerAccountInformationSection.firstName}}" stepKey="waitForCustomerPageLoad"/> + <fillField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="{{firstName}}" stepKey="fillFirstName"/> + <fillField selector="{{AdminCustomerAccountInformationSection.lastName}}" userInput="{{lastName}}" stepKey="fillLastName"/> + <fillField selector="{{AdminCustomerAccountInformationSection.email}}" userInput="{{email}}" stepKey="fillEmail"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php index 8e9cce7390831..0e586d0c424a5 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php @@ -722,7 +722,7 @@ public function testExecuteWithNewCustomerAndValidationException() ]; $extractedData = [ 'coolness' => false, - 'disable_auto_group_change' => 'false', + 'disable_auto_group_change' => 0, 'dob' => '1996-03-12', ]; @@ -731,10 +731,10 @@ public function testExecuteWithNewCustomerAndValidationException() AttributeMetadataInterface::class )->disableOriginalConstructor() ->getMock(); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->once()) ->method('getAttributeCode') ->willReturn('coolness'); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->once()) ->method('getFrontendInput') ->willReturn('int'); $attributes = [$attributeMock]; @@ -759,12 +759,12 @@ public function testExecuteWithNewCustomerAndValidationException() $objectMock = $this->getMockBuilder(DataObject::class) ->disableOriginalConstructor() ->getMock(); - $objectMock->expects($this->exactly(2)) + $objectMock->expects($this->once()) ->method('getData') ->with('customer') ->willReturn($postValue['customer']); - $this->objectFactoryMock->expects($this->exactly(2)) + $this->objectFactoryMock->expects($this->once()) ->method('create') ->with(['data' => $postValue]) ->willReturn($objectMock); @@ -773,19 +773,19 @@ public function testExecuteWithNewCustomerAndValidationException() Form::class )->disableOriginalConstructor() ->getMock(); - $customerFormMock->expects($this->exactly(2)) + $customerFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'customer') ->willReturn($extractedData); - $customerFormMock->expects($this->exactly(2)) + $customerFormMock->expects($this->once()) ->method('compactData') ->with($extractedData) ->willReturn($extractedData); - $customerFormMock->expects($this->exactly(2)) + $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); - $this->formFactoryMock->expects($this->exactly(2)) + $this->formFactoryMock->expects($this->once()) ->method('create') ->with( CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, @@ -809,7 +809,10 @@ public function testExecuteWithNewCustomerAndValidationException() ->method('createAccount') ->with($customerMock, null, '') ->willThrowException(new \Magento\Framework\Validator\Exception(__('Validator Exception'))); - + $this->customerMapperMock->expects($this->once()) + ->method('toFlatArray') + ->with($customerMock) + ->willReturn($extractedData); $customerMock->expects($this->never()) ->method('getId'); @@ -876,7 +879,7 @@ public function testExecuteWithNewCustomerAndLocalizedException() ]; $extractedData = [ 'coolness' => false, - 'disable_auto_group_change' => 'false', + 'disable_auto_group_change' => 0, 'dob' => '1996-03-12', ]; @@ -885,10 +888,10 @@ public function testExecuteWithNewCustomerAndLocalizedException() AttributeMetadataInterface::class )->disableOriginalConstructor() ->getMock(); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->once()) ->method('getAttributeCode') ->willReturn('coolness'); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->once()) ->method('getFrontendInput') ->willReturn('int'); $attributes = [$attributeMock]; @@ -913,12 +916,12 @@ public function testExecuteWithNewCustomerAndLocalizedException() $objectMock = $this->getMockBuilder(DataObject::class) ->disableOriginalConstructor() ->getMock(); - $objectMock->expects($this->exactly(2)) + $objectMock->expects($this->once()) ->method('getData') ->with('customer') ->willReturn($postValue['customer']); - $this->objectFactoryMock->expects($this->exactly(2)) + $this->objectFactoryMock->expects($this->once()) ->method('create') ->with(['data' => $postValue]) ->willReturn($objectMock); @@ -928,19 +931,19 @@ public function testExecuteWithNewCustomerAndLocalizedException() Form::class )->disableOriginalConstructor() ->getMock(); - $customerFormMock->expects($this->exactly(2)) + $customerFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'customer') ->willReturn($extractedData); - $customerFormMock->expects($this->exactly(2)) + $customerFormMock->expects($this->once()) ->method('compactData') ->with($extractedData) ->willReturn($extractedData); - $customerFormMock->expects($this->exactly(2)) + $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); - $this->formFactoryMock->expects($this->exactly(2)) + $this->formFactoryMock->expects($this->once()) ->method('create') ->with( CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, @@ -986,6 +989,11 @@ public function testExecuteWithNewCustomerAndLocalizedException() ->method('addMessage') ->with(new Error('Localized Exception')); + $this->customerMapperMock->expects($this->once()) + ->method('toFlatArray') + ->with($customerMock) + ->willReturn($extractedData); + $this->sessionMock->expects($this->once()) ->method('setCustomerFormData') ->with( @@ -1030,7 +1038,7 @@ public function testExecuteWithNewCustomerAndException() ]; $extractedData = [ 'coolness' => false, - 'disable_auto_group_change' => 'false', + 'disable_auto_group_change' => 0, 'dob' => '1996-03-12', ]; @@ -1039,10 +1047,10 @@ public function testExecuteWithNewCustomerAndException() AttributeMetadataInterface::class )->disableOriginalConstructor() ->getMock(); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->once()) ->method('getAttributeCode') ->willReturn('coolness'); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->once()) ->method('getFrontendInput') ->willReturn('int'); $attributes = [$attributeMock]; @@ -1067,12 +1075,12 @@ public function testExecuteWithNewCustomerAndException() $objectMock = $this->getMockBuilder(DataObject::class) ->disableOriginalConstructor() ->getMock(); - $objectMock->expects($this->exactly(2)) + $objectMock->expects($this->once()) ->method('getData') ->with('customer') ->willReturn($postValue['customer']); - $this->objectFactoryMock->expects($this->exactly(2)) + $this->objectFactoryMock->expects($this->once()) ->method('create') ->with(['data' => $postValue]) ->willReturn($objectMock); @@ -1081,19 +1089,19 @@ public function testExecuteWithNewCustomerAndException() Form::class )->disableOriginalConstructor() ->getMock(); - $customerFormMock->expects($this->exactly(2)) + $customerFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'customer') ->willReturn($extractedData); - $customerFormMock->expects($this->exactly(2)) + $customerFormMock->expects($this->once()) ->method('compactData') ->with($extractedData) ->willReturn($extractedData); - $customerFormMock->expects($this->exactly(2)) + $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); - $this->formFactoryMock->expects($this->exactly(2)) + $this->formFactoryMock->expects($this->once()) ->method('create') ->with( CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, @@ -1141,6 +1149,11 @@ public function testExecuteWithNewCustomerAndException() ->method('addExceptionMessage') ->with($exception, __('Something went wrong while saving the customer.')); + $this->customerMapperMock->expects($this->once()) + ->method('toFlatArray') + ->with($customerMock) + ->willReturn($extractedData); + $this->sessionMock->expects($this->once()) ->method('setCustomerFormData') ->with( diff --git a/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php b/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php index e1c771d79694e..7a0522f6476f2 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php @@ -313,10 +313,7 @@ public function testMoveTemporaryFileUnableToCreateDirectory() $destinationPath = 'customer/f/i'; - $this->mediaDirectory->expects($this->once()) - ->method('create') - ->with($destinationPath) - ->willReturn(false); + $this->configureMediaDirectoryMock($destinationPath, false); $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER); $model->moveTemporaryFile($filePath); @@ -331,10 +328,7 @@ public function testMoveTemporaryFileDestinationFolderDoesNotExists() $destinationPath = 'customer/f/i'; - $this->mediaDirectory->expects($this->once()) - ->method('create') - ->with($destinationPath) - ->willReturn(true); + $this->configureMediaDirectoryMock($destinationPath, true); $this->mediaDirectory->expects($this->once()) ->method('isWritable') ->with($destinationPath) @@ -350,10 +344,7 @@ public function testMoveTemporaryFile() $destinationPath = 'customer/f/i'; - $this->mediaDirectory->expects($this->once()) - ->method('create') - ->with($destinationPath) - ->willReturn(true); + $this->configureMediaDirectoryMock($destinationPath, true); $this->mediaDirectory->expects($this->once()) ->method('isWritable') ->with($destinationPath) @@ -390,10 +381,7 @@ public function testMoveTemporaryFileNewFileName() $destinationPath = 'customer/f/i'; - $this->mediaDirectory->expects($this->once()) - ->method('create') - ->with($destinationPath) - ->willReturn(true); + $this->configureMediaDirectoryMock($destinationPath, true); $this->mediaDirectory->expects($this->once()) ->method('isWritable') ->with($destinationPath) @@ -440,10 +428,7 @@ public function testMoveTemporaryFileWithException() $destinationPath = 'customer/f/i'; - $this->mediaDirectory->expects($this->once()) - ->method('create') - ->with($destinationPath) - ->willReturn(true); + $this->configureMediaDirectoryMock($destinationPath, true); $this->mediaDirectory->expects($this->once()) ->method('isWritable') ->with($destinationPath) @@ -486,4 +471,26 @@ public function testGetMimeType() $this->assertEquals($expected, $model->getMimeType($fileName)); } + + /** + * Configure media directory mock to create media directory. + * + * @param string $destinationPath + * @param bool $directoryCreated + */ + private function configureMediaDirectoryMock(string $destinationPath, bool $directoryCreated): void + { + $this->mediaDirectory->expects($this->at(0)) + ->method('isExist') + ->with('customer/tmp/filename.ext1') + ->willReturn(true); + $this->mediaDirectory->expects($this->at(1)) + ->method('isExist') + ->with('customer/filename.ext1') + ->willReturn(false); + $this->mediaDirectory->expects($this->once()) + ->method('create') + ->with($destinationPath) + ->willReturn($directoryCreated); + } } From 6300c0907d7b5d041efc84b84caf1601fc56babd Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Thu, 26 Nov 2020 09:53:42 +0200 Subject: [PATCH 22/32] MC-37922: Html tag <br> visible in message --- .../Controller/Adminhtml/ImportResultTest.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/ImportResultTest.php b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/ImportResultTest.php index ccd9e29e90a18..37b5bcd81f68d 100644 --- a/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/ImportResultTest.php +++ b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/ImportResultTest.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\ImportExport\Controller\Adminhtml; use Magento\Framework\Filesystem\DirectoryList; @@ -12,18 +14,19 @@ use Magento\ImportExport\Controller\Adminhtml\Import\HttpFactoryMock; /** + * Test for \Magento\ImportExport\Controller\Adminhtml\ImportResult class. + * * @magentoAppArea adminhtml */ class ImportResultTest extends \Magento\TestFramework\TestCase\AbstractBackendController { /** - * @dataProvider validationDataProvider * @param string $fileName * @param string $mimeType * @param string $delimiter - * @throws \Magento\Framework\Exception\FileSystemException * @backupGlobals enabled * @magentoDbIsolation enabled + * @dataProvider validationDataProvider * @SuppressWarnings(PHPMD.Superglobals) */ public function testAddErrorMessages(string $fileName, string $mimeType, string $delimiter): void @@ -48,8 +51,9 @@ public function testAddErrorMessages(string $fileName, string $mimeType, string $tmpDir = $filesystem->getDirectoryWrite(DirectoryList::SYS_TMP); $subDir = str_replace('\\', '_', __CLASS__); $tmpDir->create($subDir); - $target = $tmpDir->getAbsolutePath("{$subDir}/{$fileName}"); - copy(__DIR__ . "/Import/_files/{$fileName}", $target); + $target = $tmpDir->getAbsolutePath("{$subDir}" . DIRECTORY_SEPARATOR . "{$fileName}"); + copy(__DIR__ . DIRECTORY_SEPARATOR . 'Import' . DIRECTORY_SEPARATOR . '_files' + . DIRECTORY_SEPARATOR . "{$fileName}", $target); $_FILES = [ 'import_file' => [ From 1e26bd94f7293877f7d71b57eb559f8e2718c7fb Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Thu, 26 Nov 2020 15:29:13 +0200 Subject: [PATCH 23/32] MC-23545: Customer attribute of type file doesn't display in Account Information after created --- .../Customer/Controller/Account/EditPost.php | 55 +++- .../Customer/Controller/Address/FormPost.php | 45 ++- .../Magento/Customer/Model/FileUploader.php | 55 +++- .../Customer/Model/Metadata/Form/File.php | 53 ++- .../AdminFillCustomerMainDataActionGroup.xml | 26 ++ ...torefrontCreateCustomerSaveActionGroup.xml | 16 + .../StorefrontCustomerSaveActionGroup.xml | 20 ++ .../Customer/Test/Mftf/Data/ImageData.xml | 16 + ...FrontCustomerAdvancedAttributesSection.xml | 2 + .../Unit/Controller/Address/FormPostTest.php | 2 +- .../Unit/Model/Metadata/Form/FileTest.php | 307 ++++++++++-------- .../Magento/Sales/Model/AdminOrder/Create.php | 5 +- .../Test/Unit/Model/AdminOrder/CreateTest.php | 9 +- 13 files changed, 444 insertions(+), 167 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFillCustomerMainDataActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCreateCustomerSaveActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerSaveActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Data/ImageData.xml diff --git a/app/code/Magento/Customer/Controller/Account/EditPost.php b/app/code/Magento/Customer/Controller/Account/EditPost.php index 6b59986f8ec5f..d2cc385b5793f 100644 --- a/app/code/Magento/Customer/Controller/Account/EditPost.php +++ b/app/code/Magento/Customer/Controller/Account/EditPost.php @@ -31,6 +31,8 @@ use Magento\Framework\Exception\State\UserLockedException; use Magento\Customer\Controller\AbstractAccount; use Magento\Framework\Phrase; +use Magento\Framework\Filesystem; +use Magento\Framework\App\Filesystem\DirectoryList; /** * Customer edit account information controller @@ -94,6 +96,11 @@ class EditPost extends AbstractAccount implements CsrfAwareActionInterface, Http */ private $addressRegistry; + /** + * @var Filesystem + */ + private $filesystem; + /** * @param Context $context * @param Session $customerSession @@ -103,6 +110,7 @@ class EditPost extends AbstractAccount implements CsrfAwareActionInterface, Http * @param CustomerExtractor $customerExtractor * @param Escaper|null $escaper * @param AddressRegistry|null $addressRegistry + * @param Filesystem $filesystem */ public function __construct( Context $context, @@ -112,7 +120,8 @@ public function __construct( Validator $formKeyValidator, CustomerExtractor $customerExtractor, ?Escaper $escaper = null, - AddressRegistry $addressRegistry = null + AddressRegistry $addressRegistry = null, + Filesystem $filesystem = null ) { parent::__construct($context); $this->session = $customerSession; @@ -122,6 +131,7 @@ public function __construct( $this->customerExtractor = $customerExtractor; $this->escaper = $escaper ?: ObjectManager::getInstance()->get(Escaper::class); $this->addressRegistry = $addressRegistry ?: ObjectManager::getInstance()->get(AddressRegistry::class); + $this->filesystem = $filesystem ?: ObjectManager::getInstance()->get(Filesystem::class); } /** @@ -201,6 +211,12 @@ public function execute() $currentCustomerDataObject ); + $attributeToDelete = $this->_request->getParam('delete_attribute_value'); + $this->deleteCustomerFileAttribute( + $customerCandidateDataObject, + $attributeToDelete + ); + try { // whether a customer enabled change email option $this->processChangeEmailRequest($currentCustomerDataObject); @@ -388,4 +404,41 @@ private function disableAddressValidation($customer) $addressModel->setShouldIgnoreValidation(true); } } + + /** + * Removes file attribute from customer entity and file from filesystem + * + * @param CustomerInterface $customerCandidateDataObject + * @param string $attributeToDelete + * @return void + */ + private function deleteCustomerFileAttribute( + CustomerInterface $customerCandidateDataObject, + string $attributeToDelete + ) : void { + if ($attributeToDelete !== '') { + if (strpos($attributeToDelete, ',') !== false) { + $attributes = explode(',', $attributeToDelete); + } else { + $attributes[] = $attributeToDelete; + } + foreach ($attributes as $attr) { + $attributeValue = $customerCandidateDataObject->getCustomAttribute($attr); + if ($attributeValue!== null) { + if ($attributeValue->getValue() !== '') { + $mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $fileName = $attributeValue->getValue(); + $path = $mediaDirectory->getAbsolutePath('customer' . $fileName); + if ($fileName && $mediaDirectory->isFile($path)) { + $mediaDirectory->delete($path); + } + $customerCandidateDataObject->setCustomAttribute( + $attr, + '' + ); + } + } + } + } + } } diff --git a/app/code/Magento/Customer/Controller/Address/FormPost.php b/app/code/Magento/Customer/Controller/Address/FormPost.php index 25618e3129160..cae039ea975b8 100644 --- a/app/code/Magento/Customer/Controller/Address/FormPost.php +++ b/app/code/Magento/Customer/Controller/Address/FormPost.php @@ -24,6 +24,9 @@ use Magento\Framework\Exception\InputException; use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Framework\View\Result\PageFactory; +use Magento\Framework\Filesystem; +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Exception\NotFoundException; /** * Customer Address Form Post Controller @@ -47,6 +50,11 @@ class FormPost extends \Magento\Customer\Controller\Address implements HttpPostA */ private $customerAddressMapper; + /** + * @var Filesystem + */ + private $filesystem; + /** * @param Context $context * @param Session $customerSession @@ -61,6 +69,7 @@ class FormPost extends \Magento\Customer\Controller\Address implements HttpPostA * @param PageFactory $resultPageFactory * @param RegionFactory $regionFactory * @param HelperData $helperData + * @param Filesystem $filesystem * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -76,10 +85,12 @@ public function __construct( ForwardFactory $resultForwardFactory, PageFactory $resultPageFactory, RegionFactory $regionFactory, - HelperData $helperData + HelperData $helperData, + Filesystem $filesystem = null ) { $this->regionFactory = $regionFactory; $this->helperData = $helperData; + $this->filesystem = $filesystem ?: ObjectManager::getInstance()->get(Filesystem::class); parent::__construct( $context, $customerSession, @@ -150,7 +161,7 @@ protected function getExistingAddressData() if ($addressId = $this->getRequest()->getParam('id')) { $existingAddress = $this->_addressRepository->getById($addressId); if ($existingAddress->getCustomerId() !== $this->_getSession()->getCustomerId()) { - throw new \Exception(); + throw new NotFoundException(__('Address not found.')); } $existingAddressData = $this->getCustomerAddressMapper()->toFlatArray($existingAddress); } @@ -210,6 +221,9 @@ public function execute() try { $address = $this->_extractAddress(); + if ($this->_request->getParam('delete_attribute_value')) { + $address = $this->deleteAddressFileAttribute($address); + } $this->_addressRepository->save($address); $this->messageManager->addSuccessMessage(__('You saved the address.')); $url = $this->_buildUrl('*/*/index', ['_secure' => true]); @@ -249,4 +263,31 @@ private function getCustomerAddressMapper() } return $this->customerAddressMapper; } + + /** + * Removes file attribute from customer address and file from filesystem + * + * @param \Magento\Customer\Api\Data\AddressInterface $address + * @return mixed + */ + private function deleteAddressFileAttribute($address) + { + $attributeValue = $address->getCustomAttribute($this->_request->getParam('delete_attribute_value')); + if ($attributeValue!== null) { + if ($attributeValue->getValue() !== '') { + $mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $fileName = $attributeValue->getValue(); + $path = $mediaDirectory->getAbsolutePath('customer_address' . $fileName); + if ($fileName && $mediaDirectory->isFile($path)) { + $mediaDirectory->delete($path); + } + $address->setCustomAttribute( + $this->_request->getParam('delete_attribute_value'), + '' + ); + } + } + + return $address; + } } diff --git a/app/code/Magento/Customer/Model/FileUploader.php b/app/code/Magento/Customer/Model/FileUploader.php index c425ac06666c5..411ab37a1d740 100644 --- a/app/code/Magento/Customer/Model/FileUploader.php +++ b/app/code/Magento/Customer/Model/FileUploader.php @@ -100,14 +100,33 @@ public function validate() * @throws LocalizedException */ public function upload() + { + return $this->uploadFile(); + } + + /** + * File uploading process + * + * @param bool $useScope + * @return string[] + * @throws LocalizedException + */ + public function uploadFile($useScope = true) { /** @var FileProcessor $fileProcessor */ - $fileProcessor = $this->fileProcessorFactory->create([ - 'entityTypeCode' => $this->entityTypeCode, - 'allowedExtensions' => $this->getAllowedExtensions(), - ]); + $fileProcessor = $this->fileProcessorFactory->create( + [ + 'entityTypeCode' => $this->entityTypeCode, + 'allowedExtensions' => $this->getAllowedExtensions(), + ] + ); - $result = $fileProcessor->saveTemporaryFile($this->scope . '[' . $this->getAttributeCode() . ']'); + if ($useScope === true) { + $fileId = $this->scope . '[' . $this->getAttributeCode() . ']'; + } else { + $fileId = $this->getAttributeCode(); + } + $result = $fileProcessor->saveTemporaryFile($fileId); // Update tmp_name param. Required for attribute validation! $result['tmp_name'] = ltrim($result['file'], '/'); @@ -127,7 +146,14 @@ public function upload() */ private function getAttributeCode() { - return key($_FILES[$this->scope]['name']); + // phpcs:disable Magento2.Security.Superglobal + if (is_array($_FILES[$this->scope]['name'])) { + $code = key($_FILES[$this->scope]['name']); + } else { + $code = $this->scope; + } + // phpcs:enable Magento2.Security.Superglobal + return $code; } /** @@ -139,10 +165,16 @@ private function getData() { $data = []; + // phpcs:disable Magento2.Security.Superglobal $fileAttributes = $_FILES[$this->scope]; foreach ($fileAttributes as $attributeName => $attributeValue) { - $data[$attributeName] = $attributeValue[$this->getAttributeCode()]; + if (is_array($attributeValue)) { + $data[$attributeName] = $attributeValue[$this->getAttributeCode()]; + } else { + $data[$attributeName] = $attributeValue; + } } + // phpcs:enable Magento2.Security.Superglobal return $data; } @@ -160,9 +192,12 @@ private function getAllowedExtensions() foreach ($validationRules as $validationRule) { if ($validationRule->getName() == 'file_extensions') { $allowedExtensions = explode(',', $validationRule->getValue()); - array_walk($allowedExtensions, function (&$value) { - $value = strtolower(trim($value)); - }); + array_walk( + $allowedExtensions, + function (&$value) { + $value = strtolower(trim($value)); + } + ); break; } } diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index 1a1c48075fce5..17cfc0325ef41 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -13,6 +13,7 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\File\UploaderFactory; use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Io\File as IoFile; /** * Processes files that are save for customer. @@ -61,6 +62,11 @@ class File extends AbstractData */ protected $fileProcessorFactory; + /** + * @var IoFile|null + */ + private $ioFile; + /** * Constructor * @@ -76,6 +82,7 @@ class File extends AbstractData * @param Filesystem $fileSystem * @param UploaderFactory $uploaderFactory * @param \Magento\Customer\Model\FileProcessorFactory|null $fileProcessorFactory + * @param IoFile|null $ioFile * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -90,7 +97,8 @@ public function __construct( \Magento\MediaStorage\Model\File\Validator\NotProtectedExtension $fileValidator, Filesystem $fileSystem, UploaderFactory $uploaderFactory, - \Magento\Customer\Model\FileProcessorFactory $fileProcessorFactory = null + FileProcessorFactory $fileProcessorFactory = null, + IoFile $ioFile = null ) { parent::__construct($localeDate, $logger, $attribute, $localeResolver, $value, $entityTypeCode, $isAjax); $this->urlEncoder = $urlEncoder; @@ -98,8 +106,10 @@ public function __construct( $this->_fileSystem = $fileSystem; $this->uploaderFactory = $uploaderFactory; $this->fileProcessorFactory = $fileProcessorFactory ?: ObjectManager::getInstance() - ->get(\Magento\Customer\Model\FileProcessorFactory::class); + ->get(FileProcessorFactory::class); $this->fileProcessor = $this->fileProcessorFactory->create(['entityTypeCode' => $this->_entityTypeCode]); + $this->ioFile = $ioFile ?: ObjectManager::getInstance() + ->get(IoFile::class); } /** @@ -110,11 +120,17 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request) { $extend = $this->_getRequestValue($request); + // phpcs:disable Magento2.Security.Superglobal $attrCode = $this->getAttribute()->getAttributeCode(); - if ($this->_requestScope || !isset($_FILES[$attrCode])) { + + // phpcs:disable Magento2.Security.Superglobal + $uploadedFile = $request->getParam($attrCode . '_uploaded'); + if ($uploadedFile) { + $value = $uploadedFile; + } elseif ($this->_requestScope || !isset($_FILES[$attrCode])) { $value = []; - if (strpos($this->_requestScope, '/') !== false) { - $scopes = explode('/', $this->_requestScope); + if (strpos($this->_requestScope, DIRECTORY_SEPARATOR) !== false) { + $scopes = explode(DIRECTORY_SEPARATOR, $this->_requestScope); $mainScope = array_shift($scopes); } else { $mainScope = $this->_requestScope; @@ -153,6 +169,7 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request) $value = []; } } + // phpcs:enable Magento2.Security.Superglobal if (!empty($extend['delete'])) { $value['delete'] = true; @@ -171,7 +188,9 @@ protected function _validateByRules($value) { $label = $value['name']; $rules = $this->getAttribute()->getValidationRules(); - $extension = pathinfo($value['name'], PATHINFO_EXTENSION); + // phpcs:ignore Magento2.Functions.DiscouragedFunction + $pathInfo = $this->ioFile->getPathInfo($label); + $extension = $pathInfo['extension'] ?? null; $fileExtensions = ArrayObjectSearch::getArrayElementByName( $rules, 'file_extensions' @@ -219,12 +238,14 @@ protected function _validateByRules($value) */ protected function _isUploadedFile($filename) { + // phpcs:ignore Magento2.Functions.DiscouragedFunction if (is_uploaded_file($filename)) { return true; } // This case is required for file uploader UI component - $temporaryFile = FileProcessor::TMP_DIR . '/' . pathinfo($filename)['basename']; + $temporaryFile = FileProcessor::TMP_DIR . DIRECTORY_SEPARATOR . + $this->ioFile->getPathInfo($filename)['basename']; if ($this->fileProcessor->isExist($temporaryFile)) { return true; } @@ -290,10 +311,9 @@ public function compactValue($value) return $value; } - if (isset($value['file']) && !empty($value['file'])) { - if ($value['file'] == $this->_value) { - return $this->_value; - } + if ($value && is_string($value) && $this->fileProcessor->isExist($value)) { + $result = $value; + } elseif (isset($value['file']) && !empty($value['file'])) { $result = $this->processUiComponentValue($value); } else { $result = $this->processInputFieldValue($value); @@ -310,6 +330,9 @@ public function compactValue($value) */ protected function processUiComponentValue(array $value) { + if ($value['file'] == $this->_value) { + return $this->_value; + } $result = $this->fileProcessor->moveTemporaryFile($value['file']); return $result; } @@ -338,7 +361,8 @@ protected function processInputFieldValue($value) $result = $this->_value; if ($toDelete) { - $mediaDir->delete($this->_entityTypeCode . '/' . ltrim($this->_value, '/')); + $mediaDir->delete($this->_entityTypeCode . DIRECTORY_SEPARATOR . + ltrim($this->_value, DIRECTORY_SEPARATOR)); $result = ''; } @@ -363,7 +387,10 @@ protected function processInputFieldValue($value) */ public function restoreValue($value) { - return $this->_value; + if (!empty($this->_value)) { + return $this->_value; + } + return $this->compactValue($value); } /** diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFillCustomerMainDataActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFillCustomerMainDataActionGroup.xml new file mode 100644 index 0000000000000..dc7d68faf362d --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFillCustomerMainDataActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminFillCustomerMainDataActionGroup"> + <annotations> + <description>Fill customer main required data. Starts on customer creation/edit page.</description> + </annotations> + + <arguments> + <argument name="firstName" type="string" defaultValue="{{Simple_US_Customer.firstname}}"/> + <argument name="lastName" type="string" defaultValue="{{Simple_US_Customer.lastname}}"/> + <argument name="email" type="string" defaultValue="{{Simple_US_Customer.email}}"/> + </arguments> + <waitForElementVisible selector="{{AdminCustomerAccountInformationSection.firstName}}" stepKey="waitForCustomerPageLoad"/> + <fillField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="{{firstName}}" stepKey="fillFirstName"/> + <fillField selector="{{AdminCustomerAccountInformationSection.lastName}}" userInput="{{lastName}}" stepKey="fillLastName"/> + <fillField selector="{{AdminCustomerAccountInformationSection.email}}" userInput="{{email}}" stepKey="fillEmail"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCreateCustomerSaveActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCreateCustomerSaveActionGroup.xml new file mode 100644 index 0000000000000..d4ac7edffd47a --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCreateCustomerSaveActionGroup.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontCreateCustomerSaveActionGroup"> + <click selector="{{StorefrontCustomerCreateFormSection.createAccountButton}}" stepKey="clickCreateAccountButton"/> + <waitForElementVisible selector="{{StorefrontMessagesSection.success}}" stepKey="waitForSuccessMessageVisible"/> + <see selector="{{StorefrontMessagesSection.success}}" userInput="Thank you for registering with " stepKey="verifySuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerSaveActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerSaveActionGroup.xml new file mode 100644 index 0000000000000..88c1d70bb9abb --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerSaveActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontCustomerSaveActionGroup"> + <annotations> + <description>Clicks on customer save button in dashboard, asserts success message</description> + </annotations> + <scrollToTopOfPage stepKey="scrollToTopOfThePage"/> + <click selector="{{StorefrontCustomerAccountInformationSection.saveButton}}" stepKey="saveCustomerOnStoreFront"/> + <waitForElementVisible selector="{{StorefrontMessagesSection.success}}" stepKey="waitForSuccessMessageVisible"/> + <see selector="{{StorefrontMessagesSection.success}}" userInput="You saved the account information." stepKey="verifySuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/ImageData.xml b/app/code/Magento/Customer/Test/Mftf/Data/ImageData.xml new file mode 100644 index 0000000000000..3abd51883434b --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Data/ImageData.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="SmallImage" type="imageFile"> + <data key="file">small.jpg</data> + <data key="name">small</data> + <data key="extension">jpg</data> + </entity> +</entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerCreateFormSection/StoreFrontCustomerAdvancedAttributesSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerCreateFormSection/StoreFrontCustomerAdvancedAttributesSection.xml index b2f96eb539c08..d03e088104807 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerCreateFormSection/StoreFrontCustomerAdvancedAttributesSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerCreateFormSection/StoreFrontCustomerAdvancedAttributesSection.xml @@ -20,5 +20,7 @@ <element name="yesNoOptionAttribute" type="select" selector="//select[@id='{{var}}']/option[2]" parameterized="true"/> <element name="selectedOption" type="text" selector="//select[@id='{{var}}']/option[@selected='selected']" parameterized="true"/> <element name="attributeLabel" type="text" selector="//span[text()='{{attributeLabel}}']" parameterized="true"/> + <element name="fileAttribute" type="file" selector="//input[@type='file' and @name='{{attributeCode}}']" parameterized="true" timeout="30"/> + <element name="customFileAttributeUploadButton" type="input" selector=".file-uploader-area input[name='{{attributeCode}}'] ~ .file-uploader-button" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php index a10cfe207b822..37239884aeb4f 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php @@ -495,7 +495,7 @@ public function testExecute( $this->request->expects($this->once()) ->method('isPost') ->willReturn(true); - $this->request->expects($this->exactly(3)) + $this->request->expects($this->exactly(4)) ->method('getParam') ->willReturnMap([ ['id', null, $addressId], diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php index d3a6e797c7d5c..3c5016df230f9 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php @@ -103,29 +103,31 @@ public function testExtractValueNoRequestScope($expected, $attributeCode = '', $ $value = 'value'; $this->requestMock->expects( - $this->any() + $this->at(0) )->method( 'getParam' - )->willReturn( - ['delete' => $delete] + )->will( + $this->returnValue(['delete' => $delete]) ); $this->attributeMetadataMock->expects( $this->any() )->method( 'getAttributeCode' - )->willReturn( - $attributeCode + )->will( + $this->returnValue($attributeCode) ); if (!empty($attributeCode)) { $_FILES[$attributeCode] = ['attributeCodeValue']; } - $model = $this->initialize([ - 'value' => $value, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => $value, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertEquals($expected, $model->extractValue($this->requestMock)); if (!empty($attributeCode)) { @@ -157,33 +159,35 @@ public function testExtractValueWithRequestScope($expected, $requestScope, $main $value = 'value'; $this->requestMock->expects( - $this->any() + $this->at(0) )->method( 'getParam' - )->willReturn( - ['delete' => true] + )->will( + $this->returnValue(['delete' => true]) ); $this->requestMock->expects( $this->any() )->method( 'getParams' - )->willReturn( - ['delete' => true] + )->will( + $this->returnValue(['delete' => true]) ); $this->attributeMetadataMock->expects( $this->any() )->method( 'getAttributeCode' - )->willReturn( - 'attributeCode' + )->will( + $this->returnValue('attributeCode') ); - $model = $this->initialize([ - 'value' => $value, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => $value, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $model->setRequestScope($requestScope); @@ -229,22 +233,24 @@ public function testValidateValueNotToUpload($expected, $value, $isAjax = false, $this->any() )->method( 'isRequired' - )->willReturn( - $isRequired + )->will( + $this->returnValue($isRequired) ); $this->attributeMetadataMock->expects( $this->any() )->method( 'getStoreLabel' - )->willReturn( - 'attributeLabel' + )->will( + $this->returnValue('attributeLabel') ); - $model = $this->initialize([ - 'value' => $value, - 'isAjax' => $isAjax, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => $value, + 'isAjax' => $isAjax, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertEquals($expected, $model->validateValue($value)); } @@ -272,39 +278,41 @@ public function testValidateValueToUpload($expected, $value, $parameters = []) { $parameters = array_merge(['uploaded' => true, 'valid' => true], $parameters); - $this->attributeMetadataMock->expects($this->any())->method('isRequired')->willReturn(false); + $this->attributeMetadataMock->expects($this->any())->method('isRequired')->will($this->returnValue(false)); $this->attributeMetadataMock->expects( $this->any() )->method( 'getStoreLabel' - )->willReturn( - 'File Input Field Label' + )->will( + $this->returnValue('File Input Field Label') ); $this->fileValidatorMock->expects( $this->any() )->method( 'getMessages' - )->willReturn( - ['Validation error message.'] + )->will( + $this->returnValue(['Validation error message.']) ); $this->fileValidatorMock->expects( $this->any() )->method( 'isValid' - )->willReturn( - $parameters['valid'] + )->will( + $this->returnValue($parameters['valid']) ); $this->fileProcessorMock->expects($this->any()) ->method('isExist') ->willReturn($parameters['uploaded']); - $model = $this->initialize([ - 'value' => $value, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => $value, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertEquals($expected, $model->validateValue($value)); } @@ -331,24 +339,28 @@ public function validateValueToUploadDataProvider() public function testCompactValueIsAjax() { - $model = $this->initialize([ - 'value' => 'value', - 'isAjax' => true, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => 'value', + 'isAjax' => true, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertSame($model, $model->compactValue('aValue')); } public function testCompactValueNoDelete() { - $this->attributeMetadataMock->expects($this->any())->method('isRequired')->willReturn(false); + $this->attributeMetadataMock->expects($this->any())->method('isRequired')->will($this->returnValue(false)); - $model = $this->initialize([ - 'value' => 'value', - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => 'value', + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->fileProcessorMock->expects($this->once()) ->method('removeUploadedFile') @@ -360,10 +372,10 @@ public function testCompactValueNoDelete() public function testCompactValueDelete() { - $this->attributeMetadataMock->expects($this->any())->method('isRequired')->willReturn(false); + $this->attributeMetadataMock->expects($this->any())->method('isRequired')->will($this->returnValue(false)); $mediaDirMock = $this->getMockForAbstractClass( - WriteInterface::class + \Magento\Framework\Filesystem\Directory\WriteInterface::class ); $mediaDirMock->expects($this->once()) ->method('delete') @@ -372,13 +384,15 @@ public function testCompactValueDelete() $this->fileSystemMock->expects($this->once()) ->method('getDirectoryWrite') ->with(DirectoryList::MEDIA) - ->willReturn($mediaDirMock); + ->will($this->returnValue($mediaDirMock)); - $model = $this->initialize([ - 'value' => 'value', - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => 'value', + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertSame('', $model->compactValue(['delete' => true])); } @@ -389,20 +403,20 @@ public function testCompactValueTmpFile() $expected = 'saved.file'; $mediaDirMock = $this->getMockForAbstractClass( - WriteInterface::class + \Magento\Framework\Filesystem\Directory\WriteInterface::class ); $this->fileSystemMock->expects($this->once()) ->method('getDirectoryWrite') ->with(DirectoryList::MEDIA) - ->willReturn($mediaDirMock); + ->will($this->returnValue($mediaDirMock)); $mediaDirMock->expects($this->any()) ->method('getAbsolutePath') - ->willReturnArgument(0); - $uploaderMock = $this->createMock(Uploader::class); + ->will($this->returnArgument(0)); + $uploaderMock = $this->createMock(\Magento\Framework\File\Uploader::class); $this->uploaderFactoryMock->expects($this->once()) ->method('create') ->with(['fileId' => $value]) - ->willReturn($uploaderMock); + ->will($this->returnValue($uploaderMock)); $uploaderMock->expects($this->once()) ->method('setFilesDispersion') ->with(true); @@ -417,13 +431,15 @@ public function testCompactValueTmpFile() ->with(self::ENTITY_TYPE, 'new.file'); $uploaderMock->expects($this->once()) ->method('getUploadedFileName') - ->willReturn($expected); + ->will($this->returnValue($expected)); - $model = $this->initialize([ - 'value' => null, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => null, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertSame($expected, $model->compactValue($value)); } @@ -432,11 +448,13 @@ public function testRestoreValue() { $value = 'value'; - $model = $this->initialize([ - 'value' => $value, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => $value, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertEquals($value, $model->restoreValue('aValue')); } @@ -447,11 +465,13 @@ public function testRestoreValue() */ public function testOutputValueNonJson($format) { - $model = $this->initialize([ - 'value' => 'value', - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => 'value', + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertSame('', $model->outputValue($format)); } @@ -480,29 +500,31 @@ public function testOutputValueJson() )->method( 'encode' )->with( - $value - )->willReturn( - $urlKey + $this->equalTo($value) + )->will( + $this->returnValue($urlKey) ); $expected = ['value' => $value, 'url_key' => $urlKey]; - $model = $this->initialize([ - 'value' => $value, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => $value, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertSame($expected, $model->outputValue(ElementFactory::OUTPUT_FORMAT_JSON)); } /** * @param array $data - * @return File + * @return \Magento\Customer\Model\Metadata\Form\File */ private function initialize(array $data) { - return new File( + return new \Magento\Customer\Model\Metadata\Form\File( $this->localeMock, $this->loggerMock, $this->attributeMetadataMock, @@ -528,22 +550,26 @@ public function testExtractValueFileUploaderUIComponent() ->method('getAttributeCode') ->willReturn($attributeCode); - $this->requestMock->expects($this->once()) + $this->requestMock->expects($this->at(0)) ->method('getParam') ->with($requestScope) - ->willReturn([ - $attributeCode => [ - [ - 'file' => $fileName, + ->willReturn( + [ + $attributeCode => [ + [ + 'file' => $fileName, + ], ], - ], - ]); - - $model = $this->initialize([ - 'value' => 'value', - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + ] + ); + + $model = $this->initialize( + [ + 'value' => 'value', + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $model->setRequestScope($requestScope); $result = $model->extractValue($this->requestMock); @@ -555,11 +581,13 @@ public function testCompactValueRemoveUiComponentValue() { $value = 'value'; - $model = $this->initialize([ - 'value' => $value, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => $value, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->fileProcessorMock->expects($this->once()) ->method('removeUploadedFile') @@ -573,11 +601,13 @@ public function testCompactValueNoAction() { $value = 'value'; - $model = $this->initialize([ - 'value' => $value, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => $value, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertEquals($value, $model->compactValue($value)); } @@ -588,11 +618,13 @@ public function testCompactValueUiComponent() 'file' => 'filename', ]; - $model = $this->initialize([ - 'value' => null, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => null, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->fileProcessorMock->expects($this->once()) ->method('moveTemporaryFile') @@ -613,7 +645,7 @@ public function testCompactValueInputField() $uploadedFilename = 'filename.ext1'; $mediaDirectoryMock = $this->getMockBuilder( - WriteInterface::class + \Magento\Framework\Filesystem\Directory\WriteInterface::class ) ->getMockForAbstractClass(); $mediaDirectoryMock->expects($this->once()) @@ -627,9 +659,8 @@ public function testCompactValueInputField() ->willReturn($mediaDirectoryMock); $uploaderMock = $this->getMockBuilder( - Uploader::class - )->disableOriginalConstructor() - ->getMock(); + \Magento\Framework\File\Uploader::class + )->disableOriginalConstructor()->getMock(); $uploaderMock->expects($this->once()) ->method('setFilesDispersion') ->with(true) @@ -655,11 +686,13 @@ public function testCompactValueInputField() ->with(['fileId' => $value]) ->willReturn($uploaderMock); - $model = $this->initialize([ - 'value' => null, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => null, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertEquals($uploadedFilename, $model->compactValue($value)); } @@ -674,7 +707,7 @@ public function testCompactValueInputFieldWithException() $originValue = 'origin'; $mediaDirectoryMock = $this->getMockBuilder( - WriteInterface::class + \Magento\Framework\Filesystem\Directory\WriteInterface::class )->getMockForAbstractClass(); $mediaDirectoryMock->expects($this->once()) ->method('delete') @@ -697,11 +730,13 @@ public function testCompactValueInputFieldWithException() ->with($exception) ->willReturnSelf(); - $model = $this->initialize([ - 'value' => $originValue, - 'isAjax' => false, - 'entityTypeCode' => self::ENTITY_TYPE, - ]); + $model = $this->initialize( + [ + 'value' => $originValue, + 'isAjax' => false, + 'entityTypeCode' => self::ENTITY_TYPE, + ] + ); $this->assertEquals('', $model->compactValue($value)); } diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 1f23e4480ec1c..3e708d1a0df02 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -674,7 +674,7 @@ public function initFromOrderItem(\Magento\Sales\Model\Order\Item $orderItem, $q if (in_array($option['option_type'], ['date', 'date_time', 'time', 'file'])) { $product->setSkipCheckRequiredOption(false); $formattedOptions[$option['option_id']] = - $buyRequest->getDataByKey('options')[$option['option_id']]; + $buyRequest->getDataByKey('options')[$option['option_id']]; continue; } @@ -1661,7 +1661,8 @@ public function setAccountData($accountData) // emulate request $request = $form->prepareRequest($accountData); - $data = $form->extractData($request); + $requestScope = $request->getPostValue() ? 'order/account' : null; + $data = $form->extractData($request, $requestScope); $data = $form->restoreData($data); $customer = $this->customerFactory->create(); $this->dataObjectHelper->populateWithArray( diff --git a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php index c587d2322c298..36f5b7c9f4cdd 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php @@ -212,10 +212,15 @@ public function testSetAccountData() ->method('restoreData') ->willReturn(['group_id' => 1]); + $requestMock = $this->getMockBuilder(RequestInterface::class) + ->setMethods(['getPostValue']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $requestMock->expects($this->atLeastOnce())->method('getPostValue')->willReturn(null); $customerForm->method('prepareRequest') - ->willReturn($this->getMockForAbstractClass(RequestInterface::class)); + ->willReturn($requestMock); - $customer = $this->getMockForAbstractClass(CustomerInterface::class); + $customer = $this->createMock(CustomerInterface::class); $this->customerMapper->expects(self::atLeastOnce()) ->method('toFlatArray') ->willReturn(['group_id' => 1]); From c323afc418d1f3389feabe70e62c004c47d4fc0a Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Fri, 27 Nov 2020 10:30:14 +0200 Subject: [PATCH 24/32] MC-23545: Customer attribute of type file doesn't display in Account Information after created --- .../Magento/Customer/Controller/Account/EditPost.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Account/EditPost.php b/app/code/Magento/Customer/Controller/Account/EditPost.php index d2cc385b5793f..c2137f1b40019 100644 --- a/app/code/Magento/Customer/Controller/Account/EditPost.php +++ b/app/code/Magento/Customer/Controller/Account/EditPost.php @@ -212,10 +212,12 @@ public function execute() ); $attributeToDelete = $this->_request->getParam('delete_attribute_value'); - $this->deleteCustomerFileAttribute( - $customerCandidateDataObject, - $attributeToDelete - ); + if ($attributeToDelete !== null) { + $this->deleteCustomerFileAttribute( + $customerCandidateDataObject, + $attributeToDelete + ); + } try { // whether a customer enabled change email option From 6f68dc560f4318efec57430fe3903dd308ac83d9 Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Mon, 23 Nov 2020 14:43:40 +0200 Subject: [PATCH 25/32] MC-30171: Add to Cart Form wrong Form Key in FPC --- .../StorefrontProductActionSection.xml | 1 + ...gRecalculationAfterCouponCodeAddedTest.xml | 2 +- ...CartFormKeyValueIsNotCachedActionGroup.xml | 32 +++++++ ...rontCachedInputFormKeyValueUpdatedTest.xml | 46 +++++++++ .../PageCache/ViewModel/FormKeyProvider.php | 41 ++++++++ .../view/frontend/layout/default.xml | 7 ++ .../view/frontend/requirejs-config.js | 3 +- .../templates/form_key_provider.phtml | 14 +++ .../view/frontend/web/js/form-key-provider.js | 93 +++++++++++++++++++ .../view/frontend/web/js/page-cache.js | 7 +- .../frontend/js/form-key-provider.test.js | 46 +++++++++ .../PageCache/frontend/js/page-cache.test.js | 7 -- 12 files changed, 287 insertions(+), 12 deletions(-) create mode 100644 app/code/Magento/PageCache/Test/Mftf/ActionGroup/AssertStorefrontAddToCartFormKeyValueIsNotCachedActionGroup.xml create mode 100644 app/code/Magento/PageCache/Test/Mftf/Test/StorefrontCachedInputFormKeyValueUpdatedTest.xml create mode 100644 app/code/Magento/PageCache/ViewModel/FormKeyProvider.php create mode 100644 app/code/Magento/PageCache/view/frontend/templates/form_key_provider.phtml create mode 100644 app/code/Magento/PageCache/view/frontend/web/js/form-key-provider.js create mode 100644 dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/form-key-provider.test.js diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductActionSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductActionSection.xml index 13ced1c0263e0..64f365217d7e4 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductActionSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductActionSection.xml @@ -14,5 +14,6 @@ <element name="addToCartButtonTitleIsAdding" type="text" selector="//button/span[text()='Adding...']"/> <element name="addToCartButtonTitleIsAdded" type="text" selector="//button/span[text()='Added']"/> <element name="addToCartButtonTitleIsAddToCart" type="text" selector="//button/span[text()='Add to Cart']"/> + <element name="inputFormKey" type="text" selector="input[name='form_key']"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml index 20b94d0f4ec8a..40bdcff6ec937 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml @@ -88,7 +88,7 @@ <see userInput="Your coupon was successfully applied." stepKey="seeSuccessMessage"/> <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder1"/> <waitForPageLoad stepKey="waitForError"/> - <see stepKey="seeShippingMethodError" userInput="The shipping method is missing. Select the shipping method and try again."/> + <seeElementInDOM selector="{{CheckoutHeaderSection.errorMessageContainsText('The shipping method is missing. Select the shipping method and try again.')}}" stepKey="seeShippingMethodError"/> <amOnPage stepKey="navigateToShippingPage" url="{{CheckoutShippingPage.url}}"/> <waitForPageLoad stepKey="waitForShippingPageLoad"/> <click stepKey="chooseFlatRateShipping" selector="{{CheckoutShippingMethodsSection.shippingMethodRowByName('Flat Rate')}}"/> diff --git a/app/code/Magento/PageCache/Test/Mftf/ActionGroup/AssertStorefrontAddToCartFormKeyValueIsNotCachedActionGroup.xml b/app/code/Magento/PageCache/Test/Mftf/ActionGroup/AssertStorefrontAddToCartFormKeyValueIsNotCachedActionGroup.xml new file mode 100644 index 0000000000000..6ef5f878023a1 --- /dev/null +++ b/app/code/Magento/PageCache/Test/Mftf/ActionGroup/AssertStorefrontAddToCartFormKeyValueIsNotCachedActionGroup.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontAddToCartFormKeyValueIsNotCachedActionGroup"> + <annotations> + <description>Assert that product page add to cart form key is different from cached value.</description> + </annotations> + <arguments> + <argument name="cachedValue" type="string"/> + </arguments> + + <grabValueFrom selector="{{StorefrontProductActionSection.inputFormKey}}" stepKey="grabUpdatedValue"/> + <assertRegExp stepKey="validateCachedFormKey"> + <expectedResult type="string">/\w{16}/</expectedResult> + <actualResult type="string">{{cachedValue}}</actualResult> + </assertRegExp> + <assertRegExp stepKey="validateUpdatedFormKey"> + <expectedResult type="string">/\w{16}/</expectedResult> + <actualResult type="variable">grabUpdatedValue</actualResult> + </assertRegExp> + <assertNotEquals stepKey="assertFormKeyUpdated"> + <expectedResult type="string">{{cachedValue}}</expectedResult> + <actualResult type="variable">grabUpdatedValue</actualResult> + </assertNotEquals> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/PageCache/Test/Mftf/Test/StorefrontCachedInputFormKeyValueUpdatedTest.xml b/app/code/Magento/PageCache/Test/Mftf/Test/StorefrontCachedInputFormKeyValueUpdatedTest.xml new file mode 100644 index 0000000000000..a9d77429e3248 --- /dev/null +++ b/app/code/Magento/PageCache/Test/Mftf/Test/StorefrontCachedInputFormKeyValueUpdatedTest.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontCachedInputFormKeyValueUpdatedTest"> + <annotations> + <features value="PageCache"/> + <stories value="FormKey"/> + <title value="Form Key value should be updated by js script"/> + <description value="Form Key value should be updated by js script"/> + <testCaseId value="MC-39300"/> + <useCaseId value="MC-30171"/> + <severity value="AVERAGE"/> + <group value="pageCache"/> + </annotations> + <before> + <!-- Create Data --> + <createData entity="SimpleProduct2" stepKey="createProduct"/> + <actionGroup ref="CliCacheCleanActionGroup" stepKey="cleanCache"> + <argument name="tags" value="full_page"/> + </actionGroup> + </before> + <after> + <!-- Delete data --> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + </after> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductPage"> + <argument name="productUrl" value="$createProduct.custom_attributes[url_key]$"/> + </actionGroup> + <grabValueFrom selector="{{StorefrontProductActionSection.inputFormKey}}" stepKey="grabCachedValue"/> + <resetCookie userInput="PHPSESSID" stepKey="resetSessionCookie"/> + <resetCookie userInput="form_key" stepKey="resetFormKeyCookie"/> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="reopenProductPage"> + <argument name="productUrl" value="$createProduct.custom_attributes[url_key]$"/> + </actionGroup> + <actionGroup ref="AssertStorefrontAddToCartFormKeyValueIsNotCachedActionGroup" stepKey="assertValueIsUpdatedByScript"> + <argument name="cachedValue" value="{$grabCachedValue}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/PageCache/ViewModel/FormKeyProvider.php b/app/code/Magento/PageCache/ViewModel/FormKeyProvider.php new file mode 100644 index 0000000000000..26f6be43c627a --- /dev/null +++ b/app/code/Magento/PageCache/ViewModel/FormKeyProvider.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\PageCache\ViewModel; + +use Magento\Framework\View\Element\Block\ArgumentInterface; +use Magento\PageCache\Model\Config; + +/** + * Adds script to update form key from cookie after script rendering + */ +class FormKeyProvider implements ArgumentInterface +{ + /** + * @var Config + */ + private $config; + + /** + * @param Config $config + */ + public function __construct( + Config $config + ) { + $this->config = $config; + } + + /** + * Is full page cache enabled + * + * @return bool + */ + public function isFullPageCacheEnabled(): bool + { + return $this->config->isEnabled(); + } +} diff --git a/app/code/Magento/PageCache/view/frontend/layout/default.xml b/app/code/Magento/PageCache/view/frontend/layout/default.xml index 7e1fc9d31b864..3db4b1c4ae52e 100644 --- a/app/code/Magento/PageCache/view/frontend/layout/default.xml +++ b/app/code/Magento/PageCache/view/frontend/layout/default.xml @@ -10,6 +10,13 @@ <referenceBlock name="head.components"> <block class="Magento\Framework\View\Element\Js\Components" name="pagecache_page_head_components" template="Magento_PageCache::js/components.phtml"/> </referenceBlock> + <referenceBlock name="head.additional"> + <block name="form_key_provider" template="Magento_PageCache::form_key_provider.phtml"> + <arguments> + <argument name="form_key_provider" xsi:type="object">Magento\PageCache\ViewModel\FormKeyProvider</argument> + </arguments> + </block> + </referenceBlock> <referenceContainer name="content"> <block class="Magento\PageCache\Block\Javascript" template="Magento_PageCache::javascript.phtml" name="pageCache" as="pageCache"/> </referenceContainer> diff --git a/app/code/Magento/PageCache/view/frontend/requirejs-config.js b/app/code/Magento/PageCache/view/frontend/requirejs-config.js index 7a33e2748b916..59d4499092965 100644 --- a/app/code/Magento/PageCache/view/frontend/requirejs-config.js +++ b/app/code/Magento/PageCache/view/frontend/requirejs-config.js @@ -8,5 +8,6 @@ var config = { '*': { pageCache: 'Magento_PageCache/js/page-cache' } - } + }, + deps: ['Magento_PageCache/js/form-key-provider'] }; diff --git a/app/code/Magento/PageCache/view/frontend/templates/form_key_provider.phtml b/app/code/Magento/PageCache/view/frontend/templates/form_key_provider.phtml new file mode 100644 index 0000000000000..4f952002e458f --- /dev/null +++ b/app/code/Magento/PageCache/view/frontend/templates/form_key_provider.phtml @@ -0,0 +1,14 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +if ($block->getFormKeyProvider()->isFullPageCacheEnabled()): ?> + <script type="text/x-magento-init"> + { + "*": { + "Magento_PageCache/js/form-key-provider": {} + } + } + </script> +<?php endif; ?> diff --git a/app/code/Magento/PageCache/view/frontend/web/js/form-key-provider.js b/app/code/Magento/PageCache/view/frontend/web/js/form-key-provider.js new file mode 100644 index 0000000000000..c63d97840e946 --- /dev/null +++ b/app/code/Magento/PageCache/view/frontend/web/js/form-key-provider.js @@ -0,0 +1,93 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define(function () { + 'use strict'; + + return function () { + var formKey, + inputElements, + inputSelector = 'input[name="form_key"]'; + + /** + * Set form_key cookie + * @private + */ + function setFormKeyCookie(value) { + var expires, + secure, + date = new Date(), + isSecure = !!window.cookiesConfig && window.cookiesConfig.secure; + + date.setTime(date.getTime() + 86400000); + expires = '; expires=' + date.toUTCString(); + secure = isSecure ? '; secure' : ''; + + document.cookie = 'form_key=' + (value || '') + expires + secure + '; path=/'; + } + + /** + * Retrieves form key from cookie + * @private + */ + function getFormKeyCookie() { + var cookie, + i, + nameEQ = 'form_key=', + cookieArr = document.cookie.split(';'); + + for (i = 0; i < cookieArr.length; i++) { + cookie = cookieArr[i]; + + while (cookie.charAt(0) === ' ') { + cookie = cookie.substring(1, cookie.length); + } + + if (cookie.indexOf(nameEQ) === 0) { + return cookie.substring(nameEQ.length, cookie.length); + } + } + + return null; + } + + /** + * Generate form key string + * @private + */ + function generateFormKeyString() { + var result = '', + length = 16, + chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + while (length--) { + result += chars[Math.round(Math.random() * (chars.length - 1))]; + } + + return result; + } + + /** + * Init form_key inputs with value + * @private + */ + function initFormKey() { + formKey = getFormKeyCookie(); + + if (!formKey) { + formKey = generateFormKeyString(); + setFormKeyCookie(formKey); + } + inputElements = document.querySelectorAll(inputSelector); + + if (inputElements.length) { + Array.prototype.forEach.call(inputElements, function (element) { + element.setAttribute('value', formKey); + }); + } + } + + initFormKey(); + }; +}); diff --git a/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js b/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js index 41a32ab8a49c8..d7214918c530d 100644 --- a/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js +++ b/app/code/Magento/PageCache/view/frontend/web/js/page-cache.js @@ -7,9 +7,10 @@ define([ 'jquery', 'domReady', 'consoleLogger', + 'Magento_PageCache/js/form-key-provider', 'jquery-ui-modules/widget', 'mage/cookies' -], function ($, domReady, consoleLogger) { +], function ($, domReady, consoleLogger, formKeyInit) { 'use strict'; /** @@ -99,6 +100,7 @@ define([ /** * FormKey Widget - this widget is generating from key, saves it to cookie and + * @deprecated see Magento/PageCache/view/frontend/web/js/form-key-provider.js */ $.widget('mage.formKey', { options: { @@ -298,8 +300,7 @@ define([ }); domReady(function () { - $('body') - .formKey(); + formKeyInit(); }); return { diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/form-key-provider.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/form-key-provider.test.js new file mode 100644 index 0000000000000..162c00a9c0cca --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/form-key-provider.test.js @@ -0,0 +1,46 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/* eslint-disable max-nested-callbacks */ +define([ + 'jquery', + 'Magento_PageCache/js/form-key-provider' +], function ($, formKeyInit) { + 'use strict'; + + describe('Testing FormKey Provider', function () { + var inputContainer; + + beforeEach(function () { + inputContainer = document.createElement('input'); + inputContainer.setAttribute('value', ''); + inputContainer.setAttribute('name', 'form_key'); + document.querySelector('body').appendChild(inputContainer); + }); + + afterEach(function () { + $(inputContainer).remove(); + document.cookie = 'form_key= ; expires = Thu, 01 Jan 1970 00:00:00 GMT'; + }); + + it('sets value of input[form_key]', function () { + var expires, + date = new Date(); + + date.setTime(date.getTime() + 86400000); + expires = '; expires=' + date.toUTCString(); + document.cookie = 'form_key=FAKE_COOKIE' + expires + '; path=/'; + formKeyInit(); + expect($(inputContainer).val()).toEqual('FAKE_COOKIE'); + }); + + it('widget sets value to input[form_key] in case it empty', function () { + document.cookie = 'form_key= ; expires = Thu, 01 Jan 1970 00:00:00 GMT'; + formKeyInit(); + expect($(inputContainer).val()).toEqual(jasmine.any(String)); + expect($(inputContainer).val().length).toEqual(16); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/page-cache.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/page-cache.test.js index 14e0523fd5151..f12d36e888f22 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/page-cache.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/page-cache.test.js @@ -106,13 +106,6 @@ define([ expect($.mage.cookies.set).toHaveBeenCalled(); expect(inputContainer.val()).toEqual(jasmine.any(String)); }); - - it('widget exists on load on body', function (done) { - $(function () { - expect($('body').data('mageFormKey')).toBeDefined(); - done(); - }); - }); }); describe('Testing PageCache Widget', function () { From e89999511d1aee15821286aa6a072ec8d2edd435 Mon Sep 17 00:00:00 2001 From: engcom-Kilo <mikola.malevanec@transoftgroup.com> Date: Wed, 25 Nov 2020 09:45:45 +0200 Subject: [PATCH 26/32] MC-38344: Wrong date show in datepicker after saving a cart price rule, product special price date on administrator Dutch locale. --- .../Magento/Ui/view/base/web/js/form/element/date.js | 2 +- .../code/Magento/Ui/base/js/form/element/date.test.js | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/date.js b/app/code/Magento/Ui/view/base/web/js/form/element/date.js index 1432372dd75a9..af9142745206b 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/date.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/date.js @@ -127,7 +127,7 @@ define([ if (this.options.showsTime) { shiftedValue = moment.tz(value, 'UTC').tz(this.storeTimeZone); } else { - shiftedValue = moment(value, this.outputDateFormat); + shiftedValue = moment(value, this.outputDateFormat, true); } if (!shiftedValue.isValid()) { diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js index f9d379407fcbd..91f37e20cca87 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js @@ -40,8 +40,12 @@ define([ name: '', index: '', dataScope: dataScope, + outputDateFormat: 'DD-MM-YYYY', + inputDateFormat: 'YYYY-MM-DD', + pickerDateTimeFormat: 'DD-MM-YYYY', options: { - showsTime: true + showsTime: false, + dateFormat: 'dd-MM-y' } }); utils = mageUtils; @@ -56,5 +60,10 @@ define([ expect(utils.convertToMomentFormat).toHaveBeenCalled(); }); + it('Check date will have correct value with different locales.', function () { + model.value('2020-11-28'); + expect(model.getPreview()).toBe('28-11-2020'); + }); + }); }); From 7b7cf03a5fec86e4a0c79441d70929185bcccfe9 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Mon, 30 Nov 2020 13:44:23 +0200 Subject: [PATCH 27/32] MC-37085: Create automated test for "Storefront Gallery behaviour for Product with media" --- ...gingFullscreenImageByRibbonActionGroup.xml | 27 + ...ryChangingMainImageByRibbonActionGroup.xml | 27 + ...leryFullscreenThumbnailDragActionGroup.xml | 29 ++ ...tPageGalleryImageDimensionsActionGroup.xml | 34 ++ ...gePositionInThumbnailRibbonActionGroup.xml | 25 + ...PageGalleryMainImageButtonsActionGroup.xml | 28 ++ ...uctPageGalleryThumbnailDragActionGroup.xml | 32 ++ ...ageGalleryDragMainImageBackActionGroup.xml | 19 + ...GalleryDragMainImageForwardActionGroup.xml | 19 + .../Catalog/Test/Mftf/Data/ImageData.xml | 48 ++ .../Catalog/Test/Mftf/Data/ProductData.xml | 1 + .../Section/StorefrontProductMediaSection.xml | 16 +- ...ontProductWithMediaGalleryBehaviorTest.xml | 463 ++++++++++++++++++ 13 files changed, 765 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryChangingFullscreenImageByRibbonActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryChangingMainImageByRibbonActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryFullscreenThumbnailDragActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryImageDimensionsActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryMainImageButtonsActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryThumbnailDragActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageGalleryDragMainImageBackActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageGalleryDragMainImageForwardActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductWithMediaGalleryBehaviorTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryChangingFullscreenImageByRibbonActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryChangingFullscreenImageByRibbonActionGroup.xml new file mode 100644 index 0000000000000..6423bf5e319b7 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryChangingFullscreenImageByRibbonActionGroup.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontProductPageGalleryChangingFullscreenImageByRibbonActionGroup"> + <annotations> + <description>On the product page change main image by clicking on the images in the ribbon. Fullscreen</description> + </annotations> + <arguments> + <argument name="startImage" type="string" /> + <argument name="expectedImage" type="string" /> + </arguments> + <waitForElementVisible selector="{{StorefrontProductMediaSection.productImageFullscreen(startImage)}}" stepKey="seeStartFullscreenImage"/> + <seeElement selector="{{StorefrontProductMediaSection.imgSelectedInThumbnail(startImage)}}" stepKey="seeActiveImageInThumbnail"/> + <click selector="{{StorefrontProductMediaSection.productImageInFotorama(expectedImage)}}" stepKey="clickOnExpectedImage"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(expectedImage)}}" stepKey="seeExpectedImageAfterClick"/> + <seeElement selector="{{StorefrontProductMediaSection.imgSelectedInThumbnail(expectedImage)}}" stepKey="seeExpectedImageActiveInThumbnailAfterChange"/> + <click selector="{{StorefrontProductMediaSection.productImageInFotorama(startImage)}}" stepKey="clickOnStartImageInRibbon"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(startImage)}}" stepKey="seeStartImageAfterSecondChange"/> + <seeElement selector="{{StorefrontProductMediaSection.imgSelectedInThumbnail(startImage)}}" stepKey="seeStartImageActiveInThumbnailAfterSecondChange"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryChangingMainImageByRibbonActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryChangingMainImageByRibbonActionGroup.xml new file mode 100644 index 0000000000000..b196956135043 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryChangingMainImageByRibbonActionGroup.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontProductPageGalleryChangingMainImageByRibbonActionGroup"> + <annotations> + <description>Changing main image on product page media gallery by clicking on the images in the fotorama ribbon</description> + </annotations> + <arguments> + <argument name="startImage" type="string" /> + <argument name="expectedImage" type="string" /> + </arguments> + <waitForElementVisible selector="{{StorefrontProductMediaSection.productImage(startImage)}}" stepKey="waitActiveImageDefault"/> + <seeElement selector="{{StorefrontProductMediaSection.imgSelectedInThumbnail(startImage)}}" stepKey="seeActiveImageThumbnail"/> + <click selector="{{StorefrontProductMediaSection.productImageInFotorama(expectedImage)}}" stepKey="firstClickOnImageInRibbon"/> + <seeElement selector="{{StorefrontProductMediaSection.imgSelectedInThumbnail(expectedImage)}}" stepKey="seeExpectedImageSelectedInRibbon"/> + <seeElement selector="{{StorefrontProductMediaSection.productImage(expectedImage)}}" stepKey="seeChangedImageAfterFirstClick"/> + <click selector="{{StorefrontProductMediaSection.productImageInFotorama(startImage)}}" stepKey="secondClickOnImageInRibbon"/> + <seeElement selector="{{StorefrontProductMediaSection.imgSelectedInThumbnail(startImage)}}" stepKey="seeStartImageSelectedInRibbonAfterSecondClick"/> + <seeElement selector="{{StorefrontProductMediaSection.productImage(startImage)}}" stepKey="seeChangedImageAfterSecondClick"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryFullscreenThumbnailDragActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryFullscreenThumbnailDragActionGroup.xml new file mode 100644 index 0000000000000..86803aed4cfb6 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryFullscreenThumbnailDragActionGroup.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontProductPageGalleryFullscreenThumbnailDragActionGroup"> + <annotations> + <description>On the product page check functional of drag actions in the fotorama ribbon during fullscreen</description> + </annotations> + <arguments> + <argument name="dragPointImage" type="string" /> + <argument name="currentImage" type="string"/> + <argument name="firstImage" type="string" /> + </arguments> + <waitForElementVisible selector="{{StorefrontProductMediaSection.productImageFullscreen(currentImage)}}" stepKey="seeFullscreenImage"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageInFotorama(firstImage)}}" stepKey="seeFirstImageInRibbon"/> + <dragAndDrop selector1="{{StorefrontProductMediaSection.productImageInFotorama(dragPointImage)}}" selector2="{{StorefrontProductMediaSection.productImageInFotorama(dragPointImage)}}" x="-300" y="0" stepKey="dragRibbon"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(currentImage)}}" stepKey="seeFullscreenImageAfterDrag"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.productImageInFotorama(firstImage)}}" stepKey="dontSeeFirstImageInRibbonAfterDrag"/> + <dragAndDrop selector1="{{StorefrontProductMediaSection.productImageInFotorama(dragPointImage)}}" selector2="{{StorefrontProductMediaSection.productImageInFotorama(dragPointImage)}}" x="300" y="0" stepKey="dragBackRibbon"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(currentImage)}}" stepKey="seeMainImageAfterBackDrag"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageInFotorama(firstImage)}}" stepKey="seeFirstImageInRibbonAfterBackDrag"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryImageDimensionsActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryImageDimensionsActionGroup.xml new file mode 100644 index 0000000000000..7b6a8e14455ca --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryImageDimensionsActionGroup.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontProductPageGalleryImageDimensionsActionGroup"> + <annotations> + <description>On the product page grab dimensions of the displayed product image, and image section. Assert that image is less or equals</description> + </annotations> + <arguments> + <argument name="imageSource" defaultValue="{{StorefrontProductMediaSection.mainImageForJsActions}}" type="string"/> + </arguments> + <executeJS function="var img=document.querySelector('{{imageSource}}'); + return img.clientHeight;" stepKey="getImageHeight"/> + <executeJS function="var img=document.querySelector('{{imageSource}}'); + return img.clientWidth;" stepKey="getImageWidth"/> + <executeJS function="var img=document.querySelector('{{StorefrontProductMediaSection.imageSectionForJsActions}}'); + return img.clientHeight;" stepKey="getSectionHeight"/> + <executeJS function="var img=document.querySelector('{{StorefrontProductMediaSection.imageSectionForJsActions}}'); + return img.clientWidth;" stepKey="getSectionWidth"/> + <assertLessThanOrEqual stepKey="checkHeightIsCorrect"> + <actualResult type="variable">getImageHeight</actualResult> + <expectedResult type="variable">getSectionHeight</expectedResult> + </assertLessThanOrEqual> + <assertLessThanOrEqual stepKey="checkWidthIsCorrect"> + <actualResult type="variable">getImageWidth</actualResult> + <expectedResult type="variable">getSectionWidth</expectedResult> + </assertLessThanOrEqual> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup.xml new file mode 100644 index 0000000000000..6473f348648f2 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup"> + <annotations> + <description>Check the expected image position in the fotorama ribbon on the product page</description> + </annotations> + <arguments> + <argument name="image" defaultValue="Magento2.filename" type="string"/> + <argument name="extension" defaultValue="Magento2.file_extension" type="string"/> + <argument name="position" defaultValue="0" type="string" /> + </arguments> + <grabAttributeFrom userInput="src" selector="{{StorefrontProductMediaSection.fotoramaImageThumbnailImgByNumber(position)}}" stepKey="grabSrcFromThumbnailImageByPosition"/> + <assertRegExp stepKey="checkImagePositionInThumbnail"> + <actualResult type="variable">$grabSrcFromThumbnailImageByPosition</actualResult> + <expectedResult type="string">|{{image}}[_\d]*.{{extension}}|</expectedResult> + </assertRegExp> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryMainImageButtonsActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryMainImageButtonsActionGroup.xml new file mode 100644 index 0000000000000..d4cc3097946be --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryMainImageButtonsActionGroup.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontProductPageGalleryMainImageButtonsActionGroup"> + <annotations> + <description>Assert the buttons functionality "change image" on the product media gallery on the product page</description> + </annotations> + <arguments> + <argument name="startImage" type="string" /> + <argument name="expectedImage" type="string" /> + </arguments> + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> + <waitForElementVisible selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="waitForButtons"/> + <seeElement selector="{{StorefrontProductMediaSection.productImage(startImage)}}" stepKey="seeProductImageBeforeActions"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButton"/> + <seeElement selector="{{StorefrontProductMediaSection.imgSelectedInThumbnail(expectedImage)}}" stepKey="seeExpectedImageSelectedInRibbon"/> + <seeElement selector="{{StorefrontProductMediaSection.productImage(expectedImage)}}" stepKey="seeExpectedImageOnPreview"/> + <click selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="clickOnPrevImageButton"/> + <seeElement selector="{{StorefrontProductMediaSection.imgSelectedInThumbnail(startImage)}}" stepKey="seeActiveImageSelectedInRibbonAfterSecondChange"/> + <seeElement selector="{{StorefrontProductMediaSection.productImage(startImage)}}" stepKey="seeMainProductImageAfterSecondChange"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryThumbnailDragActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryThumbnailDragActionGroup.xml new file mode 100644 index 0000000000000..2e62d973ea090 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductPageGalleryThumbnailDragActionGroup.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontProductPageGalleryThumbnailDragActionGroup"> + <annotations> + <description>Check functional of drag actions in the thumbnail ribbon on the product page</description> + </annotations> + <arguments> + <argument name="dragPointImage" type="string" /> + <argument name="currentImage" type="string"/> + <argument name="firstImage" type="string" /> + </arguments> + <waitForElementVisible selector="{{StorefrontProductMediaSection.productImage(currentImage)}}" stepKey="seeMainImageBeforeDragActions"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.fotoramaPrevButton}}" stepKey="dontSeePrevButtonBeforeDragActions"/> + <dragAndDrop selector1="{{StorefrontProductMediaSection.productImageInFotorama(dragPointImage)}}" selector2="{{StorefrontProductMediaSection.productImageInFotorama(dragPointImage)}}" x="-300" y="0" stepKey="dragRibbonForward"/> + <seeElement selector="{{StorefrontProductMediaSection.productImage(currentImage)}}" stepKey="seeMainImageDontChangeAfterDrag"/> + <waitForElementVisible selector="{{StorefrontProductMediaSection.fotoramaPrevButton}}" stepKey="waitPrevButton"/> + <seeElement selector="{{StorefrontProductMediaSection.fotoramaPrevButton}}" stepKey="seePrevButton"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.productImageInFotorama(firstImage)}}" stepKey="dontSeeFirstImageInRibbonAfterDrag"/> + <dragAndDrop selector1="{{StorefrontProductMediaSection.productImageInFotorama(dragPointImage)}}" selector2="{{StorefrontProductMediaSection.productImageInFotorama(dragPointImage)}}" x="300" y="0" stepKey="dragBackRibbon"/> + <seeElement selector="{{StorefrontProductMediaSection.productImage(currentImage)}}" stepKey="seeMainImageDontChangeAfterBackDrag"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageInFotorama(firstImage)}}" stepKey="seeFirstImageInRibbonAfterBackDrag"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.fotoramaPrevButton}}" stepKey="dontSeePrevButtonAfterBackDrag"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageGalleryDragMainImageBackActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageGalleryDragMainImageBackActionGroup.xml new file mode 100644 index 0000000000000..4925d6627a0b3 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageGalleryDragMainImageBackActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontProductPageGalleryDragMainImageBackActionGroup"> + <annotations> + <description>Drag back main image in the media gallery of product page</description> + </annotations> + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOnProductImage"/> + <waitForElementVisible selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="waitNextButton"/> + <dragAndDrop selector1="{{StorefrontProductMediaSection.mainImageForJsActions}}" selector2="{{StorefrontProductMediaSection.imageNextButton}}" x="200" y="0" stepKey="dragImageBack"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageGalleryDragMainImageForwardActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageGalleryDragMainImageForwardActionGroup.xml new file mode 100644 index 0000000000000..a75a25e31717b --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageGalleryDragMainImageForwardActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontProductPageGalleryDragMainImageForwardActionGroup"> + <annotations> + <description>Drag forward main image in the media gallery of product page</description> + </annotations> + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOnProductImage"/> + <waitForElementVisible selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="waitNextButton"/> + <dragAndDrop selector1="{{StorefrontProductMediaSection.mainImageForJsActions}}" selector2="{{StorefrontProductMediaSection.imagePrevButton}}" x="-366" y="0" stepKey="dragImage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ImageData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ImageData.xml index a2391dda54809..e1072001b56e5 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ImageData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ImageData.xml @@ -25,4 +25,52 @@ <data key="name">adobe-thumb</data> <data key="extension">jpg</data> </entity> + <entity name="AdobeSmallImage" type="image"> + <data key="title" unique="suffix">magento-small</data> + <data key="file">adobe-small.jpg</data> + <data key="filename">adobe-small</data> + <data key="file_extension">jpg</data> + </entity> + <entity name="AdobeThumbImage" type="image"> + <data key="title" unique="suffix">magento-thumb</data> + <data key="file">adobe-thumb.jpg</data> + <data key="filename">adobe-thumb</data> + <data key="file_extension">jpg</data> + </entity> + <entity name="JpgImage" type="image"> + <data key="title" unique="suffix">jpgimage</data> + <data key="file">jpg.jpg</data> + <data key="filename">jpg</data> + <data key="file_extension">jpg</data> + </entity> + <entity name="LargeImage" type="image"> + <data key="title" unique="suffix">largeimage</data> + <data key="file">large.jpg</data> + <data key="filename">large</data> + <data key="file_extension">jpg</data> + </entity> + <entity name="MagentoImage" type="image"> + <data key="title" unique="suffix">magentoimage</data> + <data key="file">magento.jpg</data> + <data key="filename">magento</data> + <data key="file_extension">jpg</data> + </entity> + <entity name="MagentoStage" type="image"> + <data key="title" unique="suffix">magentostage</data> + <data key="file">magentoStage.jpg</data> + <data key="filename">magentoStage</data> + <data key="file_extension">jpg</data> + </entity> + <entity name="MediumImage" type="image"> + <data key="title" unique="suffix">mediumimage</data> + <data key="file">medium.jpg</data> + <data key="filename">medium</data> + <data key="file_extension">jpg</data> + </entity> + <entity name="PngImage" type="image"> + <data key="title" unique="suffix">magentoimage</data> + <data key="file">png.png</data> + <data key="filename">png</data> + <data key="file_extension">png</data> + </entity> </entities> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index e7760a9b90f0c..f4e468a939111 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -370,6 +370,7 @@ <data key="shareable">Yes</data> <data key="file">magento-logo.png</data> <data key="fileName">magento-logo</data> + <data key="file_extension">png</data> </entity> <entity name="MagentoLogo" type="image"> <data key="title" unique="suffix">MagentoLogo</data> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductMediaSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductMediaSection.xml index 447113ea65bb2..5efa094e2c35e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductMediaSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductMediaSection.xml @@ -16,11 +16,21 @@ <element name="closeFullscreenImage" type="button" selector="//*[@data-gallery-role='gallery' and contains(@class, 'fullscreen')]//*[@data-gallery-role='fotorama__fullscreen-icon']" /> <element name="imageFile" type="text" selector="//*[@class='product media']//img[contains(@src, '{{filename}}')]" parameterized="true"/> <element name="productImageActive" type="text" selector=".product.media div[data-active=true] > img[src*='{{filename}}']" parameterized="true"/> - <element name="productImageInFotorama" type="file" selector=".fotorama__nav__shaft img[src*='{{imageName}}']" parameterized="true"/> - <element name="fotoramaPrevButton" type="button" selector="//*[@data-gallery-role='gallery']//*[@data-gallery-role='nav-wrap']//*[@data-gallery-role='arrow' and contains(@class, 'fotorama__thumb__arr--left')]"/> - <element name="fotoramaNextButton" type="button" selector="//*[@data-gallery-role='gallery']//*[@data-gallery-role='nav-wrap']//*[@data-gallery-role='arrow' and contains(@class, 'fotorama__thumb__arr--right')]"/> + <element name="productImageInFotorama" type="file" selector=".fotorama__nav__shaft img[src*='{{imageName}}']" parameterized="true" timeout="30"/> + <element name="fotoramaPrevButton" type="button" selector="//*[@data-gallery-role='gallery']//*[@data-gallery-role='nav-wrap']//*[@data-gallery-role='arrow' and contains(@class, 'fotorama__thumb__arr--left')]" timeout="30"/> + <element name="fotoramaNextButton" type="button" selector="//*[@data-gallery-role='gallery']//*[@data-gallery-role='nav-wrap']//*[@data-gallery-role='arrow' and contains(@class, 'fotorama__thumb__arr--right')]" timeout="30"/> + <element name="fotoramaNextButtonVideo" type="button" selector="div.fotorama__arr.fotorama__arr--next.fotorama__arr--shown" timeout="30"/> <element name="fotoramaAnyMedia" type="text" selector=".fotorama__nav__shaft img"/> <element name="fotoramaImageThumbnail" type="block" selector="//div[contains(@class, 'fotorama__nav__shaft')]//div[contains(@class, 'fotorama__nav__frame--thumb')][{{imageNumber}}]" parameterized="true" timeout="30"/> + <element name="fotoramaImageThumbnailImgByNumber" type="block" selector="//div[contains(@class, 'fotorama__nav__shaft')]//div[contains(@class, 'fotorama__nav__frame--thumb')][{{imageNumber}}]//img" parameterized="true" timeout="30"/> <element name="fotoramaImageThumbnailActive" type="block" selector="//div[contains(@class, 'fotorama__nav__shaft')]//div[contains(@class, 'fotorama__nav__frame--thumb') and contains(@class, 'fotorama__active')][{{imageNumber}}]" parameterized="true" timeout="30"/> + <element name="imageNextButton" type="button" selector=".product.media .fotorama-item .fotorama__wrap--toggle-arrows .fotorama__arr--next" timeout="30"/> + <element name="imageFullscreenNextButton" type="button" selector=".fotorama--fullscreen.fotorama-item .fotorama__wrap--toggle-arrows .fotorama__arr--next" timeout="30"/> + <element name="imagePrevButton" type="button" selector=".product.media .fotorama-item .fotorama__wrap--toggle-arrows .fotorama__arr--prev" timeout="30"/> + <element name="imageFullscreenPrevButton" type="button" selector=".fotorama--fullscreen.fotorama-item .fotorama__wrap--toggle-arrows .fotorama__arr--prev" timeout="30"/> + <element name="mainImageForJsActions" type="text" selector="div.fotorama div.fotorama__active img.fotorama__img" timeout="30"/> + <element name="mainImageForJsActionsFullscreen" type="text" selector="div.fotorama div.fotorama__active img.fotorama__img--full" timeout="30"/> + <element name="imageSectionForJsActions" type="text" selector=".fotorama__wrap .fotorama__stage" /> + <element name="imgSelectedInThumbnail" type="block" selector=".fotorama__nav-wrap .fotorama__active .fotorama__loaded img[src*='{{filename}}']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductWithMediaGalleryBehaviorTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductWithMediaGalleryBehaviorTest.xml new file mode 100644 index 0000000000000..0fd5a7117167c --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductWithMediaGalleryBehaviorTest.xml @@ -0,0 +1,463 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontProductWithMediaGalleryBehaviorTest"> + <annotations> + <features value="Catalog"/> + <stories value="Storefront Gallery behaviour for Product with media"/> + <title value="Assert media behaviour for product with different media on storefront"/> + <description value="Assert media behaviour for product with different media on storefront"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-26305"/> + <group value="catalog"/> + <group value="productVideo"/> + <skip> + <issueId value="MC-33903"/> + </skip> + </annotations> + <before> + <createData entity="SimpleProduct2" stepKey="createProduct"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> + </after> + <!--Add images and video to product--> + <actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="openAdminProductEditPage"> + <argument name="productId" value="$createProduct.id$"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addBaseImage"> + <argument name="image" value="TestImageAdobe"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage1"> + <argument name="image" value="AdobeSmallImage"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage2"> + <argument name="image" value="AdobeThumbImage"/> + </actionGroup> + <actionGroup ref="AdminAddProductVideoWithPreviewActionGroup" stepKey="addVideo"> + <argument name="video" value="VimeoProductVideo"/> + <argument name="image" value="{{TestImageNew.file}}"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage4"> + <argument name="image" value="Magento2"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage5"> + <argument name="image" value="JpgImage"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage6"> + <argument name="image" value="LargeImage"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage7"> + <argument name="image" value="Magento2"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage8"> + <argument name="image" value="MagentoImage"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage9"> + <argument name="image" value="Magento3"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage10"> + <argument name="image" value="TestImageNew"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage11"> + <argument name="image" value="ProductImage"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage12"> + <argument name="image" value="MediumImage"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage13"> + <argument name="image" value="MediumImage"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage14"> + <argument name="image" value="PngImage"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage15"> + <argument name="image" value="Magento2"/> + </actionGroup> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImage16"> + <argument name="image" value="Magento3"/> + </actionGroup> + <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProductForm"/> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="goToStorefrontProductPage"> + <argument name="productUrl" value="$createProduct.custom_attributes[url_key]$"/> + </actionGroup> + <!--Assert positioning images in the ribbon Step 2.3--> + <waitForElementVisible selector="{{StorefrontProductMediaSection.fotoramaAnyMedia}}" stepKey="waitForThumbnailsAppear"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition1"> + <argument name="image" value="{{TestImageAdobe.filename}}"/> + <argument name="extension" value="{{TestImageAdobe.file_extension}}"/> + <argument name="position" value="1"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition2"> + <argument name="image" value="{{AdobeSmallImage.filename}}"/> + <argument name="extension" value="{{AdobeSmallImage.file_extension}}"/> + <argument name="position" value="2"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition3"> + <argument name="image" value="{{AdobeThumbImage.filename}}"/> + <argument name="extension" value="{{AdobeThumbImage.file_extension}}"/> + <argument name="position" value="3"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition4"> + <argument name="image" value="{{TestImageNew.filename}}"/> + <argument name="extension" value="{{TestImageNew.file_extension}}"/> + <argument name="position" value="4"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition5"> + <argument name="image" value="{{Magento2.filename}}"/> + <argument name="extension" value="{{Magento2.file_extension}}"/> + <argument name="position" value="5"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition6"> + <argument name="image" value="{{JpgImage.filename}}"/> + <argument name="extension" value="{{JpgImage.file_extension}}"/> + <argument name="position" value="6"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition7"> + <argument name="image" value="{{LargeImage.filename}}"/> + <argument name="extension" value="{{LargeImage.file_extension}}"/> + <argument name="position" value="7"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition8"> + <argument name="image" value="{{Magento2.filename}}"/> + <argument name="extension" value="{{Magento2.file_extension}}"/> + <argument name="position" value="8"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition9"> + <argument name="image" value="{{MagentoImage.filename}}"/> + <argument name="extension" value="{{MagentoImage.file_extension}}"/> + <argument name="position" value="9"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition10"> + <argument name="image" value="{{Magento3.filename}}"/> + <argument name="extension" value="{{Magento3.file_extension}}"/> + <argument name="position" value="10"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition11"> + <argument name="image" value="{{TestImageNew.filename}}"/> + <argument name="extension" value="{{TestImageNew.file_extension}}"/> + <argument name="position" value="11"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition12"> + <argument name="image" value="{{ProductImage.filename}}"/> + <argument name="extension" value="{{ProductImage.file_extension}}"/> + <argument name="position" value="12"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition13"> + <argument name="image" value="{{MediumImage.filename}}"/> + <argument name="extension" value="{{MediumImage.file_extension}}"/> + <argument name="position" value="13"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition14"> + <argument name="image" value="{{MediumImage.filename}}"/> + <argument name="extension" value="{{MediumImage.file_extension}}"/> + <argument name="position" value="14"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition15"> + <argument name="image" value="{{PngImage.filename}}"/> + <argument name="extension" value="{{PngImage.file_extension}}"/> + <argument name="position" value="15"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition16"> + <argument name="image" value="{{Magento2.filename}}"/> + <argument name="extension" value="{{Magento2.file_extension}}"/> + <argument name="position" value="16"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertImagePosition17"> + <argument name="image" value="{{Magento3.filename}}"/> + <argument name="extension" value="{{Magento3.file_extension}}"/> + <argument name="position" value="17"/> + </actionGroup> + <!--Assert fullscreen image isn't displayed. Step 2.1--> + <actionGroup ref="StorefrontAssertActiveProductImageActionGroup" stepKey="seeActiveBaseImage"> + <argument name="fileName" value="{{TestImageAdobe.filename}}"/> + </actionGroup> + <dontSeeElement selector="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}" stepKey="dontSeeFullscreenProductImage"/> + <!--Assert thumbnail drag actions. Steps 3-4--> + <actionGroup ref="AssertStorefrontProductPageGalleryThumbnailDragActionGroup" stepKey="assertThumbnailDragAction"> + <argument name="dragPointImage" value="{{TestImageNew.filename}}"/> + <argument name="currentImage" value="{{TestImageAdobe.filename}}"/> + <argument name="firstImage" value="{{TestImageAdobe.filename}}"/> + </actionGroup> + <!--Verify if looping is unavailable. Step 5--> + <dontSeeElement selector="{{StorefrontProductMediaSection.fotoramaPrevButton}}" stepKey="dontSeePrevButton"/> + <seeElement selector="{{StorefrontProductMediaSection.fotoramaNextButton}}" stepKey="seeNextButton"/> + <click selector="{{StorefrontProductMediaSection.fotoramaNextButton}}" stepKey="firstClickNextFotorama"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageInFotorama(MagentoImage.filename)}}" stepKey="see9thImageInRibbon"/> + <click selector="{{StorefrontProductMediaSection.fotoramaNextButton}}" stepKey="secondClickNextFotorama"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageInFotorama(MagentoImage.filename)}}" stepKey="seeLastImageInRibbon"/> + <seeElement selector="{{StorefrontProductMediaSection.productImage(TestImageAdobe.filename)}}" stepKey="seeActiveImageDontChangeAfterClickNext"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.fotoramaNextButton}}" stepKey="dontSeeNextButtonAfterClickNext"/> + <click selector="{{StorefrontProductMediaSection.fotoramaPrevButton}}" stepKey="firstClickPrevFotorama"/> + <click selector="{{StorefrontProductMediaSection.fotoramaPrevButton}}" stepKey="secondClickPrevFotorama"/> + <seeElement selector="{{StorefrontProductMediaSection.productImage(TestImageAdobe.filename)}}" stepKey="seeActiveImageDefaultStay2"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageInFotorama(TestImageAdobe.filename)}}" stepKey="seeFirstImageInRibbon"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.fotoramaPrevButton}}" stepKey="dontSeePrevButtonAfterClick"/> + <!--Change image by thumbnail ribbon. Step 6--> + <actionGroup ref="AssertStorefrontProductPageGalleryChangingMainImageByRibbonActionGroup" stepKey="assertThumbnailClicking"> + <argument name="startImage" value="{{TestImageAdobe.filename}}"/> + <argument name="expectedImage" value="{{AdobeSmallImage.filename}}"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductImageAppearsOnProductPagePreviewActionGroup" stepKey="seeImageOnPreview"> + <argument name="productImage" value="{{TestImageAdobe.filename}}"/> + </actionGroup> + <!--Change image by image buttons. Step 7--> + <actionGroup ref="AssertStorefrontProductPageGalleryMainImageButtonsActionGroup" stepKey="assertButtonActions"> + <argument name="startImage" value="{{TestImageAdobe.filename}}"/> + <argument name="expectedImage" value="{{AdobeSmallImage.filename}}"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductImageAppearsOnProductPagePreviewActionGroup" stepKey="seeImageAfterButtonActions"> + <argument name="productImage" value="{{TestImageAdobe.filename}}"/> + </actionGroup> + <!--Check that images <= that image section. Step 7.4--> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions0"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert0"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions1"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert1"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions2"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert2"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions3"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert3"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions4"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert4"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions5"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert5"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions6"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert6"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions7"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert7"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions8"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert8"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions9"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert9"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions10"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert10"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions11"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert11"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions12"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert12"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions13"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert13"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions14"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert14"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions15"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert15"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertImageDimensions16"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickOnNextImageButtonDimensionsAssert16"/> + <actionGroup ref="AssertStorefrontProductImageAppearsOnProductPagePreviewActionGroup" stepKey="seeImageAfterLoop"> + <argument name="productImage" value="{{TestImageAdobe.filename}}"/> + </actionGroup> + <!--Change image using the drag actions. Step 8--> + <actionGroup ref="StorefrontProductPageGalleryDragMainImageBackActionGroup" stepKey="dragBack"/> + <actionGroup ref="AssertStorefrontProductImageAppearsOnProductPagePreviewActionGroup" stepKey="seeImageAfterDragBack"> + <argument name="productImage" value="{{Magento3.filename}}"/> + </actionGroup> + <actionGroup ref="StorefrontProductPageGalleryDragMainImageForwardActionGroup" stepKey="dragForward"/> + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOnImageAfterDragActions"/> + <actionGroup ref="AssertStorefrontProductImageAppearsOnProductPagePreviewActionGroup" stepKey="seeImageAfterDragForward"> + <argument name="productImage" value="{{TestImageAdobe.filename}}"/> + </actionGroup> + <!--Assert the image looping by image buttons. Step 9--> + <click selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="loopBack"/> + <actionGroup ref="AssertStorefrontProductImageAppearsOnProductPagePreviewActionGroup" stepKey="seeImageAfterLoopBack"> + <argument name="productImage" value="{{Magento3.filename}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="loopForward"/> + <actionGroup ref="AssertStorefrontProductImageAppearsOnProductPagePreviewActionGroup" stepKey="seeImageAfterLoopForward"> + <argument name="productImage" value="{{TestImageAdobe.filename}}"/> + </actionGroup> + <!--Open the fullscreen image. Steps 10-11--> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="setNonDefaultImage"/> + <click selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="openFullscreenImage"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(AdobeSmallImage.filename)}}" stepKey="assertFullscreenImage"/> + <waitForElementVisible selector="{{StorefrontProductMediaSection.fotoramaAnyMedia}}" stepKey="waitForThumbnailsFullscreen"/> + <!--Assert positioning images in the ribbon Step 11.3--> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition1"> + <argument name="image" value="{{TestImageAdobe.filename}}"/> + <argument name="extension" value="{{TestImageAdobe.file_extension}}"/> + <argument name="position" value="1"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition2"> + <argument name="image" value="{{AdobeSmallImage.filename}}"/> + <argument name="extension" value="{{AdobeSmallImage.file_extension}}"/> + <argument name="position" value="2"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition3"> + <argument name="image" value="{{AdobeThumbImage.filename}}"/> + <argument name="extension" value="{{AdobeThumbImage.file_extension}}"/> + <argument name="position" value="3"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition4"> + <argument name="image" value="{{TestImageNew.filename}}"/> + <argument name="extension" value="{{TestImageNew.file_extension}}"/> + <argument name="position" value="4"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition5"> + <argument name="image" value="{{Magento2.filename}}"/> + <argument name="extension" value="{{Magento2.file_extension}}"/> + <argument name="position" value="5"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition6"> + <argument name="image" value="{{JpgImage.filename}}"/> + <argument name="extension" value="{{JpgImage.file_extension}}"/> + <argument name="position" value="6"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition7"> + <argument name="image" value="{{LargeImage.filename}}"/> + <argument name="extension" value="{{LargeImage.file_extension}}"/> + <argument name="position" value="7"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition8"> + <argument name="image" value="{{Magento2.filename}}"/> + <argument name="extension" value="{{Magento2.file_extension}}"/> + <argument name="position" value="8"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition9"> + <argument name="image" value="{{MagentoImage.filename}}"/> + <argument name="extension" value="{{MagentoImage.file_extension}}"/> + <argument name="position" value="9"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition10"> + <argument name="image" value="{{Magento3.filename}}"/> + <argument name="extension" value="{{Magento3.file_extension}}"/> + <argument name="position" value="10"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition11"> + <argument name="image" value="{{TestImageNew.filename}}"/> + <argument name="extension" value="{{TestImageNew.file_extension}}"/> + <argument name="position" value="11"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition12"> + <argument name="image" value="{{ProductImage.filename}}"/> + <argument name="extension" value="{{ProductImage.file_extension}}"/> + <argument name="position" value="12"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition13"> + <argument name="image" value="{{MediumImage.filename}}"/> + <argument name="extension" value="{{MediumImage.file_extension}}"/> + <argument name="position" value="13"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition14"> + <argument name="image" value="{{MediumImage.filename}}"/> + <argument name="extension" value="{{MediumImage.file_extension}}"/> + <argument name="position" value="14"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition15"> + <argument name="image" value="{{PngImage.filename}}"/> + <argument name="extension" value="{{PngImage.file_extension}}"/> + <argument name="position" value="15"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition16"> + <argument name="image" value="{{Magento2.filename}}"/> + <argument name="extension" value="{{Magento2.file_extension}}"/> + <argument name="position" value="16"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductPageGalleryImagePositionInThumbnailRibbonActionGroup" stepKey="assertFullscreenThumbnailImagePosition17"> + <argument name="image" value="{{Magento3.filename}}"/> + <argument name="extension" value="{{Magento3.file_extension}}"/> + <argument name="position" value="17"/> + </actionGroup> + <!--Assert the fullscreen thumbnail ribbon drag actions step 12--> + <actionGroup ref="AssertStorefrontProductPageGalleryFullscreenThumbnailDragActionGroup" stepKey="assertFullscreenThumbnailDragAction"> + <argument name="dragPointImage" value="{{TestImageNew.filename}}"/> + <argument name="currentImage" value="{{AdobeSmallImage.filename}}"/> + <argument name="firstImage" value="{{TestImageAdobe.filename}}"/> + </actionGroup> + <!--Change fullscreen image by clicking on thumbnail ribbon. Step 15--> + <actionGroup ref="AssertStorefrontProductPageGalleryChangingFullscreenImageByRibbonActionGroup" stepKey="assertThumbnailClickFullscreen"> + <argument name="startImage" value="{{AdobeSmallImage.filename}}"/> + <argument name="expectedImage" value="{{LargeImage.filename}}"/> + </actionGroup> + <!--Change fullscreen image using the image buttons. Steps 16 and 18--> + <click selector="{{StorefrontProductMediaSection.imageFullscreenPrevButton}}" stepKey="goToFirstImage"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(TestImageAdobe.filename)}}" stepKey="seeFirstFullscreenImage"/> + <click selector="{{StorefrontProductMediaSection.imageFullscreenPrevButton}}" stepKey="loopToLastImage"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(Magento3.filename)}}" stepKey="assertLastImageAfterLoop"/> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="loopToFirstImage"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(TestImageAdobe.filename)}}" stepKey="assertFirstImageAfterLoop"/> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert0"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions0"> + <argument name="source" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <!-- Check that images <= that image section. Step 16.5--> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert1"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions1"> + <argument name="source" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert2"/> + <click selector="{{StorefrontProductMediaSection.fotoramaNextButtonVideo}}" stepKey="skipVideo"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions3"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert4"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions4"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert5"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions5"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert6"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions6"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert7"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions7"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert8"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions8"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert9"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions9"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert10"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions10"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert11"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions11"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert12"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions12"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert13"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions13"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert14"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions14"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert15"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions15"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <click selector="{{StorefrontProductMediaSection.imageFullscreenNextButton}}" stepKey="clickOnNextImageButtonFullscreenDimensionsAssert16"/> + <actionGroup ref="AssertStorefrontProductPageGalleryImageDimensionsActionGroup" stepKey="assertFullscreenImageDimensions16"> + <argument name="imageSource" value="{{StorefrontProductMediaSection.mainImageForJsActionsFullscreen}}"/> + </actionGroup> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(TestImageAdobe.filename)}}" stepKey="assertFirstImageAfterSecondLoop"/> + <!-- TODO: Change fullscreen image by drag/swipe action: after MQE-2333 implementation --> + <!--Steps 19-20--> + <click selector="{{StorefrontProductMediaSection.imageFullscreenPrevButton}}" stepKey="selectLastImage"/> + <seeElement selector="{{StorefrontProductMediaSection.productImageFullscreen(Magento3.filename)}}" stepKey="assertLastImageFullscreen"/> + <click selector="{{StorefrontProductMediaSection.closeFullscreenImage}}" stepKey="closeFullScreenImage"/> + <actionGroup ref="AssertStorefrontProductImageAppearsOnProductPagePreviewActionGroup" stepKey="seeLastImageAfterFullscreen"> + <argument name="productImage" value="{{Magento3.filename}}"/> + </actionGroup> + </test> +</tests> From 1e6a9c62cb46b6bd1a3536f8429c8d6cd297e098 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Mon, 30 Nov 2020 14:39:17 +0200 Subject: [PATCH 28/32] MC-39474: [MFTF] Flaky StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest because of bad design --- ...gRecalculationAfterCouponCodeAddedTest.xml | 7 +- ...ecalculationAfterCouponCodeAppliedTest.xml | 104 ++++++++++++++++++ ...tForShowShippingMethodNoApplicableTest.xml | 2 +- .../AdminCreateCartPriceRuleActionGroup.xml | 4 +- ...StorefrontApplyDiscountCodeActionGroup.xml | 2 +- 5 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAppliedTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml index 20b94d0f4ec8a..bd8bcdbc5cd2d 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml @@ -7,9 +7,9 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest"> + <test name="StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest" deprecated="Use StoreFrontFreeShippingRecalculationAfterCouponCodeAppliedTest instead"> <annotations> - <title value="Checkout Free Shipping Recalculation after Coupon Code Added"/> + <title value="DEPRECATED. Checkout Free Shipping Recalculation after Coupon Code Added"/> <stories value="Checkout Free Shipping Recalculation after Coupon Code Added"/> <description value="User should be able to do checkout free shipping recalculation after adding coupon code"/> <features value="Checkout"/> @@ -17,6 +17,9 @@ <testCaseId value="MAGETWO-96537"/> <useCaseId value="MAGETWO-96431"/> <group value="Checkout"/> + <skip> + <issueId value="DEPRECATED">Use StoreFrontFreeShippingRecalculationAfterCouponCodeAppliedTest instead</issueId> + </skip> </annotations> <before> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAppliedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAppliedTest.xml new file mode 100644 index 0000000000000..bc9dddf53ad03 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAppliedTest.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StoreFrontFreeShippingRecalculationAfterCouponCodeAppliedTest"> + <annotations> + <features value="Checkout"/> + <stories value="Checkout Free Shipping Recalculation after Coupon Code Added"/> + <title value="Checkout Free Shipping Recalculation after Coupon Code Added"/> + <description value="User should be able to do checkout free shipping recalculation after adding coupon code"/> + <severity value="BLOCKER"/> + <testCaseId value="MC-28548"/> + <useCaseId value="MAGETWO-96431"/> + <group value="Checkout"/> + </annotations> + + <before> + <createData entity="Simple_US_Customer" stepKey="createCustomer"> + <field key="group_id">1</field> + </createData> + <createData entity="_defaultCategory" stepKey="defaultCategory"/> + <createData entity="_defaultProduct" stepKey="simpleProduct"> + <field key="price">90</field> + <requiredEntity createDataKey="defaultCategory"/> + </createData> + <!--It is default for FlatRate--> + <createData entity="FlatRateShippingMethodConfig" stepKey="enableFlatRate"/> + <createData entity="FreeShippingMethodsSettingConfig" stepKey="freeShippingMethodsSettingConfig"/> + <createData entity="MinimumOrderAmount90" stepKey="minimumOrderAmount90"/> + <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> + <argument name="tags" value=""/> + </actionGroup> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCartPriceRuleDeleteAllActionGroup" stepKey="deleteAllCartPriceRules"/> + <actionGroup ref="AdminCreateCartPriceRuleWithCouponCodeActionGroup" stepKey="createCartPriceRule"> + <argument name="ruleName" value="CatPriceRule"/> + <argument name="couponCode" value="CatPriceRule.coupon_code"/> + </actionGroup> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStoreFront"> + <argument name="Customer" value="$createCustomer$"/> + </actionGroup> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductPage"> + <argument name="productUrl" value="$simpleProduct.custom_attributes[url_key]$"/> + </actionGroup> + </before> + + <after> + <deleteData createDataKey="simpleProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="defaultCategory" stepKey="deleteCategory"/> + <createData entity="DefaultShippingMethodsConfig" stepKey="defaultShippingMethodsConfig"/> + <createData entity="DefaultMinimumOrderAmount" stepKey="defaultMinimumOrderAmount"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + + <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> + <argument name="tags" value=""/> + </actionGroup> + <actionGroup ref="AdminCartPriceRuleDeleteAllActionGroup" stepKey="deleteAllCartPriceRules"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartRule"> + <argument name="product" value="$simpleProduct$"/> + <argument name="couponCode" value="{{CatPriceRule.coupon_code}}"/> + </actionGroup> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart1"/> + <waitForPageLoad stepKey="waitForpageLoad1"/> + <dontSee selector="{{CheckoutShippingMethodsSection.shippingMethodRowByName('Free')}}" stepKey="dontSeeFreeShipping"/> + <actionGroup ref="StorefrontCartPageOpenActionGroup" stepKey="goToShoppingCartPage"/> + <conditionalClick selector="{{DiscountSection.DiscountTab}}" dependentSelector="{{DiscountSection.CouponInput}}" visible="false" stepKey="openDiscountTabIfClosed"/> + <waitForPageLoad stepKey="waitForCouponTabOpen1"/> + <click selector="{{DiscountSection.CancelCoupon}}" stepKey="cancelCoupon"/> + <waitForPageLoad stepKey="waitForCancel"/> + <see userInput='You canceled the coupon code.' stepKey="seeCancellationMessage"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart2"/> + <waitForPageLoad stepKey="waitForShippingMethods"/> + <click selector="{{CheckoutShippingMethodsSection.shippingMethodRowByName('Free')}}" stepKey="chooseFreeShipping"/> + <actionGroup ref="StorefrontCheckoutClickNextOnShippingStepActionGroup" stepKey="clickNextAfterFreeShippingMethodSelection"/> + <waitForPageLoad stepKey="waitForReviewAndPayments"/> + <actionGroup ref="StorefrontApplyDiscountCodeActionGroup" stepKey="applyCouponCode"> + <argument name="discountCode" value="{{CatPriceRule.coupon_code}}"/> + </actionGroup> + <!-- Assert order cannot be placed and error message will shown. --> + <actionGroup ref="AssertStorefrontOrderIsNotPlacedActionGroup" stepKey="seeShippingMethodError"> + <argument name="error" value="The shipping method is missing. Select the shipping method and try again."/> + </actionGroup> + <amOnPage stepKey="navigateToShippingPage" url="{{CheckoutShippingPage.url}}"/> + <waitForPageLoad stepKey="waitForShippingPageLoad"/> + + <click stepKey="chooseFlatRateShipping" selector="{{CheckoutShippingMethodsSection.shippingMethodRowByName('Flat Rate')}}"/> + <actionGroup ref="CheckoutSelectFlatRateShippingMethodActionGroup" stepKey="selectFlatRateShippingMethod"/> + <actionGroup ref="StorefrontCheckoutClickNextOnShippingStepActionGroup" stepKey="clickNextAfterFlatRateShippingMethodSelection"/> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectPaymentMethod"/> + <!-- Place Order --> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="placeOrder"> + <argument name="orderNumberMessage" value="CONST.successCheckoutOrderNumberMessage"/> + <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutForShowShippingMethodNoApplicableTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutForShowShippingMethodNoApplicableTest.xml index 22bc1260e5f33..3c06ca17cfedc 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutForShowShippingMethodNoApplicableTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutForShowShippingMethodNoApplicableTest.xml @@ -58,6 +58,6 @@ <click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="clickNextButton"/> <!-- Assert order cannot be placed and error message will shown. --> <waitForPageLoad stepKey="waitForError"/> - <see stepKey="seeShippingMethodError" userInput="The shipping method is missing. Select the shipping method and try again."/> + <seeElementInDOM selector="{{CheckoutHeaderSection.errorMessageContainsText('The shipping method is missing. Select the shipping method and try again')}}" stepKey="seeShippingMethodError"/> </test> </tests> diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml index 57a2c17419532..f6a705ee368e9 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleActionGroup.xml @@ -19,6 +19,7 @@ <amOnPage url="{{AdminCartPriceRulesPage.url}}" stepKey="amOnCartPriceList"/> <waitForPageLoad stepKey="waitForPriceList"/> <click selector="{{AdminCartPriceRulesSection.addNewRuleButton}}" stepKey="clickAddNewRule"/> + <waitForElementVisible selector="{{AdminCartPriceRulesFormSection.ruleName}}" stepKey="waitRuleNameFieldAppeared"/> <fillField selector="{{AdminCartPriceRulesFormSection.ruleName}}" userInput="{{ruleName.name}}" stepKey="fillRuleName"/> <selectOption selector="{{AdminCartPriceRulesFormSection.websites}}" userInput="{{ruleName.websites}}" stepKey="selectWebsites"/> <selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" parameterArray="[{{ruleName.customerGroups}}]" stepKey="selectCustomerGroup"/> @@ -26,6 +27,7 @@ <selectOption selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="{{ruleName.apply}}" stepKey="selectActionType"/> <fillField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="{{ruleName.discountAmount}}" stepKey="fillDiscountAmount"/> <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> - <see selector="{{AdminCartPriceRulesFormSection.successMessage}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> + <waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitForSuccessMessage"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontApplyDiscountCodeActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontApplyDiscountCodeActionGroup.xml index c8363a3df6221..5607512c862b3 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontApplyDiscountCodeActionGroup.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontApplyDiscountCodeActionGroup.xml @@ -12,7 +12,7 @@ <arguments> <argument name="discountCode" type="string"/> </arguments> - <click selector="{{DiscountSection.DiscountTab}}" stepKey="clickToAddDiscount"/> + <conditionalClick selector="{{DiscountSection.DiscountTab}}" dependentSelector="{{DiscountSection.CouponInput}}" visible="false" stepKey="clickToAddDiscount"/> <fillField selector="{{DiscountSection.DiscountInput}}" userInput="{{discountCode}}" stepKey="fillFieldDiscountCode"/> <click selector="{{DiscountSection.ApplyCodeBtn}}" stepKey="clickToApplyDiscount"/> <waitForElementVisible selector="{{DiscountSection.DiscountVerificationMsg}}" time="30" stepKey="waitForDiscountToBeAdded"/> From c79feeb2166867c7ad551c7a9062067e4f7759a3 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Mon, 30 Nov 2020 17:18:49 +0200 Subject: [PATCH 29/32] MC-39482: [MFTF] Flaky EndToEndB2CLoggedInUserTestCest because of bad design --- .../Catalog/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml | 2 ++ .../Customer/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml | 3 ++- .../SalesRule/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml index fbb6893e92b1e..179ac35b9d206 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml @@ -10,6 +10,8 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="EndToEndB2CLoggedInUserTest"> <before> + <actionGroup ref="DeleteAllProductsUsingProductGridActionGroup" after="loginAsAdmin" stepKey="deleteAllProducts"/> + <createData entity="ApiCategory" stepKey="createCategory"/> <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct1"> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml index 8dcf494b3572b..824c898068342 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml @@ -21,10 +21,11 @@ </annotations> <before> <resetCookie userInput="PHPSESSID" stepKey="resetCookieForCart"/> + <actionGroup ref="AdminLoginActionGroup" after="resetCookieForCart" stepKey="loginAsAdmin"/> </before> <after> <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="logoutCustomer"/> - <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <comment userInput="No need this since it done in before section" stepKey="loginAsAdmin"/> <actionGroup ref="DeleteCustomerFromAdminActionGroup" stepKey="deleteCustomerFromAdmin"/> <actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearProductsGridFilters"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="adminLogout"/> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml index 7a995b1feeeda..d76e9edb828bd 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="EndToEndB2CLoggedInUserTest"> <before> + <actionGroup ref="AdminCartPriceRuleDeleteAllActionGroup" after="loginAsAdmin" stepKey="deleteCartPriceRule"/> <createData entity="ApiSalesRule" stepKey="createSalesRule"/> <createData entity="ApiSalesRuleCoupon" stepKey="createSalesRuleCoupon"> <requiredEntity createDataKey="createSalesRule"/> From a44a1b3f46c09d92a6b8e78481894e2b3cc92837 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 1 Dec 2020 11:05:08 +0200 Subject: [PATCH 30/32] MC-39501: [MFTF] Flaky AdminAddImageToWYSIWYGProductTest because of bad design --- .../Test/Mftf/Data/WYSIWYGConfigData.xml | 2 +- .../Test/AdminAddImageToWYSIWYGCatalogTest.xml | 2 +- .../Test/AdminAddImageToWYSIWYGProductTest.xml | 13 ++++++++----- ...AdminEditTextEditorProductAttributeTest.xml | 2 +- ...erifyDefaultWYSIWYGToolbarOnProductTest.xml | 2 +- ...ltcontrolsonproductshortdescriptionTest.xml | 2 +- ...fyTinyMCEv4IsNativeWYSIWYGOnCatalogTest.xml | 2 +- ...fyTinyMCEv4IsNativeWYSIWYGOnProductTest.xml | 2 +- .../CliEnableTinyMCE4ActionGroup.xml | 18 ++++++++++++++++++ .../Test/AdminAddImageToWYSIWYGBlockTest.xml | 2 +- .../Test/AdminAddImageToWYSIWYGCMSTest.xml | 4 ++-- .../AdminAddVariableToWYSIWYGBlockTest.xml | 2 +- .../Test/AdminAddVariableToWYSIWYGCMSTest.xml | 2 +- .../Test/AdminAddWidgetToWYSIWYGBlockTest.xml | 2 +- ...dWidgetToWYSIWYGWithCMSPageLinkTypeTest.xml | 2 +- ...dgetToWYSIWYGWithCMSStaticBlockTypeTest.xml | 2 +- ...oWYSIWYGWithCatalogCategoryLinkTypeTest.xml | 2 +- ...ToWYSIWYGWithCatalogProductLinkTypeTest.xml | 2 +- ...ToWYSIWYGWithCatalogProductListTypeTest.xml | 2 +- ...WYGWithRecentlyComparedProductsTypeTest.xml | 2 +- ...SIWYGWithRecentlyViewedProductsTypeTest.xml | 2 +- ...scapeAndEnterHandlesForWYSIWYGBlockTest.xml | 2 +- .../CheckOrderOfProdsInWidgetOnCMSPageTest.xml | 2 +- ...rifyTinyMCEv4IsNativeWYSIWYGOnBlockTest.xml | 2 +- ...fyTinyMCEv4IsNativeWYSIWYGOnCMSPageTest.xml | 2 +- .../Mftf/ActionGroup/SwitcherActionGroup.xml | 4 ++-- .../AdminAddImageToWYSIWYGNewsletterTest.xml | 2 +- ...AdminAddVariableToWYSIWYGNewsletterTest.xml | 2 +- .../AdminAddWidgetToWYSIWYGNewsletterTest.xml | 2 +- ...inyMCEv4IsNativeWYSIWYGOnNewsletterTest.xml | 2 +- .../Test/AdminSwitchWYSIWYGOptionsTest.xml | 2 +- 31 files changed, 57 insertions(+), 36 deletions(-) create mode 100644 app/code/Magento/Cms/Test/Mftf/ActionGroup/CliEnableTinyMCE4ActionGroup.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/WYSIWYGConfigData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/WYSIWYGConfigData.xml index 7bb8cf5f4db37..3965cfa1f958b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/WYSIWYGConfigData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/WYSIWYGConfigData.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> - +<!--TODO: This datasets should be moved to CMS module--> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="EnableWYSIWYG"> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGCatalogTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGCatalogTest.xml index bcdf6ad39124a..029c304873ce2 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGCatalogTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGCatalogTest.xml @@ -11,7 +11,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <annotations> <features value="Catalog"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml index acc22f2e611d6..5ea7253619ed9 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml @@ -10,18 +10,20 @@ <test name="AdminAddImageToWYSIWYGProductTest"> <annotations> <features value="Catalog"/> - <stories value="MAGETWO-42041-Default WYSIWYG toolbar configuration with Magento Media Gallery"/> - <group value="Catalog"/> + <stories value="Default WYSIWYG toolbar configuration with Magento Media Gallery"/> <title value="Admin should be able to add image to WYSIWYG Editor on Product Page"/> <description value="Admin should be able to add image to WYSIWYG Editor on Product Page"/> <severity value="CRITICAL"/> - <testCaseId value="MAGETWO-84375"/> + <testCaseId value="MC-25763"/> + <group value="catalog"/> </annotations> + <before> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> + <after> <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> @@ -32,8 +34,9 @@ <actionGroup ref="FillMainProductFormActionGroup" stepKey="fillBasicProductInfo" /> <click selector="{{AdminProductFormSection.contentTab}}" stepKey="clickContentTab" /> - <scrollTo selector="{{ProductDescriptionWYSIWYGToolbarSection.showHideBtn}}" y="-150" x="0" stepKey="scrollToDescription" /> + <scrollTo selector="{{ProductDescriptionWYSIWYGToolbarSection.showHideBtn}}" y="-150" x="0" stepKey="scrollToDescription"/> <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.TinyMCE4}}" stepKey="waitForDescription" /> + <scrollTo selector="{{ProductDescriptionWYSIWYGToolbarSection.showHideBtn}}" y="-150" x="0" stepKey="scrollToDescriptionAgain"/> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.InsertImageIcon}}" stepKey="clickInsertImageIcon1" /> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.Browse}}" stepKey="clickBrowse1" /> <waitForLoadingMaskToDisappear stepKey="waitForBrowseModal" /> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminEditTextEditorProductAttributeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminEditTextEditorProductAttributeTest.xml index b437d5fb0c868..283ed72e62faa 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminEditTextEditorProductAttributeTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminEditTextEditorProductAttributeTest.xml @@ -20,7 +20,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> <createData stepKey="myProductAttributeCreation" entity="productAttributeWysiwyg"/> <createData stepKey="myProductAttributeSetAssign" entity="AddToDefaultSet"> <requiredEntity createDataKey="myProductAttributeCreation"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/VerifyDefaultWYSIWYGToolbarOnProductTest/VerifyDefaultWYSIWYGToolbarOnProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/VerifyDefaultWYSIWYGToolbarOnProductTest/VerifyDefaultWYSIWYGToolbarOnProductTest.xml index 456abecc63ccb..662a251be3b20 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/VerifyDefaultWYSIWYGToolbarOnProductTest/VerifyDefaultWYSIWYGToolbarOnProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/VerifyDefaultWYSIWYGToolbarOnProductTest/VerifyDefaultWYSIWYGToolbarOnProductTest.xml @@ -20,7 +20,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4"/> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4"/> </before> <amOnPage url="{{AdminProductCreatePage.url(AddToDefaultSet.attributeSetId, 'simple')}}" stepKey="navigateToProduct"/> <waitForPageLoad stepKey="wait"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/VerifyDefaultWYSIWYGToolbarOnProductTest/VerifydefaultcontrolsonproductshortdescriptionTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/VerifyDefaultWYSIWYGToolbarOnProductTest/VerifydefaultcontrolsonproductshortdescriptionTest.xml index e929cbd752f81..d4bc095dbe9b1 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/VerifyDefaultWYSIWYGToolbarOnProductTest/VerifydefaultcontrolsonproductshortdescriptionTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/VerifyDefaultWYSIWYGToolbarOnProductTest/VerifydefaultcontrolsonproductshortdescriptionTest.xml @@ -20,7 +20,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4"/> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4"/> </before> <amOnPage url="{{AdminProductCreatePage.url(AddToDefaultSet.attributeSetId, 'simple')}}" stepKey="navigateToProduct"/> <waitForPageLoad stepKey="wait"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCatalogTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCatalogTest.xml index d7e4f97ed0bc2..ee6ff0c224545 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCatalogTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCatalogTest.xml @@ -21,7 +21,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <actionGroup ref="AdminOpenCategoryPageActionGroup" stepKey="navigateToNewCatalog"/> <waitForLoadingMaskToDisappear stepKey="wait2" /> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnProductTest.xml index cffc4af6fcbbd..f75053f495c4d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnProductTest.xml @@ -20,7 +20,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <amOnPage url="{{AdminProductCreatePage.url(AddToDefaultSet.attributeSetId, 'simple')}}" stepKey="navigateToNewProduct"/> <waitForPageLoad stepKey="wait1"/> diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/CliEnableTinyMCE4ActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/CliEnableTinyMCE4ActionGroup.xml new file mode 100644 index 0000000000000..9e49762f3de20 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/CliEnableTinyMCE4ActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="CliEnableTinyMCE4ActionGroup"> + <annotations> + <description>Enable Tiny MCE 4 by CLI command config:set</description> + </annotations> + + <magentoCLI command="config:set {{EnableTinyMCE4.path}} {{EnableTinyMCE4.value}}" stepKey="enableTinyMCE4"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGBlockTest.xml index c0424e09f8f76..e2111aac348cb 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGBlockTest.xml @@ -22,7 +22,7 @@ <createData entity="_defaultBlock" stepKey="createPreReqBlock" /> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <actionGroup ref="AssignBlockToCMSPage" stepKey="assignBlockToCMSPage"> <argument name="Block" value="$$createPreReqBlock$$"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGCMSTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGCMSTest.xml index 4f67b81446ae7..39f44a3270944 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGCMSTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGCMSTest.xml @@ -21,7 +21,7 @@ <createData entity="_defaultCmsPage" stepKey="createCMSPage" /> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <after> <actionGroup ref="NavigateToMediaGalleryActionGroup" stepKey="navigateToMediaGallery"/> @@ -33,7 +33,7 @@ <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> - + <actionGroup ref="NavigateToCreatedCMSPageActionGroup" stepKey="navigateToCreatedCMSPage"> <argument name="CMSPage" value="$$createCMSPage$$"/> </actionGroup> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddVariableToWYSIWYGBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddVariableToWYSIWYGBlockTest.xml index 32bd75d373115..963844710dd7f 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddVariableToWYSIWYGBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddVariableToWYSIWYGBlockTest.xml @@ -22,7 +22,7 @@ <createData entity="_defaultBlock" stepKey="createPreReqBlock" /> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <!--Create Custom Variable--> <actionGroup ref="CreateCustomVariableActionGroup" stepKey="createCustomVariable" /> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddVariableToWYSIWYGCMSTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddVariableToWYSIWYGCMSTest.xml index 698f29a28598f..7f3d2537a9b0d 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddVariableToWYSIWYGCMSTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddVariableToWYSIWYGCMSTest.xml @@ -19,7 +19,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <!--Create Custom Variable--> <actionGroup ref="CreateCustomVariableActionGroup" stepKey="createCustomVariable" /> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGBlockTest.xml index 887fe88533f74..9e28e81c2696d 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGBlockTest.xml @@ -22,7 +22,7 @@ <createData entity="_defaultBlock" stepKey="createPreReqBlock" /> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <actionGroup ref="NavigateToCreatedCMSBlockPageActionGroup" stepKey="navigateToCreatedCMSBlockPage"> <argument name="CMSBlockPage" value="$$createPreReqBlock$$"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeTest.xml index 509e1abe81ef6..a599d22eab298 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeTest.xml @@ -21,7 +21,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <!--Main test--> <actionGroup ref="AdminOpenCreateNewCMSPageActionGroup" stepKey="navigateToPage"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCMSStaticBlockTypeTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCMSStaticBlockTypeTest.xml index cfb323683dc2c..1c9d7b38a40a4 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCMSStaticBlockTypeTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCMSStaticBlockTypeTest.xml @@ -22,7 +22,7 @@ <createData entity="_defaultBlock" stepKey="createPreReqBlock" /> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <!--Main test--> <actionGroup ref="AdminOpenCreateNewCMSPageActionGroup" stepKey="navigateToPage"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogCategoryLinkTypeTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogCategoryLinkTypeTest.xml index d9ea67491e30a..4f78f6bcce5e0 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogCategoryLinkTypeTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogCategoryLinkTypeTest.xml @@ -21,7 +21,7 @@ <createData entity="_defaultCategory" stepKey="createPreReqCategory"/> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> <actionGroup ref="ConfigAdminAccountSharingActionGroup" stepKey="allowAdminShareAccount"/> </before> <!--Main test--> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductLinkTypeTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductLinkTypeTest.xml index 86f90e0e2a580..4ee5b0d263d40 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductLinkTypeTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductLinkTypeTest.xml @@ -25,7 +25,7 @@ </createData> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <!--Main test--> <actionGroup ref="AdminOpenCreateNewCMSPageActionGroup" stepKey="navigateToPage"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeTest.xml index dcb4c3dc11f3c..6c36913cbb593 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeTest.xml @@ -27,7 +27,7 @@ </createData> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <!--Main test--> <actionGroup ref="AdminOpenCreateNewCMSPageActionGroup" stepKey="navigateToPage"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeTest.xml index 6acf8ef18a332..440f63403c519 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeTest.xml @@ -26,7 +26,7 @@ </createData> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <actionGroup ref="AdminOpenCreateNewCMSPageActionGroup" stepKey="navigateToPage"/> <fillField selector="{{CmsNewPagePageBasicFieldsSection.pageTitle}}" userInput="{{_defaultCmsPage.title}}" stepKey="fillFieldTitle"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithRecentlyViewedProductsTypeTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithRecentlyViewedProductsTypeTest.xml index 1ec4f7054e8c2..226292e6cdea4 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithRecentlyViewedProductsTypeTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddWidgetToWYSIWYGWithRecentlyViewedProductsTypeTest.xml @@ -25,7 +25,7 @@ </createData> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <!--Main test--> <actionGroup ref="AdminOpenCreateNewCMSPageActionGroup" stepKey="navigateToPage"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminCheckCreateFolderEscapeAndEnterHandlesForWYSIWYGBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminCheckCreateFolderEscapeAndEnterHandlesForWYSIWYGBlockTest.xml index c1d5f39d2a005..c5ab9d13b848a 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminCheckCreateFolderEscapeAndEnterHandlesForWYSIWYGBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminCheckCreateFolderEscapeAndEnterHandlesForWYSIWYGBlockTest.xml @@ -23,7 +23,7 @@ <createData entity="_defaultBlock" stepKey="createPreReqBlock" /> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <after> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/CheckOrderOfProdsInWidgetOnCMSPageTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/CheckOrderOfProdsInWidgetOnCMSPageTest.xml index 484dc16faa3b9..c0e6a9cbd793d 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/CheckOrderOfProdsInWidgetOnCMSPageTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/CheckOrderOfProdsInWidgetOnCMSPageTest.xml @@ -22,7 +22,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="enableTinyMCE4"/> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="enableTinyMCE4"/> <waitForPageLoad stepKey="waitConfigToSave"/> <createData entity="ApiCategory" stepKey="createFirstCategory"/> <createData entity="ApiSimpleProduct" stepKey="product1"> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockTest.xml index 58f3b9d5bd3b1..03e3097dbd720 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockTest.xml @@ -22,7 +22,7 @@ <createData entity="_defaultCmsPage" stepKey="createPreReqCMSPage" /> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <amOnPage url="{{CmsNewBlock.url}}" stepKey="amOnNewBlockPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCMSPageTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCMSPageTest.xml index 43615ac906b00..82e725de46249 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCMSPageTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCMSPageTest.xml @@ -21,7 +21,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnPagePagesGrid"/> <waitForPageLoad stepKey="waitForPageLoad1"/> diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/SwitcherActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/SwitcherActionGroup.xml index f4f97b14682f3..c6b2605c73d8c 100644 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/SwitcherActionGroup.xml +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/SwitcherActionGroup.xml @@ -10,9 +10,9 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="SwitchToVersion4ActionGroup"> <annotations> - <description>Goes to the 'Configuration' page for 'Content Management'. Sets the 'WYSIWYG Editor' to 'TinyMCE 4'. Clicks on the Save button. PLEASE NOTE: The value is Hardcoded.</description> + <description>DEPRECATED. Use CliEnableTinyMCE4 instead. Goes to the 'Configuration' page for 'Content Management'. Sets the 'WYSIWYG Editor' to 'TinyMCE 4'. Clicks on the Save button. PLEASE NOTE: The value is Hardcoded.</description> </annotations> - + <amOnPage url="{{ConfigurationStoresPage.url}}" stepKey="navigateToWYSIWYGConfigPage1"/> <waitForPageLoad stepKey="waitForConfigPageToLoad"/> <conditionalClick stepKey="expandWYSIWYGOptions" selector="{{ContentManagementSection.WYSIWYGOptions}}" dependentSelector="{{ContentManagementSection.CheckIfTabExpand}}" visible="true"/> diff --git a/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddImageToWYSIWYGNewsletterTest.xml b/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddImageToWYSIWYGNewsletterTest.xml index e255f14a83661..a6cb2456c583f 100644 --- a/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddImageToWYSIWYGNewsletterTest.xml +++ b/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddImageToWYSIWYGNewsletterTest.xml @@ -20,7 +20,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <!--Create a newsletter template that contains an image--> <amOnPage url="{{NewsletterTemplateForm.url}}" stepKey="amOnNewsletterTemplatePage"/> diff --git a/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddVariableToWYSIWYGNewsletterTest.xml b/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddVariableToWYSIWYGNewsletterTest.xml index ff2e2a84a612e..d4bb8d358e21d 100644 --- a/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddVariableToWYSIWYGNewsletterTest.xml +++ b/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddVariableToWYSIWYGNewsletterTest.xml @@ -20,7 +20,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <!--Create Custom Variable--> <actionGroup ref="CreateCustomVariableActionGroup" stepKey="createCustomVariable" /> diff --git a/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddWidgetToWYSIWYGNewsletterTest.xml b/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddWidgetToWYSIWYGNewsletterTest.xml index 73880f283677d..0fa16d275d6f4 100644 --- a/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddWidgetToWYSIWYGNewsletterTest.xml +++ b/app/code/Magento/Newsletter/Test/Mftf/Test/AdminAddWidgetToWYSIWYGNewsletterTest.xml @@ -20,7 +20,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <amOnPage url="{{NewsletterTemplateForm.url}}" stepKey="amOnNewsletterTemplatePage"/> <waitForElementVisible selector="{{BasicFieldNewsletterSection.templateName}}" stepKey="waitForTemplateName"/> diff --git a/app/code/Magento/Newsletter/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnNewsletterTest.xml b/app/code/Magento/Newsletter/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnNewsletterTest.xml index 3a247402c111d..7cfd4c67369c8 100644 --- a/app/code/Magento/Newsletter/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnNewsletterTest.xml +++ b/app/code/Magento/Newsletter/Test/Mftf/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnNewsletterTest.xml @@ -20,7 +20,7 @@ <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYGActionGroup" stepKey="enableWYSIWYG"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> </before> <amOnPage url="{{NewsletterTemplateForm.url}}" stepKey="amOnNewsletterTemplatePage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> diff --git a/app/code/Magento/Tinymce3/Test/Mftf/Test/AdminSwitchWYSIWYGOptionsTest.xml b/app/code/Magento/Tinymce3/Test/Mftf/Test/AdminSwitchWYSIWYGOptionsTest.xml index 0ba20d201f909..0bfdc0eed289c 100644 --- a/app/code/Magento/Tinymce3/Test/Mftf/Test/AdminSwitchWYSIWYGOptionsTest.xml +++ b/app/code/Magento/Tinymce3/Test/Mftf/Test/AdminSwitchWYSIWYGOptionsTest.xml @@ -77,7 +77,7 @@ <waitForPageLoad stepKey="wait6" /> <!--see widget on Storefront--> <see userInput="Hello TinyMCE3!" stepKey="seeContent2"/> - <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> + <actionGroup ref="CliEnableTinyMCE4ActionGroup" stepKey="switchToTinyMCE4" /> <after> <actionGroup ref="DisabledWYSIWYGActionGroup" stepKey="disableWYSIWYG"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> From c7e78cd3cd4bd9a5136924cc8bf6a9425453de4a Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 1 Dec 2020 12:40:21 +0200 Subject: [PATCH 31/32] MC-39505: [MFTF] Flaky AdminMarketingNewsletterTemplateUpdateTest because of bad design --- .../Test/AdminMarketingNewsletterTemplateUpdateTest.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Newsletter/Test/Mftf/Test/AdminMarketingNewsletterTemplateUpdateTest.xml b/app/code/Magento/Newsletter/Test/Mftf/Test/AdminMarketingNewsletterTemplateUpdateTest.xml index 1a0c90ff13c36..1d8565d7b2b78 100644 --- a/app/code/Magento/Newsletter/Test/Mftf/Test/AdminMarketingNewsletterTemplateUpdateTest.xml +++ b/app/code/Magento/Newsletter/Test/Mftf/Test/AdminMarketingNewsletterTemplateUpdateTest.xml @@ -15,6 +15,9 @@ <title value="Newsletter Updating Test"/> <description value="Admin should be able update created Newsletter Template"/> <severity value="MAJOR"/> + <testCaseId value="MC-39506"/> + <useCaseId value="MAGETWO-69597"/> + <group value="newsletter"/> <group value="reports"/> <group value="mtf_migrated"/> <group value="WYSIWYGDisabled"/> @@ -40,6 +43,7 @@ </actionGroup> <actionGroup ref="AdminMarketingOpenNewsletterTemplateFromGridActionGroup" stepKey="openCreatedNewsletterTemplate"/> </before> + <after> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToNewsletterGridPage"> <argument name="menuUiId" value="{{AdminMenuMarketing.dataUiId}}"/> @@ -74,8 +78,8 @@ <argument name="subject" value="{{updatedNewsletter.subject}}"/> </actionGroup> <actionGroup ref="AdminSearchNewsletterTemplateOnGridActionGroup" stepKey="findUpdatedNewsletterTemplate"> - <argument name="name" value="Updated Newsletter Template"/> - <argument name="subject" value="Updated Newsletter Subject"/> + <argument name="name" value="{{updatedNewsletter.name}}"/> + <argument name="subject" value="{{updatedNewsletter.subject}}"/> </actionGroup> <actionGroup ref="AdminMarketingOpenNewsletterTemplateFromGridActionGroup" stepKey="openTemplate"/> <actionGroup ref="AssertAdminNewsletterTemplateFormActionGroup" stepKey="assertNewsletterForm"> From 2083ffffa5ba105a7f77a90327bd82a5b1adf09c Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Wed, 2 Dec 2020 10:15:27 +0200 Subject: [PATCH 32/32] MC-39539: [MFTF] Flaky AdminCreateCustomerTest because of bad design --- .../Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml index 7442a32d58b2d..5b6c4fd23e038 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml @@ -15,21 +15,24 @@ <title value="Admin should be able to create a customer"/> <description value="Admin should be able to create a customer"/> <severity value="BLOCKER"/> - <testCaseId value="MAGETWO-72095"/> + <testCaseId value="MC-28500"/> <group value="customer"/> <group value="create"/> </annotations> + <before> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindexCustomerGrid"> <argument name="indices" value="customer_grid"/> </actionGroup> </before> + <after> + <actionGroup ref="AdminClearCustomersFiltersActionGroup" stepKey="clearCustomersFilter"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="adminLogout"/> </after> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin1"/> - <amOnPage url="{{AdminCustomerPage.url}}" stepKey="navigateToCustomers"/> + <actionGroup ref="AdminClearCustomersFiltersActionGroup" stepKey="navigateToCustomers"/> <waitForPageLoad stepKey="waitForLoad1"/> <click selector="{{AdminCustomerGridMainActionsSection.addNewCustomer}}" stepKey="clickCreateCustomer"/> <fillField userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminCustomerAccountInformationSection.firstName}}" stepKey="fillFirstName"/>