diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php index 2e17e734b1e60..7bda179a11131 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php @@ -408,6 +408,7 @@ protected function saveAndReplaceAdvancedPrices() } elseif (\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND == $behavior) { $this->processCountExistingPrices($tierPrices, self::TABLE_TIER_PRICE) ->processCountNewPrices($tierPrices); + $this->saveProductPrices($tierPrices, self::TABLE_TIER_PRICE); if ($listSku) { $this->setUpdatedAt($listSku); @@ -562,11 +563,14 @@ protected function processCountExistingPrices($prices, $table) $tableName = $this->_resourceFactory->create()->getTable($table); $productEntityLinkField = $this->getProductEntityLinkField(); - $existingPrices = $this->_connection->fetchAssoc( + $existingPrices = $this->_connection->fetchAll( $this->_connection->select()->from( $tableName, - ['value_id', $productEntityLinkField, 'all_groups', 'customer_group_id'] - )->where($productEntityLinkField . ' IN (?)', $existProductIds) + [$productEntityLinkField, 'all_groups', 'customer_group_id', 'qty'] + )->where( + $productEntityLinkField . ' IN (?)', + $existProductIds + ) ); foreach ($existingPrices as $existingPrice) { foreach ($prices as $sku => $skuPrices) { @@ -591,8 +595,10 @@ protected function incrementCounterUpdated($prices, $existingPrice) foreach ($prices as $price) { if ($existingPrice['all_groups'] == $price['all_groups'] && $existingPrice['customer_group_id'] == $price['customer_group_id'] + && (int) $existingPrice['qty'] === (int) $price['qty'] ) { $this->countItemsUpdated++; + continue; } } } diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php index 340e81746f029..2aa59c1cfb758 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php +++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php @@ -921,7 +921,7 @@ public function testProcessCountExistingPrices( ); $dbSelectMock = $this->createMock(\Magento\Framework\DB\Select::class); $this->connection->expects($this->once()) - ->method('fetchAssoc') + ->method('fetchAll') ->willReturn($existingPrices); $this->connection->expects($this->once()) ->method('select') @@ -930,7 +930,7 @@ public function testProcessCountExistingPrices( ->method('from') ->with( self::TABLE_NAME, - ['value_id', self::LINK_FIELD, 'all_groups', 'customer_group_id'] + [self::LINK_FIELD, 'all_groups', 'customer_group_id', 'qty'] )->willReturnSelf(); $this->advancedPricing->expects($this->once()) ->method('retrieveOldSkus') diff --git a/app/code/Magento/Analytics/Test/Mftf/Section/AdminAdvancedReportingSection.xml b/app/code/Magento/Analytics/Test/Mftf/Section/AdminAdvancedReportingSection.xml new file mode 100644 index 0000000000000..7b6851e5bdf37 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Mftf/Section/AdminAdvancedReportingSection.xml @@ -0,0 +1,12 @@ + + + +
+ +
+
\ No newline at end of file diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingButtonTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingButtonTest.xml new file mode 100644 index 0000000000000..505e178f49f43 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingButtonTest.xml @@ -0,0 +1,35 @@ + + + + + + + + <description value="Test log in to AdvancedReporting and tests AdvancedReportingButtonTest"/> + <testCaseId value="MC-14800"/> + <severity value="CRITICAL"/> + <group value="analytics"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref = "LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Navigate through Advanced Reporting button on dashboard to Sign Up page--> + <amOnPage url="{{AdminDashboardPage.url}}" stepKey="amOnDashboardPage"/> + <waitForPageLoad stepKey="waitForDashboardPageLoad"/> + <click selector="{{AdminAdvancedReportingSection.goToAdvancedReporting}}" stepKey="clickGoToAdvancedReporting"/> + <switchToNextTab stepKey="switchToNewTab"/> + <seeInCurrentUrl url="advancedreporting.rjmetrics.com/report" stepKey="seeAssertAdvancedReportingPageUrl"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/config.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/config.xml index 24291187c0584..7324421d3c14b 100644 --- a/app/code/Magento/AuthorizenetAcceptjs/etc/config.xml +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/config.xml @@ -7,6 +7,13 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd"> <default> + <dev> + <js> + <minify_exclude> + <authorizenet_acceptjs>\.authorize\.net/v1/Accept</authorizenet_acceptjs> + </minify_exclude> + </js> + </dev> <payment> <authorizenet_acceptjs> <active>0</active> diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/base/requirejs-config.js b/app/code/Magento/AuthorizenetAcceptjs/view/base/requirejs-config.js index cbe0a6c30e699..83ddd1094ea1a 100644 --- a/app/code/Magento/AuthorizenetAcceptjs/view/base/requirejs-config.js +++ b/app/code/Magento/AuthorizenetAcceptjs/view/base/requirejs-config.js @@ -4,10 +4,16 @@ */ var config = { - map: { - '*': { - acceptjssandbox: 'https://jstest.authorize.net/v1/Accept.js', - acceptjs: 'https://js.authorize.net/v1/Accept.js' + shim: { + acceptjs: { + exports: 'Accept' + }, + acceptjssandbox: { + exports: 'Accept' } + }, + paths: { + acceptjssandbox: 'https://jstest.authorize.net/v1/Accept', + acceptjs: 'https://js.authorize.net/v1/Accept' } }; diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-factory.js b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-factory.js index c8813c17c70c7..e98a204e36cee 100644 --- a/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-factory.js +++ b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-factory.js @@ -16,7 +16,7 @@ define([ dependency = 'acceptjssandbox'; } - require([dependency], function () { + require([dependency], function (accept) { var $body = $('body'); /* @@ -26,16 +26,7 @@ define([ * Dynamically-loading-Accept-js-E-WC-03-Accept-js-is-not-loaded/td-p/63283 */ $body.on('handshake.acceptjs', function () { - /* - * Accept.js doesn't return the library when loading - * and requirejs "shim" can't be used because it only works with the "paths" config option - * and we can't use "paths" because require will try to load ".min.js" in production - * and that doesn't work because it doesn't exist - * and we can't add a query string to force a URL because accept.js will reject it - * and we can't include it locally because they check in the script before loading more scripts - * So, we use the global version as "shim" would - */ - deferred.resolve(window.Accept); + deferred.resolve(accept); $body.off('handshake.acceptjs'); }); }, diff --git a/app/code/Magento/Backup/Test/Mftf/ActionGroup/DeleteBackupActionGroup.xml b/app/code/Magento/Backup/Test/Mftf/ActionGroup/DeleteBackupActionGroup.xml index 4f34f24c3a806..b3a6e5d795cea 100644 --- a/app/code/Magento/Backup/Test/Mftf/ActionGroup/DeleteBackupActionGroup.xml +++ b/app/code/Magento/Backup/Test/Mftf/ActionGroup/DeleteBackupActionGroup.xml @@ -17,6 +17,7 @@ <click selector="{{AdminGridTableSection.backupRowCheckbox(backup.name)}}" stepKey="selectBackupRow"/> <selectOption selector="{{AdminGridActionSection.actionSelect}}" userInput="Delete" stepKey="selectDeleteAction"/> <click selector="{{AdminGridActionSection.submitButton}}" stepKey="clickSubmit"/> + <waitForPageLoad stepKey="waitForConfirmWindowToAppear"/> <see selector="{{AdminConfirmationModalSection.message}}" userInput="Are you sure you want to delete the selected backup(s)?" stepKey="seeConfirmationModal"/> <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="clickOkConfirmDelete"/> <dontSee selector="{{AdminGridTableSection.backupNameColumn}}" userInput="{{backup.name}}" stepKey="dontSeeBackupInGrid"/> diff --git a/app/code/Magento/Backup/Test/Mftf/Data/BackupData.xml b/app/code/Magento/Backup/Test/Mftf/Data/BackupData.xml index ae97351cafcaf..ad218cdd57500 100644 --- a/app/code/Magento/Backup/Test/Mftf/Data/BackupData.xml +++ b/app/code/Magento/Backup/Test/Mftf/Data/BackupData.xml @@ -20,4 +20,8 @@ <data key="name" unique="suffix">databaseBackup</data> <data key="type">Database</data> </entity> -</entities> + <entity name="WebSetupWizardBackup" type="backup"> + <data key="name">WebSetupWizard</data> + <data key="type">Database</data> + </entity> +</entities> \ No newline at end of file diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml new file mode 100644 index 0000000000000..a00f1e367864e --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml @@ -0,0 +1,14 @@ +<?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="VerifyProductTypeOrder"> + <seeElement stepKey="seeBundleInOrder" selector="{{AdminProductDropdownOrderSection.bundleProduct}}"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductDropdownOrderSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductDropdownOrderSection.xml new file mode 100644 index 0000000000000..787f7ade8ffab --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductDropdownOrderSection.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="AdminProductDropdownOrderSection"> + <element name="bundleProduct" type="text" selector="//li[not(preceding-sibling::li[span[@title='Downloadable Product']]) and not(following-sibling::li[span[@title='Simple Product']]) and not(following-sibling::li[span[@title='Configurable Product']]) and not(following-sibling::li[span[@title='Grouped Product']]) and not(following-sibling::li[span[@title='Virtual Product']])]/span[@title='Bundle Product']"/> + </section> +</sections> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/BundleProductFixedPricingTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/BundleProductFixedPricingTest.xml index 574c0dccdb07f..c922b981aecd9 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/BundleProductFixedPricingTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/BundleProductFixedPricingTest.xml @@ -31,6 +31,10 @@ <deleteData createDataKey="createPreReqCategory" stepKey="deletePreReqCategory"/> <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + <!-- Delete the bundled product we created in the test body --> + <actionGroup ref="deleteProductBySku" stepKey="deleteBundleProduct"> + <argument name="sku" value="{{BundleProduct.sku}}"/> + </actionGroup> <actionGroup ref="logout" stepKey="logout"/> </after> <!--Go to bundle product creation page--> diff --git a/app/code/Magento/Catalog/Api/ProductRenderListInterface.php b/app/code/Magento/Catalog/Api/ProductRenderListInterface.php index f79efa4c814d7..954acd35a07db 100644 --- a/app/code/Magento/Catalog/Api/ProductRenderListInterface.php +++ b/app/code/Magento/Catalog/Api/ProductRenderListInterface.php @@ -4,18 +4,22 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Catalog\Api; /** - * Interface which provides product renders information for products + * Interface which provides product renders information for products. + * * @api * @since 101.1.0 */ interface ProductRenderListInterface { /** - * Collect and retrieve the list of product render info - * This info contains raw prices and formated prices, product name, stock status, store_id, etc + * Collect and retrieve the list of product render info. + * + * This info contains raw prices and formatted prices, product name, stock status, store_id, etc. + * * @see \Magento\Catalog\Api\Data\ProductRenderInfoDtoInterface * * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria diff --git a/app/code/Magento/Catalog/Block/Product/View/Options/AbstractOptions.php b/app/code/Magento/Catalog/Block/Product/View/Options/AbstractOptions.php index 181211a0fc4a2..059580b9b5eae 100644 --- a/app/code/Magento/Catalog/Block/Product/View/Options/AbstractOptions.php +++ b/app/code/Magento/Catalog/Block/Product/View/Options/AbstractOptions.php @@ -9,11 +9,14 @@ * * @author Magento Core Team <core@magentocommerce.com> */ + namespace Magento\Catalog\Block\Product\View\Options; use Magento\Catalog\Pricing\Price\CustomOptionPriceInterface; /** + * Product aoptions section abstract block. + * * @api * @since 100.0.2 */ @@ -46,7 +49,7 @@ abstract class AbstractOptions extends \Magento\Framework\View\Element\Template /** * @param \Magento\Framework\View\Element\Template\Context $context * @param \Magento\Framework\Pricing\Helper\Data $pricingHelper - * @param \Magento\Catalog\Helper\Data $catalogData, + * @param \Magento\Catalog\Helper\Data $catalogData * @param array $data */ public function __construct( @@ -123,6 +126,8 @@ public function getFormattedPrice() } /** + * Retrieve formatted price. + * * @return string * * @deprecated @@ -134,7 +139,7 @@ public function getFormatedPrice() } /** - * Return formated price + * Return formatted price * * @param array $value * @param bool $flag diff --git a/app/code/Magento/Catalog/Model/Category/Tree.php b/app/code/Magento/Catalog/Model/Category/Tree.php index 6080f74d5fa06..0a9cb25d7b0e5 100644 --- a/app/code/Magento/Catalog/Model/Category/Tree.php +++ b/app/code/Magento/Catalog/Model/Category/Tree.php @@ -32,27 +32,40 @@ class Tree */ protected $treeFactory; + /** + * @var \Magento\Catalog\Model\ResourceModel\Category\TreeFactory + */ + private $treeResourceFactory; + /** * @param \Magento\Catalog\Model\ResourceModel\Category\Tree $categoryTree * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Catalog\Model\ResourceModel\Category\Collection $categoryCollection * @param \Magento\Catalog\Api\Data\CategoryTreeInterfaceFactory $treeFactory + * @param \Magento\Catalog\Model\ResourceModel\Category\TreeFactory|null $treeResourceFactory */ public function __construct( \Magento\Catalog\Model\ResourceModel\Category\Tree $categoryTree, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Catalog\Model\ResourceModel\Category\Collection $categoryCollection, - \Magento\Catalog\Api\Data\CategoryTreeInterfaceFactory $treeFactory + \Magento\Catalog\Api\Data\CategoryTreeInterfaceFactory $treeFactory, + \Magento\Catalog\Model\ResourceModel\Category\TreeFactory $treeResourceFactory = null ) { $this->categoryTree = $categoryTree; $this->storeManager = $storeManager; $this->categoryCollection = $categoryCollection; $this->treeFactory = $treeFactory; + $this->treeResourceFactory = $treeResourceFactory ?? \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Catalog\Model\ResourceModel\Category\TreeFactory::class); } /** + * Get root node by category. + * * @param \Magento\Catalog\Model\Category|null $category * @return Node|null + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function getRootNode($category = null) { @@ -71,13 +84,18 @@ public function getRootNode($category = null) } /** + * Get node by category. + * * @param \Magento\Catalog\Model\Category $category * @return Node + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException */ protected function getNode(\Magento\Catalog\Model\Category $category) { $nodeId = $category->getId(); - $node = $this->categoryTree->loadNode($nodeId); + $categoryTree = $this->treeResourceFactory->create(); + $node = $categoryTree->loadNode($nodeId); $node->loadChildren(); $this->prepareCollection(); $this->categoryTree->addCollectionData($this->categoryCollection); @@ -85,7 +103,11 @@ protected function getNode(\Magento\Catalog\Model\Category $category) } /** + * Prepare category collection. + * * @return void + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException */ protected function prepareCollection() { @@ -104,6 +126,8 @@ protected function prepareCollection() } /** + * Get tree by node. + * * @param \Magento\Framework\Data\Tree\Node $node * @param int $depth * @param int $currentLevel @@ -127,6 +151,8 @@ public function getTree($node, $depth = null, $currentLevel = 0) } /** + * Get node children. + * * @param \Magento\Framework\Data\Tree\Node $node * @param int $depth * @param int $currentLevel diff --git a/app/code/Magento/Catalog/Model/CategoryList.php b/app/code/Magento/Catalog/Model/CategoryList.php index e3318db505489..cab8e013d9ba1 100644 --- a/app/code/Magento/Catalog/Model/CategoryList.php +++ b/app/code/Magento/Catalog/Model/CategoryList.php @@ -76,11 +76,10 @@ public function getList(SearchCriteriaInterface $searchCriteria) $this->extensionAttributesJoinProcessor->process($collection); $this->collectionProcessor->process($searchCriteria, $collection); - $collection->load(); $items = []; - foreach ($collection->getItems() as $category) { - $items[] = $this->categoryRepository->get($category->getId()); + foreach ($collection->getAllIds() as $id) { + $items[] = $this->categoryRepository->get($id); } /** @var CategorySearchResultsInterface $searchResult */ diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml index 89bfc1ac19eb2..d786795bc3090 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml @@ -231,6 +231,23 @@ <waitForPageLoad stepKey="waitForStoreViewChangeLoad"/> </actionGroup> + <actionGroup name="switchCategoryToAllStoreView"> + <arguments> + <argument name="CatName"/> + </arguments> + <click selector="{{AdminCategorySidebarTreeSection.categoryInTree(CatName)}}" stepKey="navigateToCreatedCategory" /> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <waitForLoadingMaskToDisappear stepKey="waitForSpinner1"/> + <scrollToTopOfPage stepKey="scrollToToggle"/> + <click selector="{{AdminCategoryMainActionsSection.CategoryStoreViewDropdownToggle}}" stepKey="openStoreViewDropDown"/> + <click selector="{{AdminCategoryMainActionsSection.allStoreViews}}" stepKey="clickStoreViewByName"/> + <see selector="{{AdminCategoryMainActionsSection.storeSwitcher}}" userInput="All Store Views" stepKey="seeAllStoreView"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <waitForLoadingMaskToDisappear stepKey="waitForSpinner2"/> + <click selector="{{AdminCategoryMainActionsSection.CategoryStoreViewModalAccept}}" stepKey="selectStoreViewAccept"/> + <waitForPageLoad stepKey="waitForStoreViewChangeLoad"/> + </actionGroup> + <actionGroup name="navigateToCreatedCategory"> <arguments> <argument name="Category"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml index acf7800dfed7c..2914ecc470220 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml @@ -74,4 +74,21 @@ <click selector="{{AdminProductAttributeSetGridSection.nthRow('1')}}" stepKey="clickFirstRow"/> <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> </actionGroup> + + <!-- Delete attribute set --> + <actionGroup name="deleteAttributeSetByLabel"> + <arguments> + <argument name="label" type="string"/> + </arguments> + <amOnPage url="{{AdminProductAttributeSetGridPage.url}}" stepKey="goToAttributeSets"/> + <waitForPageLoad stepKey="waitForAttributeSetPageLoad"/> + <fillField selector="{{AdminProductAttributeSetGridSection.filter}}" userInput="{{label}}" stepKey="filterByName"/> + <click selector="{{AdminProductAttributeSetGridSection.searchBtn}}" stepKey="clickSearch"/> + <click selector="{{AdminProductAttributeSetGridSection.nthRow('1')}}" stepKey="clickFirstRow"/> + <waitForPageLoad stepKey="waitForClick"/> + <click selector="{{AdminProductAttributeSetSection.deleteBtn}}" stepKey="clickDelete"/> + <click selector="{{AdminProductAttributeSetSection.modalOk}}" stepKey="confirmDelete"/> + <waitForPageLoad stepKey="waitForDeleteToFinish"/> + <see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="The attribute set has been removed." stepKey="seeDeleteMessage"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAttributeDeletionErrorMessageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAttributeDeletionErrorMessageActionGroup.xml new file mode 100644 index 0000000000000..9402ac05d79a5 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAttributeDeletionErrorMessageActionGroup.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="AssertAttributeDeletionErrorMessageActionGroup"> + <waitForElementVisible selector="{{AdminProductMessagesSection.errorMessage}}" stepKey="waitForErrorMessage"/> + <see selector="{{AdminProductMessagesSection.errorMessage}}" userInput="This attribute is used in configurable products." stepKey="deleteProductAttributeFailureMessage"/> + </actionGroup> +</actionGroups> + diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductAttributePresenceInCatalogProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductAttributePresenceInCatalogProductGridActionGroup.xml new file mode 100644 index 0000000000000..25390e6b4a80b --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductAttributePresenceInCatalogProductGridActionGroup.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="AssertProductAttributePresenceInCatalogProductGridActionGroup"> + <arguments> + <argument name="productAttribute" type="entity"/> + </arguments> + <waitForPageLoad stepKey="waitForCatalogProductGridPageLoad"/> + <seeElement selector="{{AdminGridHeaders.headerByName(productAttribute.label)}}" stepKey="seeAttributeInHeaders"/> + </actionGroup> +</actionGroups> + diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/DeleteProductAttributeByAttributeCodeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/DeleteProductAttributeByAttributeCodeActionGroup.xml new file mode 100644 index 0000000000000..575cbdcd9b6dc --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/DeleteProductAttributeByAttributeCodeActionGroup.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="DeleteProductAttributeByAttributeCodeActionGroup"> + <arguments> + <argument name="productAttributeCode" type="string"/> + </arguments> + <waitForPageLoad stepKey="waitForViewAdminProductAttributeLoad" time="30" /> + <click selector="{{AttributePropertiesSection.DeleteAttribute}}" stepKey="deleteAttribute"/> + <click selector="{{ModalConfirmationSection.OkButton}}" stepKey="clickOnConfirmOk"/> + <waitForPageLoad stepKey="waitForViewProductAttributePageLoad"/> +</actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenProductAttributeFromSearchResultInGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenProductAttributeFromSearchResultInGridActionGroup.xml new file mode 100644 index 0000000000000..31b024c82a9a0 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenProductAttributeFromSearchResultInGridActionGroup.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="OpenProductAttributeFromSearchResultInGridActionGroup" extends="SearchAttributeByCodeOnProductAttributeGridActionGroup"> + <arguments> + <argument name="productAttributeCode" type="string"/> + </arguments> + <waitForElementVisible selector="{{AdminProductAttributeGridSection.AttributeCode(productAttributeCode)}}" stepKey="waitForAdminProductAttributeGridLoad"/> + <click selector="{{AdminProductAttributeGridSection.AttributeCode(productAttributeCode)}}" stepKey="clickAttributeToView"/> + <waitForPageLoad stepKey="waitForViewAdminProductAttributeLoad" /> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchAttributeByCodeOnProductAttributeGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchAttributeByCodeOnProductAttributeGridActionGroup.xml new file mode 100644 index 0000000000000..67cdd8192fcb4 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchAttributeByCodeOnProductAttributeGridActionGroup.xml @@ -0,0 +1,24 @@ +<?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="SearchAttributeByCodeOnProductAttributeGridActionGroup"> + <arguments> + <argument name="productAttributeCode" type="string"/> + </arguments> + <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttributeGrid"/> + <waitForPageLoad stepKey="waitForAdminProductAttributeGridLoad"/> + <click selector="{{AdminProductAttributeGridSection.ResetFilter}}" stepKey="resetFiltersOnGrid"/> + <waitForPageLoad stepKey="waitForAdminProductAttributeGridSectionLoad"/> + <fillField selector="{{AdminProductAttributeGridSection.FilterByAttributeCode}}" userInput="{{productAttributeCode}}" stepKey="setAttributeCode"/> + <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="searchForAttributeFromTheGrid"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskOnGridToDisappear"/> + <see selector="{{AdminProductAttributeGridSection.attributeCodeColumn}}" userInput="{{productAttributeCode}}" stepKey="seeAttributeCodeInGrid"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml new file mode 100644 index 0000000000000..aec21f3bc48c9 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml @@ -0,0 +1,17 @@ +<?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="VerifyProductTypeOrder"> + <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickAddProductDropdown"/> + <waitForPageLoad stepKey="waitForLoad"/> + <seeElement stepKey="seeSimpleInOrder" selector="{{AdminProductDropdownOrderSection.simpleProduct}}"/> + <seeElement stepKey="seeVirtualInOrder" selector="{{AdminProductDropdownOrderSection.virtualProduct}}"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/CatalogSpecialPriceData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogSpecialPriceData.xml new file mode 100644 index 0000000000000..4c6b0749a0f9e --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogSpecialPriceData.xml @@ -0,0 +1,15 @@ +<?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="specialProductPrice" type="catalogSpecialPrice"> + <data key="price">99.99</data> + <data key="store_id">0</data> + <var key="sku" entityType="product2" entityKey="sku" /> + </entity> +</entities> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml index 6e1db92f5a040..134abcaa50354 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml @@ -52,6 +52,27 @@ <data key="used_for_sort_by">true</data> <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity> </entity> + <entity name="productAttributeWithTwoOptionsNotVisible" type="ProductAttribute"> + <data key="attribute_code" unique="suffix">test_attr_</data> + <data key="frontend_input">select</data> + <data key="scope">global</data> + <data key="is_required">false</data> + <data key="is_unique">false</data> + <data key="is_searchable">false</data> + <data key="is_visible">true</data> + <data key="is_visible_in_advanced_search">false</data> + <data key="is_visible_on_front">false</data> + <data key="is_filterable">false</data> + <data key="is_filterable_in_search">false</data> + <data key="used_in_product_listing">false</data> + <data key="is_used_for_promo_rules">false</data> + <data key="is_comparable">false</data> + <data key="is_used_in_grid">false</data> + <data key="is_visible_in_grid">false</data> + <data key="is_filterable_in_grid">false</data> + <data key="used_for_sort_by">false</data> + <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity> + </entity> <entity name="productDropDownAttribute" type="ProductAttribute"> <data key="attribute_code" unique="suffix">attribute</data> <data key="frontend_input">select</data> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index d812123e4b553..0b3a31194ea36 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -96,6 +96,31 @@ <data key="quantity">0</data> <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> + <entity name="SimpleOutOfStockProduct" type="product"> + <data key="sku" unique="suffix">testSku</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">OutOfStockProduct</data> + <data key="price">123.00</data> + <data key="urlKey" unique="suffix">testurlkey</data> + <data key="status">1</data> + <data key="quantity">0</data> + </entity> + <!-- Simple Product Disabled --> + <entity name="SimpleProductOffline" type="product2"> + <data key="sku" unique="suffix">testSku</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">SimpleOffline</data> + <data key="price">123.00</data> + <data key="status">2</data> + <data key="quantity">100</data> + <data key="urlKey" unique="suffix">testurlkey</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute">CustomAttributeProductAttribute</requiredEntity> + </entity> <entity name="NewSimpleProduct" type="product"> <data key="price">321.00</data> </entity> @@ -110,6 +135,18 @@ <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute">CustomAttributeProductAttribute</requiredEntity> </entity> + <entity name="ApiSimpleOutOfStock" type="product2"> + <data key="sku" unique="suffix">api-simple-product</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">Api Simple Out Of Stock Product</data> + <data key="price">123.00</data> + <data key="urlKey" unique="suffix">api-simple-product</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="custom_attribute">CustomAttributeProductAttribute</requiredEntity> + </entity> <entity name="ApiSimpleOne" type="product2"> <data key="sku" unique="suffix">api-simple-product</data> <data key="type_id">simple</data> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml index a3a358fda44fd..e5070340421a9 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml @@ -48,4 +48,12 @@ <data key="price">500,000.00</data> <data key="qty">1</data> </entity> + <entity name="tierProductPrice" type="catalogTierPrice"> + <data key="price">90.00</data> + <data key="price_type">fixed</data> + <data key="website_id">0</data> + <data key="customer_group">ALL GROUPS</data> + <data key="quantity">2</data> + <var key="sku" entityType="product2" entityKey="sku" /> + </entity> </entities> \ No newline at end of file diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_special_price-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_special_price-meta.xml new file mode 100644 index 0000000000000..354277ad056f7 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_special_price-meta.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="catalogSpecialPrice" dataType="catalogSpecialPrice" type="create" auth="adminOauth" url="/V1/products/special-price" method="POST"> + <contentType>application/json</contentType> + <object key="prices" dataType="catalogSpecialPrice"> + <object dataType="catalogSpecialPrice" key="0"> + <field key="price">number</field> + <field key="store_id">integer</field> + <field key="sku">string</field> + <field key="price_from">string</field> + <field key="price_to">string</field> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_tier_price-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_tier_price-meta.xml new file mode 100644 index 0000000000000..7aa7530b0fda8 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_tier_price-meta.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="catalogTierPrice" dataType="catalogTierPrice" type="create" auth="adminOauth" url="/V1/products/tier-prices" method="POST"> + <contentType>application/json</contentType> + <object key="prices" dataType="catalogTierPrice"> + <object dataType="catalogTierPrice" key="0"> + <field key="price">number</field> + <field key="price_type">string</field> + <field key="website_id">integer</field> + <field key="sku">string</field> + <field key="customer_group">string</field> + <field key="quantity">integer</field> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryMainActionsSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryMainActionsSection.xml index 009110a729bde..e8adede5b2de6 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryMainActionsSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryMainActionsSection.xml @@ -14,5 +14,7 @@ <element name="CategoryStoreViewDropdownToggle" type="button" selector="#store-change-button"/> <element name="CategoryStoreViewOption" type="button" selector="//div[contains(@class, 'store-switcher')]//a[normalize-space()='{{store}}']" parameterized="true"/> <element name="CategoryStoreViewModalAccept" type="button" selector=".modal-popup.confirm._show .action-accept"/> + <element name="allStoreViews" type="button" selector=".store-switcher .store-switcher-all" timeout="30"/> + <element name="storeSwitcher" type="text" selector=".store-switcher"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml index 263a445b0fc64..d24c501152b78 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml @@ -46,6 +46,7 @@ <element name="StoreFrontPropertiesTab" selector="#product_attribute_tabs_front" type="button"/> <element name="EnableWYSIWYG" type="select" selector="#enabled"/> <element name="useForPromoRuleConditions" type="select" selector="#is_used_for_promo_rules"/> + <element name="StorefrontPropertiesSectionToggle" type="button" selector="#front_fieldset-wrapper"/> </section> <section name="WYSIWYGProductAttributeSection"> <element name="ShowHideBtn" type="button" selector="#toggledefault_value_texteditor"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductDropdownOrderSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductDropdownOrderSection.xml new file mode 100644 index 0000000000000..b58fb2316f915 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductDropdownOrderSection.xml @@ -0,0 +1,15 @@ +<?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="AdminProductDropdownOrderSection"> + <element name="simpleProduct" type="text" selector="//li[not(preceding-sibling::li)]//span[@title='Simple Product']"/> + <element name="virtualProduct" type="text" selector="//li[not(preceding-sibling::li[span[@title='Bundle Product']]) and not(preceding-sibling::li[span[@title='Downloadable Product']]) and not(following-sibling::li[span[@title='Simple Product']]) and not(following-sibling::li[span[@title='Configurable Product']]) and not(following-sibling::li[span[@title='Grouped Product']])]/span[@title='Virtual Product']"/> + </section> +</sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml index 656a844d49700..da282d06145aa 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml @@ -13,17 +13,23 @@ <element name="attributeSetFilterResult" type="input" selector="div[data-index='attribute_set_id'] .action-menu-item._last" timeout="30"/> <element name="attributeSetFilterResultByName" type="text" selector="//label/span[text() = '{{var}}']" timeout="30" parameterized="true"/> <element name="productName" type="input" selector=".admin__field[data-index=name] input"/> + <element name="productNameDisabled" type="input" selector=".admin__field[data-index=name] input[disabled=true]"/> <element name="RequiredNameIndicator" type="text" selector=" return window.getComputedStyle(document.querySelector('._required[data-index=name]>.admin__field-label span'), ':after').getPropertyValue('content');"/> <element name="RequiredSkuIndicator" type="text" selector=" return window.getComputedStyle(document.querySelector('._required[data-index=sku]>.admin__field-label span'), ':after').getPropertyValue('content');"/> <element name="productSku" type="input" selector=".admin__field[data-index=sku] input"/> + <element name="productSkuDisabled" type="input" selector=".admin__field[data-index=sku] input[disabled=true]"/> <element name="enableProductAttributeLabel" type="text" selector="//span[text()='Enable Product']/parent::label"/> <element name="enableProductAttributeLabelWrapper" type="text" selector="//span[text()='Enable Product']/parent::label/parent::div"/> <element name="productStatus" type="checkbox" selector="input[name='product[status]']"/> + <element name="productStatusDisabled" type="checkbox" selector="input[name='product[status]'][disabled]"/> <element name="enableProductLabel" type="checkbox" selector="input[name='product[status]']+label"/> <element name="productStatusUseDefault" type="checkbox" selector="input[name='use_default[status]']"/> <element name="productNameUseDefault" type="checkbox" selector="input[name='use_default[name]']"/> <element name="productPrice" type="input" selector=".admin__field[data-index=price] input"/> + <element name="productPriceDisabled" type="input" selector=".admin__field[data-index=price] input[disabled=true]"/> + <element name="productPriceUseDefault" type="checkbox" selector=".admin__field[data-index=price] [name='use_default[price]']"/> <element name="productTaxClass" type="select" selector="//*[@name='product[tax_class_id]']"/> + <element name="productTaxClassDisabled" type="select" selector="select[name='product[tax_class_id]'][disabled=true]"/> <element name="productTaxClassUseDefault" type="checkbox" selector="input[name='use_default[tax_class_id]']"/> <element name="advancedPricingLink" type="button" selector="button[data-index='advanced_pricing_button']" timeout="30"/> <element name="categoriesDropdown" type="multiselect" selector="div[data-index='category_ids']"/> @@ -31,6 +37,7 @@ <element name="productQuantity" type="input" selector=".admin__field[data-index=qty] input"/> <element name="advancedInventoryLink" type="button" selector="//button[contains(@data-index, 'advanced_inventory_button')]" timeout="30"/> <element name="productStockStatus" type="select" selector="select[name='product[quantity_and_stock_status][is_in_stock]']"/> + <element name="productStockStatusDisabled" type="select" selector="select[name='product[quantity_and_stock_status][is_in_stock]'][disabled=true]"/> <element name="stockStatus" type="select" selector="[data-index='product-details'] select[name='product[quantity_and_stock_status][is_in_stock]']"/> <element name="productWeight" type="input" selector=".admin__field[data-index=weight] input"/> <element name="productWeightSelect" type="select" selector="select[name='product[product_has_weight]']"/> @@ -48,6 +55,7 @@ <element name="productFormTab" type="button" selector="//strong[@class='admin__collapsible-title']/span[contains(text(), '{{tabName}}')]" parameterized="true"/> <element name="productFormTabState" type="text" selector="//strong[@class='admin__collapsible-title']/span[contains(text(), '{{tabName}}')]/parent::*/parent::*[@data-state-collapsible='{{state}}']" parameterized="true"/> <element name="visibility" type="select" selector="//select[@name='product[visibility]']"/> + <element name="visibilityDisabled" type="select" selector="select[name='product[visibility]'][disabled=true]"/> <element name="visibilityUseDefault" type="checkbox" selector="//input[@name='use_default[visibility]']"/> <element name="divByDataIndex" type="input" selector="div[data-index='{{var}}']" parameterized="true"/> <element name="setProductAsNewFrom" type="input" selector="input[name='product[news_from_date]']"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml index 43345c69e6c04..939974248aabf 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridFilterSection.xml @@ -28,6 +28,7 @@ <element name="priceFilterTo" type="input" selector="input.admin__control-text[name='price[to]']"/> <element name="typeFilter" type="select" selector="select.admin__control-select[name='type_id']"/> <element name="statusFilter" type="select" selector="select.admin__control-select[name='status']"/> + <element name="firstRowBySku" type="button" selector="//div[text()='{{var}}']/ancestor::tr" parameterized="true" timeout="30"/> <element name="newFromDateFilter" type="input" selector="input.admin__control-text[name='news_from_date[from]']"/> <element name="keywordSearch" type="input" selector="input#fulltext"/> <element name="keywordSearchButton" type="button" selector=".data-grid-search-control-wrap button.action-submit" timeout="30"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryProductSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryProductSection.xml index f35eb63ee0e0a..51b5a0242d976 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryProductSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryProductSection.xml @@ -32,5 +32,6 @@ <!--<element name="ProductAddToCompareByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//a[contains(@class, 'tocompare')]" parameterized="true"/>--> <element name="ProductAddToCompareByName" type="text" selector="//*[contains(@class,'product-item-info')][descendant::a[contains(text(), '{{var1}}')]]//a[contains(@class, 'tocompare')]" parameterized="true"/> <element name="ProductImageByNameAndSrc" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//img[contains(@src, '{{src}}')]" parameterized="true"/> + <element name="ProductStockUnavailable" type="text" selector="//*[text()='Out of stock']"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductInfoMainSection.xml index 058f369ad139b..8504683648bce 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductInfoMainSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -74,6 +74,11 @@ <element name="productTierPriceAmount" type="text" selector="//ul[contains(@class, 'prices-tier')]//li[{{var1}}]//span[contains(text(), '{{var2}}')]" parameterized="true"/> <element name="productTierPriceSavePercentageAmount" type="text" selector="//ul[contains(@class, 'prices-tier')]//li[{{var1}}]//span[contains(@class, 'percent')][contains(text(), '{{var2}}')]" parameterized="true"/> + <!-- Special price selectors --> + <element name="productSpecialPrice" type="text" selector="//span[@data-price-type='finalPrice']/span"/> + <element name="specialProductText" type="text" selector="//span[text()='Regular Price']"/> + <element name="oldProductPrice" type="text" selector="//span[@data-price-type='oldPrice']/span"/> + <!-- Customizable Option selectors --> <element name="allCustomOptionLabels" type="text" selector="#product-options-wrapper label"/> <element name="customOptionLabel" type="text" selector="//label[contains(., '{{customOptionTitle}}')]" parameterized="true"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminVerifyProductOrderTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminVerifyProductOrderTest.xml new file mode 100644 index 0000000000000..a81c26b6e6eaf --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminVerifyProductOrderTest.xml @@ -0,0 +1,31 @@ +<?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="AdminVerifyProductOrder"> + <annotations> + <features value="Catalog"/> + <stories value="Verify Product Order"/> + <title value="Admin should see product types in specified order"/> + <description value="Product Type Order should be Simple -> Configurable -> Grouped -> Virtual -> Bundle -> Downloadable -> EE"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-14207"/> + <group value="mtf_migrated"/> + <group value="product"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <actionGroup ref="GoToProductCatalogPage" stepKey="goToProductCatalogPage"/> + <actionGroup ref="VerifyProductTypeOrder" stepKey="verifyProductTypeOrder"/> + </test> +</tests> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/DeleteUsedInConfigurableProductAttributeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/DeleteUsedInConfigurableProductAttributeTest.xml new file mode 100644 index 0000000000000..e79e4cea408fb --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/DeleteUsedInConfigurableProductAttributeTest.xml @@ -0,0 +1,105 @@ +<?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="DeleteUsedInConfigurableProductAttributeTest"> + <annotations> + <stories value="Delete product attribute"/> + <title value="Admin should not be able to delete product attribute used in configurable product"/> + <description value="Admin should not be able to delete product attribute used in configurable product"/> + <testCaseId value="MC-14061"/> + <severity value="CRITICAL"/> + <group value="Catalog"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <!-- Create category --> + <createData entity="SimpleSubCategory" stepKey="categoryHandle"/> + + <!-- Create base configurable product--> + <createData entity="BaseConfigurableProduct" stepKey="baseConfigProductHandle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + + <!-- Create Dropdown Product Attribute --> + <createData entity="productDropDownAttribute" stepKey="productAttributeHandle"/> + + <!--Create attribute options --> + <createData entity="productAttributeOption1" stepKey="productAttributeOption1Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + <createData entity="productAttributeOption2" stepKey="productAttributeOption2Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + + <!--Add to attribute to Default attribute set--> + <createData entity="AddToDefaultSet" stepKey="addToAttributeSetHandle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + + <!-- Get handle of the attribute options --> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getAttributeOption1Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getAttributeOption2Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </getData> + + <!--Create configurable product with the options --> + <createData entity="ConfigurableProductTwoOptions" stepKey="configProductOptionHandle"> + <requiredEntity createDataKey="baseConfigProductHandle"/> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption1Handle"/> + <requiredEntity createDataKey="getAttributeOption2Handle"/> + </createData> + + <!-- Login As Admin --> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Delete the configurable product created in the before block --> + <deleteData createDataKey="baseConfigProductHandle" stepKey="deleteConfig"/> + + <!-- Delete the category created in the before block --> + <deleteData createDataKey="categoryHandle" stepKey="deleteCategory"/> + + <!-- Delete configurable product attribute created in the before block --> + <deleteData createDataKey="productAttributeHandle" stepKey="deleteProductAttribute"/> + + <!-- Logout --> + <actionGroup ref="logout" stepKey="logoutFromAdmin"/> + </after> + <!-- Go to Stores > Attributes > Products. Search and select the product attribute that was used to create the configurable product--> + <actionGroup ref="OpenProductAttributeFromSearchResultInGridActionGroup" stepKey="openProductAttributeFromSearchResultInGrid"> + <argument name="productAttributeCode" value="$$productAttributeHandle.attribute_code$$"/> + </actionGroup> + + <!-- Click Delete Attribute button --> + <actionGroup ref="DeleteProductAttributeByAttributeCodeActionGroup" stepKey="deleteProductAttributeByAttributeCode"> + <argument name="productAttributeCode" value="$$productAttributeHandle.attribute_code$$"/> + </actionGroup> + + <!-- Should see error message: This attribute is used in configurable products. --> + <actionGroup ref="AssertAttributeDeletionErrorMessageActionGroup" stepKey="assertAttributeDeletionErrorMessage"/> + + <!-- Go back to the product attribute grid. Should see the product attribute in the grid --> + <actionGroup ref="SearchAttributeByCodeOnProductAttributeGridActionGroup" stepKey="searchAttributeByCodeOnProductAttributeGrid"> + <argument name="productAttributeCode" value="$$productAttributeHandle.attribute_code$$"/> + </actionGroup> + + <!-- Go to the Catalog > Products page and search configurable product created in before block.--> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForProductOnBackend"> + <argument name="product" value="$$baseConfigProductHandle$$"/> + </actionGroup> + + <!--Should see the product attributes as expected --> + <actionGroup ref="AssertProductAttributePresenceInCatalogProductGridActionGroup" stepKey="assertProductAttributePresenceInCatalogProductGrid"> + <argument name="productAttribute" value="$$productAttributeHandle$$"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/TreeTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/TreeTest.php index 9fb2adb2b8ecd..97c098ba0ff2e 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Category/TreeTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/TreeTest.php @@ -43,6 +43,11 @@ class TreeTest extends \PHPUnit\Framework\TestCase */ protected $node; + /** + * @var \Magento\Catalog\Model\ResourceModel\Category\TreeFactory + */ + private $treeResourceFactoryMock; + protected function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -59,6 +64,12 @@ protected function setUp() \Magento\Store\Model\StoreManagerInterface::class )->disableOriginalConstructor()->getMock(); + $this->treeResourceFactoryMock = $this->createMock( + \Magento\Catalog\Model\ResourceModel\Category\TreeFactory::class + ); + $this->treeResourceFactoryMock->method('create') + ->willReturn($this->categoryTreeMock); + $methods = ['create']; $this->treeFactoryMock = $this->createPartialMock(\Magento\Catalog\Api\Data\CategoryTreeInterfaceFactory::class, $methods); @@ -70,7 +81,8 @@ protected function setUp() 'categoryCollection' => $this->categoryCollection, 'categoryTree' => $this->categoryTreeMock, 'storeManager' => $this->storeManagerMock, - 'treeFactory' => $this->treeFactoryMock + 'treeFactory' => $this->treeFactoryMock, + 'treeResourceFactory' => $this->treeResourceFactoryMock, ] ); } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php index f78c0ad924954..b8b76524099f4 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php @@ -93,7 +93,7 @@ public function testGetList() $collection = $this->getMockBuilder(Collection::class)->disableOriginalConstructor()->getMock(); $collection->expects($this->once())->method('getSize')->willReturn($totalCount); - $collection->expects($this->once())->method('getItems')->willReturn([$categoryFirst, $categorySecond]); + $collection->expects($this->once())->method('getAllIds')->willReturn([$categoryIdFirst, $categoryIdSecond]); $this->collectionProcessorMock->expects($this->once()) ->method('process') diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php index e910a5c8be4cd..24c5e664831e4 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php @@ -7,7 +7,6 @@ namespace Magento\CatalogGraphQl\Model\Resolver; -use Magento\Framework\Exception\InputException; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\CatalogGraphQl\Model\Resolver\Products\Query\Filter; use Magento\CatalogGraphQl\Model\Resolver\Products\Query\Search; @@ -17,7 +16,6 @@ use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\SearchFilter; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Catalog\Model\Layer\Resolver; -use Magento\Framework\Api\Search\SearchCriteriaInterface; /** * Products field resolver, used for GraphQL request processing. @@ -82,10 +80,10 @@ public function resolve( } elseif (isset($args['search'])) { $layerType = Resolver::CATALOG_LAYER_SEARCH; $this->searchFilter->add($args['search'], $searchCriteria); - $searchResult = $this->getSearchResult($this->searchQuery, $searchCriteria, $info); + $searchResult = $this->searchQuery->getResult($searchCriteria, $info); } else { $layerType = Resolver::CATALOG_LAYER_CATEGORY; - $searchResult = $this->getSearchResult($this->filterQuery, $searchCriteria, $info); + $searchResult = $this->filterQuery->getResult($searchCriteria, $info); } //possible division by 0 if ($searchCriteria->getPageSize()) { @@ -117,25 +115,4 @@ public function resolve( return $data; } - - /** - * Get search result. - * - * @param Filter|Search $query - * @param SearchCriteriaInterface $searchCriteria - * @param ResolveInfo $info - * - * @return \Magento\CatalogGraphQl\Model\Resolver\Products\SearchResult - * @throws GraphQlInputException - */ - private function getSearchResult($query, SearchCriteriaInterface $searchCriteria, ResolveInfo $info) - { - try { - $searchResult = $query->getResult($searchCriteria, $info); - } catch (InputException $e) { - throw new GraphQlInputException(__($e->getMessage())); - } - - return $searchResult; - } } diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Setup/PropertyMapper.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Setup/PropertyMapper.php new file mode 100644 index 0000000000000..f72e1536f4710 --- /dev/null +++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Setup/PropertyMapper.php @@ -0,0 +1,34 @@ +<?php +declare(strict_types=1); + +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\CatalogSearch\Model\ResourceModel\Setup; + +use Magento\Eav\Model\Entity\Setup\PropertyMapperAbstract; + +/** + * Class PropertyMapper + * + * @package Magento\CatalogSearch\Model\ResourceModel\Setup + */ +class PropertyMapper extends PropertyMapperAbstract +{ + /** + * Map input attribute properties to storage representation + * + * @param array $input + * @param int $entityTypeId + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function map(array $input, $entityTypeId): array + { + return [ + 'search_weight' => $this->_getValue($input, 'search_weight', 1), + ]; + } +} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Setup/PropertyMapperTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Setup/PropertyMapperTest.php new file mode 100644 index 0000000000000..5c917b360f147 --- /dev/null +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Setup/PropertyMapperTest.php @@ -0,0 +1,65 @@ +<?php +declare(strict_types=1); + +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\CatalogSearch\Test\Unit\Model\ResourceModel\Setup; + +use Magento\CatalogSearch\Model\ResourceModel\Setup\PropertyMapper; +use PHPUnit\Framework\TestCase; + +/** + * Class PropertyMapperTest + * + * @package Magento\CatalogSearch\Test\Unit\Model\ResourceModel\Setup + */ +class PropertyMapperTest extends TestCase +{ + /** + * @var PropertyMapper + */ + private $propertyMapper; + + /** + * @return void + */ + protected function setUp(): void + { + $this->propertyMapper = new PropertyMapper(); + } + + /** + * @return array + */ + public function caseProvider(): array + { + return [ + [ + ['search_weight' => 9, 'something_other' => '3'], + ['search_weight' => 9] + ], + [ + ['something' => 3], + ['search_weight' => 1] + ] + ]; + } + + /** + * @dataProvider caseProvider + * + * @test + * + * @param array $input + * @param array $result + * @return void + */ + public function testMapCorrectlyMapsValue(array $input, array $result): void + { + //Second parameter doesn't matter as it is not used + $this->assertSame($result, $this->propertyMapper->map($input, 4)); + } +} diff --git a/app/code/Magento/CatalogSearch/etc/di.xml b/app/code/Magento/CatalogSearch/etc/di.xml index 5c80c92141727..7359bd6b454b9 100644 --- a/app/code/Magento/CatalogSearch/etc/di.xml +++ b/app/code/Magento/CatalogSearch/etc/di.xml @@ -364,4 +364,11 @@ <type name="Magento\Config\Model\Config"> <plugin name="config_enable_eav_indexer" type="Magento\CatalogSearch\Plugin\EnableEavIndexer" /> </type> + <type name="Magento\Eav\Model\Entity\Setup\PropertyMapper\Composite"> + <arguments> + <argument name="propertyMappers" xsi:type="array"> + <item name="catalog_search" xsi:type="string">Magento\CatalogSearch\Model\ResourceModel\Setup\PropertyMapper</item> + </argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php index cacc761dbee36..44b47faf3d4b8 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php @@ -13,6 +13,8 @@ use Magento\Store\Model\Store; use Magento\UrlRewrite\Model\UrlPersistInterface; use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; +use Magento\Store\Api\StoreWebsiteRelationInterface; +use Magento\Framework\App\ObjectManager; /** * Observer to assign the products to website @@ -39,22 +41,31 @@ class ProductToWebsiteChangeObserver implements ObserverInterface */ protected $request; + /** + * @var StoreWebsiteRelationInterface + */ + private $storeWebsiteRelation; + /** * @param ProductUrlRewriteGenerator $productUrlRewriteGenerator * @param UrlPersistInterface $urlPersist * @param ProductRepositoryInterface $productRepository * @param RequestInterface $request + * @param StoreWebsiteRelationInterface $storeWebsiteRelation */ public function __construct( ProductUrlRewriteGenerator $productUrlRewriteGenerator, UrlPersistInterface $urlPersist, ProductRepositoryInterface $productRepository, - RequestInterface $request + RequestInterface $request, + StoreWebsiteRelationInterface $storeWebsiteRelation = null ) { $this->productUrlRewriteGenerator = $productUrlRewriteGenerator; $this->urlPersist = $urlPersist; $this->productRepository = $productRepository; $this->request = $request; + $this->storeWebsiteRelation = $storeWebsiteRelation ?: + ObjectManager::getInstance()->get(StoreWebsiteRelationInterface::class); } /** @@ -73,10 +84,17 @@ public function execute(\Magento\Framework\Event\Observer $observer) ); if (!empty($this->productUrlRewriteGenerator->generate($product))) { - $this->urlPersist->deleteByData([ - UrlRewrite::ENTITY_ID => $product->getId(), - UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE, - ]); + if ($this->request->getParam('remove_website_ids')) { + foreach ($this->request->getParam('remove_website_ids') as $webId) { + foreach ($this->storeWebsiteRelation->getStoreByWebsiteId($webId) as $storeId) { + $this->urlPersist->deleteByData([ + UrlRewrite::ENTITY_ID => $product->getId(), + UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE, + UrlRewrite::STORE_ID => $storeId + ]); + } + } + } if ($product->getVisibility() != Visibility::VISIBILITY_NOT_VISIBLE) { $this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product)); } diff --git a/app/code/Magento/Checkout/Block/Cart/Totals.php b/app/code/Magento/Checkout/Block/Cart/Totals.php index 375c564f29059..7ac5c1c149cc6 100644 --- a/app/code/Magento/Checkout/Block/Cart/Totals.php +++ b/app/code/Magento/Checkout/Block/Cart/Totals.php @@ -3,12 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Checkout\Block\Cart; use Magento\Framework\View\Element\BlockInterface; use Magento\Checkout\Block\Checkout\LayoutProcessorInterface; /** + * Totals cart block. + * * @api */ class Totals extends \Magento\Checkout\Block\Cart\AbstractCart @@ -62,6 +65,8 @@ public function __construct( } /** + * Retrieve encoded js layout. + * * @return string */ public function getJsLayout() @@ -74,6 +79,8 @@ public function getJsLayout() } /** + * Retrieve totals from cache. + * * @return array */ public function getTotals() @@ -85,6 +92,8 @@ public function getTotals() } /** + * Set totals to cache. + * * @param array $value * @return $this * @codeCoverageIgnore @@ -96,6 +105,8 @@ public function setTotals($value) } /** + * Create totals block and set totals. + * * @param string $code * @return BlockInterface */ @@ -121,6 +132,8 @@ protected function _getTotalRenderer($code) } /** + * Get totals html. + * * @param mixed $total * @param int|null $area * @param int $colspan @@ -177,7 +190,7 @@ public function needDisplayBaseGrandtotal() } /** - * Get formated in base currency base grand total value + * Get formatted in base currency base grand total value * * @return string */ diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontMiniCartActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontMiniCartActionGroup.xml index 7a5c5e1d15872..e4a388d2c3a58 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontMiniCartActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontMiniCartActionGroup.xml @@ -35,4 +35,11 @@ <click selector="{{StoreFrontRemoveItemModalSection.ok}}" stepKey="confirmDelete"/> <waitForPageLoad stepKey="waitForDeleteToFinish"/> </actionGroup> + + <!--Check that the minicart is empty--> + <actionGroup name="assertMiniCartEmpty"> + <dontSeeElement selector="{{StorefrontMinicartSection.productCount}}" stepKey="dontSeeMinicartProductCount"/> + <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="expandMinicart"/> + <see selector="{{StorefrontMinicartSection.minicartContent}}" userInput="You have no items in your shopping cart." stepKey="seeEmptyCartMessage"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/shopping-cart.js b/app/code/Magento/Checkout/view/frontend/web/js/shopping-cart.js index 3ea49cd981d90..eecfa65b189d1 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/shopping-cart.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/shopping-cart.js @@ -14,7 +14,11 @@ define([ _create: function () { var items, i, reload; - $(this.options.emptyCartButton).on('click', $.proxy(function () { + $(this.options.emptyCartButton).on('click', $.proxy(function (event) { + if (event.detail === 0) { + return; + } + $(this.options.emptyCartButton).attr('name', 'update_cart_action_temp'); $(this.options.updateCartActionContainer) .attr('name', 'update_cart_action').attr('value', 'empty_cart'); diff --git a/app/code/Magento/Config/Model/Config.php b/app/code/Magento/Config/Model/Config.php index bec44e9d55757..6bf191c20a844 100644 --- a/app/code/Magento/Config/Model/Config.php +++ b/app/code/Magento/Config/Model/Config.php @@ -525,24 +525,29 @@ public function setDataByPath($path, $value) if ($path === '') { throw new \UnexpectedValueException('Path must not be empty'); } + $pathParts = explode('/', $path); $keyDepth = count($pathParts); - if ($keyDepth !== 3) { + if ($keyDepth < 3) { throw new \UnexpectedValueException( - "Allowed depth of configuration is 3 (<section>/<group>/<field>). Your configuration depth is " - . $keyDepth . " for path '$path'" + 'Minimal depth of configuration is 3. Your configuration depth is ' . $keyDepth ); } + + $section = array_shift($pathParts); $data = [ - 'section' => $pathParts[0], - 'groups' => [ - $pathParts[1] => [ - 'fields' => [ - $pathParts[2] => ['value' => $value], - ], - ], + 'fields' => [ + array_pop($pathParts) => ['value' => $value], ], ]; + while ($pathParts) { + $data = [ + 'groups' => [ + array_pop($pathParts) => $data, + ], + ]; + } + $data['section'] = $section; $this->addData($data); } diff --git a/app/code/Magento/Config/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Config/Test/Unit/Model/ConfigTest.php index bdcb44b756bb2..66163e354cc06 100644 --- a/app/code/Magento/Config/Test/Unit/Model/ConfigTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/ConfigTest.php @@ -330,22 +330,59 @@ public function testSaveToCheckScopeDataSet() $this->model->save(); } - public function testSetDataByPath() + /** + * @param string $path + * @param string $value + * @param string $section + * @param array $groups + * @dataProvider setDataByPathDataProvider + */ + public function testSetDataByPath(string $path, string $value, string $section, array $groups) { - $value = 'value'; - $path = '<section>/<group>/<field>'; $this->model->setDataByPath($path, $value); - $expected = [ - 'section' => '<section>', - 'groups' => [ - '<group>' => [ - 'fields' => [ - '<field>' => ['value' => $value], + $this->assertEquals($section, $this->model->getData('section')); + $this->assertEquals($groups, $this->model->getData('groups')); + } + + /** + * @return array + */ + public function setDataByPathDataProvider(): array + { + return [ + 'depth 3' => [ + 'a/b/c', + 'value1', + 'a', + [ + 'b' => [ + 'fields' => [ + 'c' => ['value' => 'value1'], + ], + ], + ], + ], + 'depth 5' => [ + 'a/b/c/d/e', + 'value1', + 'a', + [ + 'b' => [ + 'groups' => [ + 'c' => [ + 'groups' => [ + 'd' => [ + 'fields' => [ + 'e' => ['value' => 'value1'], + ], + ], + ], + ], + ], ], ], ], ]; - $this->assertSame($expected, $this->model->getData()); } /** @@ -359,14 +396,13 @@ public function testSetDataByPathEmpty() /** * @param string $path - * @param string $expectedException - * * @dataProvider setDataByPathWrongDepthDataProvider */ - public function testSetDataByPathWrongDepth($path, $expectedException) + public function testSetDataByPathWrongDepth(string $path) { - $expectedException = 'Allowed depth of configuration is 3 (<section>/<group>/<field>). ' . $expectedException; - $this->expectException('\UnexpectedValueException'); + $currentDepth = count(explode('/', $path)); + $expectedException = 'Minimal depth of configuration is 3. Your configuration depth is ' . $currentDepth; + $this->expectException(\UnexpectedValueException::class); $this->expectExceptionMessage($expectedException); $value = 'value'; $this->model->setDataByPath($path, $value); @@ -375,13 +411,11 @@ public function testSetDataByPathWrongDepth($path, $expectedException) /** * @return array */ - public function setDataByPathWrongDepthDataProvider() + public function setDataByPathWrongDepthDataProvider(): array { return [ - 'depth 2' => ['section/group', "Your configuration depth is 2 for path 'section/group'"], - 'depth 1' => ['section', "Your configuration depth is 1 for path 'section'"], - 'depth 4' => ['section/group/field/sub-field', "Your configuration depth is 4 for path" - . " 'section/group/field/sub-field'", ], + 'depth 2' => ['section/group'], + 'depth 1' => ['section'], ]; } } diff --git a/app/code/Magento/ConfigurableImportExport/etc/module.xml b/app/code/Magento/ConfigurableImportExport/etc/module.xml index 7ff81f8d63443..b59234ca0e7da 100644 --- a/app/code/Magento/ConfigurableImportExport/etc/module.xml +++ b/app/code/Magento/ConfigurableImportExport/etc/module.xml @@ -6,6 +6,9 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_ConfigurableImportExport" > + <module name="Magento_ConfigurableImportExport"> + <sequence> + <module name="Magento_ConfigurableProduct"/> + </sequence> </module> </config> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminConfigurableProductActionGroup.xml index d6e7221ec1cab..95b86ec3a8587 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminConfigurableProductActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminConfigurableProductActionGroup.xml @@ -156,4 +156,124 @@ <click selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" stepKey="clickOnConfirmInPopup"/> <seeElement selector="{{AdminProductMessagesSection.successMessage}}" stepKey="seeSaveProductMessage"/> </actionGroup> + + <actionGroup name="addNewProductConfigurationAttribute"> + <arguments> + <argument name="attribute" type="entity"/> + <argument name="firstOption" type="entity"/> + <argument name="secondOption" type="entity"/> + </arguments> + <!-- Create new attribute --> + <click selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" stepKey="clickOnNewAttribute"/> + <waitForPageLoad stepKey="waitForIFrame"/> + <switchToIFrame selector="{{AdminNewAttributePanel.newAttributeIFrame}}" stepKey="switchToNewAttributeIFrame"/> + <fillField selector="{{AdminNewAttributePanel.defaultLabel}}" userInput="{{attribute.default_label}}" stepKey="fillDefaultLabel"/> + <click selector="{{AdminNewAttributePanel.saveAttribute}}" stepKey="clickOnNewAttributePanel"/> + <waitForPageLoad stepKey="waitForSaveAttribute"/> + <switchToIFrame stepKey="switchOutOfIFrame"/> + <waitForPageLoad stepKey="waitForFilters"/> + <!-- Find created below attribute and add option; save attribute --> + <click selector="{{AdminCreateProductConfigurationsPanel.filters}}" stepKey="clickOnFilters"/> + <fillField userInput="{{attribute.default_label}}" selector="{{AdminCreateProductConfigurationsPanel.attributeCode}}" stepKey="fillFilterAttributeCodeField"/> + <click selector="{{AdminCreateProductConfigurationsPanel.applyFilters}}" stepKey="clickApplyFiltersButton"/> + <click selector="{{AdminCreateProductConfigurationsPanel.firstCheckbox}}" stepKey="clickOnFirstCheckbox"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton"/> + <click selector="{{AdminCreateProductConfigurationsPanel.createNewValue}}" stepKey="clickOnCreateFirstNewValue"/> + <fillField userInput="{{firstOption.name}}" selector="{{AdminCreateProductConfigurationsPanel.attributeName}}" stepKey="fillFieldForNewFirstOption"/> + <click selector="{{AdminCreateProductConfigurationsPanel.saveAttribute}}" stepKey="clickOnSaveNewAttribute"/> + <click selector="{{AdminCreateProductConfigurationsPanel.createNewValue}}" stepKey="clickOnCreateSecondNewValue"/> + <fillField userInput="{{secondOption.name}}" selector="{{AdminCreateProductConfigurationsPanel.attributeName}}" stepKey="fillFieldForNewSecondOption"/> + <click selector="{{AdminCreateProductConfigurationsPanel.saveAttribute}}" stepKey="clickOnSaveAttribute"/> + <click selector="{{AdminCreateProductConfigurationsPanel.selectAll}}" stepKey="clickOnSelectAll"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnSecondNextButton"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnThirdNextButton"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnFourthNextButton"/> + </actionGroup> + + <actionGroup name="changeProductConfigurationsInGrid"> + <arguments> + <argument name="firstOption" type="entity"/> + <argument name="secondOption" type="entity"/> + </arguments> + <fillField userInput="{{firstOption.name}}" selector="{{AdminProductFormConfigurationsSection.confProductNameCell(firstOption.name)}}" stepKey="fillFieldNameForFirstAttributeOption"/> + <fillField userInput="{{secondOption.name}}" selector="{{AdminProductFormConfigurationsSection.confProductNameCell(secondOption.name)}}" stepKey="fillFieldNameForSecondAttributeOption"/> + <fillField userInput="{{firstOption.sku}}" selector="{{AdminProductFormConfigurationsSection.confProductSkuCell(firstOption.name)}}" stepKey="fillFieldSkuForFirstAttributeOption"/> + <fillField userInput="{{secondOption.sku}}" selector="{{AdminProductFormConfigurationsSection.confProductSkuCell(secondOption.name)}}" stepKey="fillFieldSkuForSecondAttributeOption"/> + <fillField userInput="{{firstOption.price}}" selector="{{AdminProductFormConfigurationsSection.confProductPriceCell(firstOption.name)}}" stepKey="fillFieldPriceForFirstAttributeOption"/> + <fillField userInput="{{secondOption.price}}" selector="{{AdminProductFormConfigurationsSection.confProductPriceCell(secondOption.name)}}" stepKey="fillFieldPriceForSecondAttributeOption"/> + <fillField userInput="{{firstOption.quantity}}" selector="{{AdminProductFormConfigurationsSection.confProductQuantityCell(firstOption.name)}}" stepKey="fillFieldQuantityForFirstAttributeOption"/> + <fillField userInput="{{secondOption.quantity}}" selector="{{AdminProductFormConfigurationsSection.confProductQuantityCell(secondOption.name)}}" stepKey="fillFieldQuantityForSecondAttributeOption"/> + <fillField userInput="{{firstOption.weight}}" selector="{{AdminProductFormConfigurationsSection.confProductWeightCell(firstOption.name)}}" stepKey="fillFieldWeightForFirstAttributeOption"/> + <fillField userInput="{{secondOption.weight}}" selector="{{AdminProductFormConfigurationsSection.confProductWeightCell(secondOption.name)}}" stepKey="fillFieldWeightForSecondAttributeOption"/> + </actionGroup> + + <actionGroup name="changeProductConfigurationsInGridExceptSku" extends="changeProductConfigurationsInGrid"> + <remove keyForRemoval="fillFieldSkuForFirstAttributeOption"/> + <remove keyForRemoval="fillFieldSkuForSecondAttributeOption"/> + </actionGroup> + + <actionGroup name="addProductToConfigurationsGrid"> + <arguments> + <argument name="sku" type="string"/> + <argument name="name" type="string"/> + </arguments> + <click selector="{{AdminProductFormConfigurationsSection.actionsBtnByProductName(name)}}" stepKey="clickToExpandFirstActions"/> + <click selector="{{AdminProductFormConfigurationsSection.addProduct(name)}}" stepKey="clickChooseFirstDifferentProduct"/> + <switchToIFrame stepKey="switchOutOfIFrame"/> + <waitForPageLoad stepKey="waitForFilters"/> + <click selector="{{AdminCreateProductConfigurationsPanel.filters}}" stepKey="clickFilters"/> + <fillField selector="{{AdminProductGridFilterSection.skuFilter}}" userInput="{{sku}}" stepKey="fillProductSkuFilter"/> + <click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="clickApplyFilters"/> + <click selector="{{AdminProductGridFilterSection.firstRowBySku(sku)}}" stepKey="clickOnFirstRow"/> + </actionGroup> + + <actionGroup name="addUniqueImageToConfigurableProductOption"> + <arguments> + <argument name="image" defaultValue="ProductImage"/> + <argument name="frontend_label" type="string"/> + <argument name="label" type="string"/> + </arguments> + <click selector="{{AdminCreateProductConfigurationsPanel.applyUniqueImagesToEachSkus}}" stepKey="clickOnApplyUniqueImagesToEachSku"/> + <selectOption userInput="{{frontend_label}}" selector="{{AdminCreateProductConfigurationsPanel.selectImagesButton}}" stepKey="selectOption"/> + <attachFile selector="{{AdminCreateProductConfigurationsPanel.uploadImagesButton(label)}}" userInput="{{image.file}}" stepKey="uploadFile"/> + <waitForElementNotVisible selector="{{AdminCreateProductConfigurationsPanel.uploadProgressBar}}" stepKey="waitForUpload"/> + <waitForElementVisible selector="{{AdminCreateProductConfigurationsPanel.imageFile(image.fileName)}}" stepKey="waitForThumbnail"/> + </actionGroup> + + <actionGroup name="addUniquePriceToConfigurableProductOption"> + <arguments> + <argument name="frontend_label" type="string"/> + <argument name="label" type="string"/> + <argument name="price" type="string"/> + </arguments> + <click selector="{{AdminCreateProductConfigurationsPanel.applyUniquePricesToEachSkus}}" stepKey="clickOnApplyUniquePricesToEachSku"/> + <selectOption userInput="{{frontend_label}}" selector="{{AdminCreateProductConfigurationsPanel.selectPriceButton}}" stepKey="selectOption"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.price(label)}}" userInput="{{price}}" stepKey="enterAttributeQuantity"/> + </actionGroup> + + <actionGroup name="saveConfigurableProductWithNewAttributeSet"> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickSaveConfigurableProduct"/> + <waitForElementVisible selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" time="30" stepKey="waitForAttributeSetConfirmation"/> + <click selector="{{AdminChooseAffectedAttributeSetPopup.addNewAttrSet}}" stepKey="clickAddNewAttributeSet"/> + <fillField selector="{{AdminChooseAffectedAttributeSetPopup.createNewAttrSetName}}" userInput="{{ProductAttributeFrontendLabel.label}}" stepKey="fillFieldNewAttrSetName"/> + <click selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" stepKey="clickConfirmAttributeSet"/> + <see selector="You saved the product" stepKey="seeConfigurableSaveConfirmation" after="clickConfirmAttributeSet"/> + </actionGroup> + + <actionGroup name="saveConfigurableProductAddToCurrentAttributeSet"> + <waitForElementVisible selector="{{AdminProductFormActionSection.saveButton}}" stepKey="waitForSaveBtnVisible"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProductAgain"/> + <waitForElementVisible selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" stepKey="waitPopUpVisible"/> + <click selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" stepKey="clickOnConfirmPopup"/> + <seeElement selector="{{AdminMessagesSection.success}}" stepKey="seeSaveProductMessage"/> + </actionGroup> + + <actionGroup name="assertConfigurableProductOnAdminProductPage"> + <arguments> + <argument name="product" type="entity"/> + </arguments> + <seeInField userInput="{{ApiConfigurableProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="seeNameRequired"/> + <seeInField userInput="{{ApiConfigurableProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="seeSkuRequired"/> + <dontSeeInField userInput="{{ApiConfigurableProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="dontSeePriceRequired"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml index 39c206e365a2d..e2759fc0fd23d 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml @@ -21,4 +21,15 @@ <!-- @TODO: MAGETWO-80272 Move to Magento_Checkout --> <seeElement selector="{{StorefrontCategoryProductSection.ProductAddToCartByName(product.name)}}" stepKey="AssertAddToCart" /> </actionGroup> + + <!-- Check configurable product out of stock on the category page --> + <actionGroup name="StorefrontCheckCategoryOutOfStockConfigurableProduct"> + <arguments> + <argument name="product" type="entity"/> + </arguments> + <seeElement selector="{{StorefrontCategoryProductSection.ProductTitleByName(product.name)}}" stepKey="assertProductName"/> + <moveMouseOver selector="{{StorefrontCategoryProductSection.ProductInfoByName(product.name)}}" stepKey="moveMouseOverProduct" /> + <seeElement selector="{{StorefrontCategoryProductSection.ProductStockUnavailable}}" stepKey="AssertOutOfStock"/> + <dontSeeElement selector="{{StorefrontCategoryProductSection.ProductAddToCartByName(product.name)}}" stepKey="AssertAddToCart" /> + </actionGroup> </actionGroups> \ No newline at end of file diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontProductActionGroup.xml index 9be600c239c79..51bb041b66089 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontProductActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontProductActionGroup.xml @@ -33,4 +33,49 @@ </arguments> <seeElement selector="{{StorefrontProductInfoMainSection.attributeOptionByAttributeID(attributeCode, optionName)}}" stepKey="verifyOptionExists"/> </actionGroup> + + <!-- Verify configurable product options in storefront product view --> + <actionGroup name="storefrontCheckConfigurableProductOptions"> + <arguments> + <argument name="product" type="entity"/> + <argument name="firstOption" type="entity"/> + <argument name="secondOption" type="entity"/> + </arguments> + <selectOption userInput="{{firstOption.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOption1"/> + <see userInput="{{product.name}}" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="seeConfigurableProductName"/> + <see userInput="{{firstOption.price}}" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="assertProductPricePresent"/> + <see userInput="{{product.sku}}" selector="{{StorefrontProductInfoMainSection.productSku}}" stepKey="seeConfigurableProductSku"/> + <see userInput="IN STOCK" selector="{{StorefrontProductInfoMainSection.productStockStatus}}" stepKey="assertInStock"/> + <see userInput="{{colorProductAttribute.default_label}}" selector="{{StorefrontProductInfoMainSection.productAttributeTitle1}}" stepKey="seeColorAttributeName"/> + <dontSee userInput="As low as" selector="{{StorefrontProductInfoMainSection.productPriceLabel}}" stepKey="dontSeeProductPriceLabel1"/> + <selectOption userInput="{{secondOption.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOption2"/> + <dontSee userInput="As low as" selector="{{StorefrontProductInfoMainSection.productPriceLabel}}" stepKey="dontSeeProductPriceLabel2"/> + <see userInput="{{secondOption.price}}" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="seeProductPrice2"/> + </actionGroup> + + <!-- Assert option image in storefront product page --> + <actionGroup name="assertOptionImageInStorefrontProductPage"> + <arguments> + <argument name="product" type="entity"/> + <argument name="label" type="string"/> + <argument name="image" defaultValue="MagentoLogo"/> + </arguments> + <seeInCurrentUrl url="/{{product.urlKey}}.html" stepKey="checkUrl"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <selectOption userInput="{{label}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOption1"/> + <seeElement selector="{{StorefrontProductMediaSection.imageFile(image.filename)}}" stepKey="seeFirstImage"/> + </actionGroup> + + <!-- Assert configurable product with special price in storefront product page --> + <actionGroup name="assertConfigurableProductWithSpecialPriceOnStorefrontProductPage"> + <arguments> + <argument name="option" type="string"/> + <argument name="price" type="string"/> + <argument name="specialPrice" defaultValue="specialProductPrice"/> + </arguments> + <selectOption userInput="{{option}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOptionWithSpecialPrice"/> + <see userInput="{{specialProductPrice.price}}" selector="{{StorefrontProductInfoMainSection.productSpecialPrice}}" stepKey="seeSpecialProductPrice"/> + <see userInput="Regular Price" selector="{{StorefrontProductInfoMainSection.specialProductText}}" stepKey="seeText"/> + <see userInput="{{price}}" selector="{{StorefrontProductInfoMainSection.oldProductPrice}}" stepKey="seeOldProductPrice"/> + </actionGroup> </actionGroups> \ No newline at end of file diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml new file mode 100644 index 0000000000000..f3b0786236062 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml @@ -0,0 +1,14 @@ +<?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="VerifyProductTypeOrder"> + <seeElement stepKey="seeConfigurableInOrder" selector="{{AdminProductDropdownOrderSection.configurableProduct}}"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ProductConfigurableAttributeData.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ProductConfigurableAttributeData.xml index 9342172f7d4df..4c5f83ecebecf 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ProductConfigurableAttributeData.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ProductConfigurableAttributeData.xml @@ -42,4 +42,22 @@ <data key="name">Black</data> <data key="price">5.00</data> </entity> + <entity name="colorConfigurableProductAttribute1" type="product_attribute"> + <data key="name" unique="suffix">Green</data> + <data key="sku" unique="suffix">sku-green</data> + <data key="type_id">simple</data> + <data key="price">1</data> + <data key="visibility">1</data> + <data key="quantity">1</data> + <data key="weight">1</data> + </entity> + <entity name="colorConfigurableProductAttribute2" type="product_attribute"> + <data key="name" unique="suffix">Red</data> + <data key="sku" unique="suffix">sku-red</data> + <data key="type_id">simple</data> + <data key="price">2</data> + <data key="visibility">1</data> + <data key="quantity">10</data> + <data key="weight">1</data> + </entity> </entities> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminChooseAffectedAttributeSetSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminChooseAffectedAttributeSetSection.xml index 6e8303e6baead..78e4c7bced8e2 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminChooseAffectedAttributeSetSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminChooseAffectedAttributeSetSection.xml @@ -10,6 +10,8 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminChooseAffectedAttributeSetPopup"> <element name="confirm" type="button" selector="button[data-index='confirm_button']" timeout="30"/> + <element name="addNewAttrSet" type="radio" selector="//input[@data-index='affectedAttributeSetNew']" timeout="30"/> + <element name="createNewAttrSetName" type="input" selector="//input[@name='configurableNewAttributeSetName']" timeout="30"/> <element name="closePopUp" type="button" selector="//*[contains(@class,'product_form_product_form_configurable_attribute_set')]//button[@data-role='closeBtn']" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminCreateProductConfigurationsPanelSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminCreateProductConfigurationsPanelSection.xml index 9b4798c95ec72..eccff2830d2a5 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminCreateProductConfigurationsPanelSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminCreateProductConfigurationsPanelSection.xml @@ -35,9 +35,18 @@ <element name="attribute3" type="input" selector="#apply-single-price-input-2"/> <element name="applySingleQuantityToEachSkus" type="radio" selector=".admin__field-label[for='apply-single-inventory-radio']" timeout="30"/> + <element name="applyUniqueImagesToEachSkus" type="radio" selector=".admin__field-label[for='apply-unique-images-radio']" timeout="30"/> + <element name="applyUniquePricesToEachSkus" type="radio" selector=".admin__field-label[for='apply-unique-prices-radio']" timeout="30"/> + <element name="selectImagesButton" type="select" selector="#apply-images-attributes" timeout="30"/> + <element name="uploadImagesButton" type="file" selector="//*[text()='{{option}}']/../../div[@data-role='gallery']//input[@type='file']" timeout="30" parameterized="true"/> + <element name="uploadProgressBar" type="text" selector=".uploader .file-row"/> + <element name="imageFile" type="text" selector="//*[@data-role='gallery']//img[contains(@src, '{{url}}')]" parameterized="true"/> + <element name="selectPriceButton" type="select" selector="#select-each-price" timeout="30"/> + <element name="price" type="input" selector="//*[text()='{{option}}']/../..//input[contains(@id, 'apply-single-price-input')]" parameterized="true"/> <element name="quantity" type="input" selector="#apply-single-inventory-input"/> <element name="gridLoadingMask" type="text" selector="[data-role='spinner'][data-component*='product_attributes_listing']"/> <element name="attributeCheckboxByName" type="input" selector="//*[contains(@data-attribute-option-title,'{{arg}}')]//input[@type='checkbox']" parameterized="true"/> <element name="attributeColorCheckbox" type="select" selector="//div[contains(text(),'color') and @class='data-grid-cell-content']/../preceding-sibling::td/label/input"/> + <element name="attributeRowByAttributeCode" type="block" selector="//td[count(../../..//th[./*[.='Attribute Code']]/preceding-sibling::th) + 1][./*[.='{{attribute_code}}']]/../td//input[@data-action='select-row']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminProductDropdownOrderSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminProductDropdownOrderSection.xml new file mode 100644 index 0000000000000..6056e7f3cbd09 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminProductDropdownOrderSection.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="AdminProductDropdownOrderSection"> + <element name="configurableProduct" type="text" selector="//li[not(preceding-sibling::li[span[@title='Virtual Product']]) and not(preceding-sibling::li[span[@title='Grouped Product']]) and not(preceding-sibling::li[span[@title='Bundle Product']]) and not(preceding-sibling::li[span[@title='Downloadable Product']]) and not(following-sibling::li[span[@title='Simple Product']])]/span[@title='Configurable Product']"/> + </section> +</sections> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminProductFormConfigurationsSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminProductFormConfigurationsSection.xml index 73ae71adfaaf0..d1b16cb8f5ce3 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminProductFormConfigurationsSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminProductFormConfigurationsSection.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminProductFormConfigurationsSection"> <element name="sectionHeader" type="text" selector=".admin__collapsible-block-wrapper[data-index='configurable']"/> + <element name="createdConfigurationsBlock" type="text" selector="div.admin__field.admin__field-wide"/> <element name="createConfigurations" type="button" selector="button[data-index='create_configurable_products_button']" timeout="30"/> <element name="currentVariationsRows" type="button" selector=".data-row"/> <element name="currentVariationsNameCells" type="textarea" selector=".admin__control-fields[data-index='name_container']"/> @@ -20,10 +21,17 @@ <element name="currentVariationsStatusCells" type="textarea" selector="._no-header[data-index='status']"/> <element name="firstSKUInConfigurableProductsGrid" type="input" selector="//input[@name='configurable-matrix[0][sku]']"/> <element name="actionsBtn" type="button" selector="(//button[@class='action-select']/span[contains(text(), 'Select')])[{{var1}}]" parameterized="true"/> + <element name="actionsBtnByProductName" type="textarea" selector="//*[.='Attributes']/ancestor::tr/td[@data-index='attributes']//span[contains(text(), '{{var}}')]/ancestor::tr//button[@class='action-select']" parameterized="true"/> + <element name="addProduct" type="button" selector="//*[.='Attributes']/ancestor::tr/td[@data-index='attributes']//span[contains(text(), '{{var}}')]/ancestor::tr//a[text()='Choose a different Product']" parameterized="true"/> <element name="removeProductBtn" type="button" selector="//a[text()='Remove Product']"/> <element name="disableProductBtn" type="button" selector="//a[text()='Disable Product']"/> <element name="enableProductBtn" type="button" selector="//a[text()='Enable Product']"/> <element name="confProductSku" type="input" selector="//*[@name='configurable-matrix[{{arg}}][sku]']" parameterized="true"/> + <element name="confProductNameCell" type="input" selector="//*[.='Attributes']/ancestor::tr//span[contains(text(), '{{var}}')]/ancestor::tr/td[@data-index='name_container']//input" parameterized="true"/> + <element name="confProductSkuCell" type="input" selector="//*[.='Attributes']/ancestor::tr//span[contains(text(), '{{var}}')]/ancestor::tr/td[@data-index='sku_container']//input" parameterized="true"/> + <element name="confProductPriceCell" type="input" selector="//*[.='Attributes']/ancestor::tr//span[contains(text(), '{{var}}')]/ancestor::tr/td[@data-index='price_container']//input" parameterized="true"/> + <element name="confProductQuantityCell" type="input" selector="//*[.='Attributes']/ancestor::tr//span[contains(text(), '{{var}}')]/ancestor::tr/td[@data-index='quantity_container']//input" parameterized="true"/> + <element name="confProductWeightCell" type="input" selector="//*[.='Attributes']/ancestor::tr//span[contains(text(), '{{var}}')]/ancestor::tr/td[@data-index='price_weight']//input" parameterized="true"/> <element name="confProductSkuMessage" type="text" selector="//*[@name='configurable-matrix[{{arg}}][sku]']/following-sibling::label" parameterized="true"/> <element name="variationsSkuInputByRow" selector="[data-index='configurable-matrix'] table > tbody > tr:nth-of-type({{row}}) input[name*='sku']" type="input" parameterized="true"/> <element name="variationsSkuInputErrorByRow" selector="[data-index='configurable-matrix'] table > tbody > tr:nth-of-type({{row}}) .admin__field-error" type="text" parameterized="true"/> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml index b64a52d7cea41..09de3cc302903 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -11,6 +11,7 @@ <section name="StorefrontProductInfoMainSection"> <element name="optionByAttributeId" type="input" selector="#attribute{{var1}}" parameterized="true"/> <element name="productAttributeTitle1" type="text" selector="#product-options-wrapper div[tabindex='0'] label"/> + <element name="productPrice" type="text" selector="div.price-box.price-final_price"/> <element name="productAttributeOptions1" type="select" selector="#product-options-wrapper div[tabindex='0'] option"/> <element name="productAttributeOptionsSelectButton" type="select" selector="#product-options-wrapper .super-attribute-select"/> <element name="productAttributeOptionsError" type="text" selector="//div[@class='mage-error']"/> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminAssertNoticeThatExistingSkuAutomaticallyChangedWhenSavingProductWithSameSkuTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminAssertNoticeThatExistingSkuAutomaticallyChangedWhenSavingProductWithSameSkuTest.xml new file mode 100644 index 0000000000000..68bf703ecdab4 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminAssertNoticeThatExistingSkuAutomaticallyChangedWhenSavingProductWithSameSkuTest.xml @@ -0,0 +1,75 @@ +<?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="AdminAssertNoticeThatExistingSkuAutomaticallyChangedWhenSavingProductWithSameSkuTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Assert notice that existing sku automatically changed when saving product with same sku"/> + <description value="Admin should not be able to create configurable product and two new options with the same sku"/> + <testCaseId value="MC-13693"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Delete configurable product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Delete product attribute --> + <actionGroup ref="deleteProductAttributeByLabel" stepKey="deleteProductAttribute"> + <argument name="ProductAttribute" value="colorProductAttribute"/> + </actionGroup> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Fill configurable product values --> + <actionGroup ref="fillMainProductForm" stepKey="fillConfigurableProductValues"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!--Create product configurations--> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations" after="fillConfigurableProductValues"/> + <waitForElementVisible selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" time="30" stepKey="waitForConfigurationModalOpen" after="clickCreateConfigurations"/> + + <!--Create new attribute with two option --> + <actionGroup ref="addNewProductConfigurationAttribute" stepKey="createProductConfigurationAttribute"> + <argument name="attribute" value="colorProductAttribute"/> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Change products sku configurations in grid --> + <fillField userInput="{{ApiConfigurableProduct.sku}}" selector="{{AdminProductFormConfigurationsSection.confProductSkuCell(colorConfigurableProductAttribute1.name)}}" stepKey="fillFieldSkuForFirstAttributeOption"/> + <fillField userInput="{{ApiConfigurableProduct.sku}}" selector="{{AdminProductFormConfigurationsSection.confProductSkuCell(colorConfigurableProductAttribute2.name)}}" stepKey="fillFieldSkuForSecondAttributeOption"/> + + <!-- Save product --> + <waitForElementVisible selector="{{AdminProductFormActionSection.saveButton}}" stepKey="waitForSaveBtnVisible"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProductAgain"/> + <waitForElementVisible selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" stepKey="waitPopUpVisible"/> + <click selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" stepKey="clickOnConfirmPopup"/> + + <!-- Assert product auto incremented sku notice message; see success message --> + <see selector="{{AdminMessagesSection.noticeMessage}}" stepKey="seeNoticeMessage" userInput="SKU for product {{ApiConfigurableProduct.name}} has been changed to {{ApiConfigurableProduct.sku}}-2."/> + <see selector="{{AdminMessagesSection.successMessage}}" stepKey="seeSuccessMessage" userInput="You saved the product."/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductBasedOnParentSkuTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductBasedOnParentSkuTest.xml new file mode 100644 index 0000000000000..f4f607e9119b6 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductBasedOnParentSkuTest.xml @@ -0,0 +1,82 @@ +<?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="AdminCreateConfigurableProductBasedOnParentSkuTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Configurable product variation's sku should be based on parent SKU"/> + <description value="Admin should be able to create configurable product with two new options based on parent SKU, without assigned to category and attribute set"/> + <testCaseId value="MC-13689"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Delete configurable product with children products --> + <actionGroup ref="deleteProductBySku" stepKey="deleteProducts"> + <argument name="sku" value="{{ApiConfigurableProduct.sku}}"/> + </actionGroup> + + <!-- Delete product attribute --> + <actionGroup ref="deleteProductAttributeByLabel" stepKey="deleteProductAttribute"> + <argument name="ProductAttribute" value="colorProductAttribute"/> + </actionGroup> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Fill configurable product values --> + <actionGroup ref="fillMainProductForm" stepKey="fillConfigurableProductValues"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!--Create product configurations--> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations" after="fillConfigurableProductValues"/> + <waitForElementVisible selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" time="30" stepKey="waitForConfigurationModalOpen" after="clickCreateConfigurations"/> + + <!--Create new attribute with two option --> + <actionGroup ref="addNewProductConfigurationAttribute" stepKey="createProductConfigurationAttribute"> + <argument name="attribute" value="colorProductAttribute"/> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Change product configurations except sku --> + <actionGroup ref="changeProductConfigurationsInGridExceptSku" stepKey="changeProductConfigurationsInGridExceptSku"> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Save product --> + <actionGroup ref="saveConfigurableProductAddToCurrentAttributeSet" stepKey="saveProduct"/> + + <!-- Assert child products generated sku in grid --> + <amOnPage url="{{ProductCatalogPage.url}}" stepKey="openProductCatalogPage"/> + <waitForPageLoad stepKey="waitForProductCatalogPageLoad"/> + <actionGroup ref="filterProductGridByName2" stepKey="filterFirstProductByNameInGrid"> + <argument name="name" value="{{colorConfigurableProductAttribute1.name}}"/> + </actionGroup> + <see selector="{{AdminProductGridSection.productGridCell('1', 'SKU')}}" userInput="{{ApiConfigurableProduct.sku}}-{{colorConfigurableProductAttribute1.name}}" stepKey="seeFirstProductSkuInGrid"/> + <actionGroup ref="filterProductGridByName2" stepKey="filterSecondProductByNameInGrid"> + <argument name="name" value="{{colorConfigurableProductAttribute2.name}}"/> + </actionGroup> + <see selector="{{AdminProductGridSection.productGridCell('1', 'SKU')}}" userInput="{{ApiConfigurableProduct.sku}}-{{colorConfigurableProductAttribute2.name}}" stepKey="seeSecondProductSkuInGrid"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithCreatingCategoryAndAttributeTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithCreatingCategoryAndAttributeTest.xml new file mode 100644 index 0000000000000..a7242b43c2b5f --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithCreatingCategoryAndAttributeTest.xml @@ -0,0 +1,124 @@ +<?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="AdminCreateConfigurableProductWithCreatingCategoryAndAttributeTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Create configurable product with creating new category and new attribute (required fields only)"/> + <description value="Admin should be able to create configurable product with creating new category and new attribute (required fields only)"/> + <testCaseId value="MC-13687"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Delete configurable product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Delete children products --> + <actionGroup ref="deleteProductBySku" stepKey="deleteFirstChildProduct"> + <argument name="sku" value="{{colorConfigurableProductAttribute1.sku}}"/> + </actionGroup> + <actionGroup ref="deleteProductBySku" stepKey="deleteSecondChildProduct"> + <argument name="sku" value="{{colorConfigurableProductAttribute2.sku}}"/> + </actionGroup> + + <!-- Delete product attribute --> + <actionGroup ref="deleteProductAttributeByLabel" stepKey="deleteProductAttribute"> + <argument name="ProductAttribute" value="colorProductAttribute"/> + </actionGroup> + + <!-- Delete attribute set --> + <actionGroup ref="deleteAttributeSetByLabel" stepKey="deleteAttributeSet"> + <argument name="label" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + + <!-- Delete category --> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Fill configurable product required fields only--> + <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{ApiConfigurableProduct.name}}" stepKey="fillProductName"/> + <fillField selector="{{AdminProductFormSection.productSku}}" userInput="{{ApiConfigurableProduct.sku}}" stepKey="fillProductSku"/> + <fillField selector="{{AdminProductFormSection.productPrice}}" userInput="{{ApiConfigurableProduct.price}}" stepKey="fillProductPrice"/> + + <!-- Add configurable product in category --> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createCategory.name$$]" stepKey="fillCategory"/> + + <!--Create product configurations--> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations"/> + <waitForElementVisible selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" time="30" stepKey="waitForConfigurationModalOpen" after="clickCreateConfigurations"/> + + <!--Create new attribute with two option --> + <actionGroup ref="addNewProductConfigurationAttribute" stepKey="createProductConfigurationAttribute"> + <argument name="attribute" value="colorProductAttribute"/> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Change product configurations in grid --> + <actionGroup ref="changeProductConfigurationsInGrid" stepKey="changeProductConfigurationsInGrid"> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Save configurable product; add product to new attribute set --> + <actionGroup ref="saveConfigurableProductWithNewAttributeSet" stepKey="saveConfigurableProduct"/> + + <!-- Find configurable product in grid --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="visitAdminProductPage"/> + <waitForPageLoad stepKey="waitForAdminProductPageLoad"/> + <actionGroup ref="filterProductGridBySku" stepKey="findCreatedConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Assert configurable product on admin product page --> + <click selector="{{AdminProductGridSection.firstRow}}" stepKey="clickOnProductPage"/> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <actionGroup ref="assertConfigurableProductOnAdminProductPage" stepKey="assertConfigurableProductOnAdminProductPage"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Flash cache --> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + + <!--Assert configurable product in category --> + <amOnPage url="$$createCategory.name$$.html" stepKey="amOnCategoryPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="assertConfigurableProductInCategory"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="optionProduct" value="colorConfigurableProductAttribute1"/> + </actionGroup> + + <!--Assert configurable product on product page --> + <amOnPage url="{{ApiConfigurableProduct.urlKey}}.html" stepKey="amOnProductPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <actionGroup ref="storefrontCheckConfigurableProductOptions" stepKey="checkConfigurableProductOptions"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithDisabledChildrenProductsTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithDisabledChildrenProductsTest.xml new file mode 100644 index 0000000000000..49f3f8b5ea931 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithDisabledChildrenProductsTest.xml @@ -0,0 +1,123 @@ +<?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="AdminCreateConfigurableProductWithDisabledChildrenProductsTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Create configurable product with disabled children products"/> + <description value="Admin should be able to create configurable product with disabled children products, assigned to category"/> + <testCaseId value="MC-13711"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <!-- Create attribute with one options --> + <createData entity="productAttributeWithTwoOptionsNotVisible" stepKey="createConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + + <!-- Create the child that will be a part of the configurable product --> + <createData entity="SimpleProductOffline" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption"/> + </createData> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Don't display out of stock product --> + <actionGroup ref="noDisplayOutOfStockProduct" stepKey="revertDisplayOutOfStockProduct"/> + + <!-- Delete configurable product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Delete created data --> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createConfigProductAttribute" stepKey="deleteAttribute"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Fill configurable product values --> + <actionGroup ref="fillMainProductForm" stepKey="fillConfigurableProductValues"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Create product configurations and add attribute and select all options --> + <actionGroup ref="generateConfigurationsByAttributeCode" stepKey="generateConfigurationsByAttributeCode" after="fillConfigurableProductValues"> + <argument name="attributeCode" value="$$createConfigProductAttribute.attribute_code$$"/> + </actionGroup> + + <!-- Add configurable product to category --> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createCategory.name$$]" stepKey="fillCategory" after="fillConfigurableProductValues"/> + + <!-- Add child product to configurations grid --> + <actionGroup ref="addProductToConfigurationsGrid" stepKey="addSimpleProduct"> + <argument name="sku" value="$$createSimpleProduct.sku$$"/> + <argument name="name" value="$$createConfigProductAttributeOption.option[store_labels][1][label]$$"/> + </actionGroup> + + <!-- Save configurable product --> + <actionGroup ref="saveProductForm" stepKey="saveConfigurableProduct"/> + + <!-- Find configurable product in grid --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="visitAdminProductPage"/> + <waitForPageLoad stepKey="waitForAdminProductPageLoad"/> + <actionGroup ref="filterProductGridBySku" stepKey="findCreatedConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Assert configurable product on admin product page --> + <click selector="{{AdminProductGridSection.firstRow}}" stepKey="clickOnProductPage"/> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <actionGroup ref="assertConfigurableProductOnAdminProductPage" stepKey="assertConfigurableProductOnAdminProductPage"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!--Assert configurable attributes block is present on product page --> + <scrollTo selector="{{AdminProductFormConfigurationsSection.sectionHeader}}" stepKey="scrollToSearchEngineTab" /> + <seeElement selector="{{AdminProductFormConfigurationsSection.createdConfigurationsBlock}}" stepKey="seeCreatedConfigurations"/> + <see userInput="$$createSimpleProduct.name$$" selector="{{AdminProductFormConfigurationsSection.currentVariationsNameCells}}" stepKey="seeProductNameInConfigurations"/> + + <!-- Display out of stock product --> + <actionGroup ref="displayOutOfStockProduct" stepKey="displayOutOfStockProduct"/> + + <!-- Flash cache --> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + + <!-- Assert configurable product is not present in category --> + <amOnPage url="$$createCategory.name$$.html" stepKey="amOnCategoryPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + <see selector="{{StorefrontCategoryMainSection.emptyProductMessage}}" userInput="We can't find products matching the selection." stepKey="seeEmptyProductMessage"/> + + <!-- Assert configurable product is out of stock--> + <amOnPage url="{{ApiConfigurableProduct.urlKey}}.html" stepKey="amOnProductPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <see stepKey="checkForOutOfStock" selector="{{StorefrontProductInfoMainSection.stockIndication}}" userInput="OUT OF STOCK"/> + </test> +</tests> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithImagesTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithImagesTest.xml new file mode 100644 index 0000000000000..925e7a890cead --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithImagesTest.xml @@ -0,0 +1,159 @@ +<?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="AdminCreateConfigurableProductWithImagesTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Create configurable product with images"/> + <description value="Admin should be able to create configurable product with images"/> + <testCaseId value="MC-13713"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <!-- Create first attribute with 2 options --> + <createData entity="productAttributeWithTwoOptionsNotVisible" stepKey="createFirstConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOptionOne"> + <requiredEntity createDataKey="createFirstConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOptionTwo"> + <requiredEntity createDataKey="createFirstConfigProductAttribute"/> + </createData> + + <!-- Create second attribute with 2 options --> + <createData entity="productAttributeWithTwoOptions" stepKey="createSecondConfigProductAttribute"/> + <createData entity="productAttributeOption3" stepKey="createConfigProductAttributeOptionThree"> + <requiredEntity createDataKey="createSecondConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption4" stepKey="createConfigProductAttributeOptionFour"> + <requiredEntity createDataKey="createSecondConfigProductAttribute"/> + </createData> + + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createFirstConfigProductAttribute"/> + <requiredEntity createDataKey="createSecondConfigProductAttribute"/> + </createData> + + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Delete configurable product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Delete created data --> + <deleteData createDataKey="createFirstConfigProductAttribute" stepKey="deleteFirstConfigProductAttribute"/> + <deleteData createDataKey="createSecondConfigProductAttribute" stepKey="deleteSecondConfigProductAttribute"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Fill configurable product values --> + <actionGroup ref="fillMainProductForm" stepKey="fillConfigurableProductValues"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Add configurable product to category --> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createCategory.name$$]" stepKey="fillCategory" after="fillConfigurableProductValues"/> + + <!-- Add image to product --> + <actionGroup ref="addProductImage" stepKey="addImageForProduct"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + + <!-- Create product configurations --> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations" after="addImageForProduct"/> + <waitForElementVisible selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" time="30" stepKey="waitForConfigurationModalOpen" after="clickCreateConfigurations"/> + + <!-- Show 100 attributes per page --> + <actionGroup ref="adminDataGridSelectPerPage" stepKey="selectNumberOfAttributesPerPage"> + <argument name="perPage" value="100"/> + </actionGroup> + + <!--Add attributes and select all options --> + <click selector="{{AdminCreateProductConfigurationsPanel.attributeRowByAttributeCode($$createFirstConfigProductAttribute.attribute_code$$)}}" stepKey="clickOnFirstAttributeCheckbox"/> + <click selector="{{AdminCreateProductConfigurationsPanel.attributeRowByAttributeCode($$createSecondConfigProductAttribute.attribute_code$$)}}" stepKey="clickOnSecondAttributeCheckbox"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton1"/> + <click selector="{{AdminCreateProductConfigurationsPanel.selectAllByAttribute($$createFirstConfigProductAttribute.default_frontend_label$$)}}" stepKey="clickOnSelectAllInFirstAttribute"/> + <click selector="{{AdminCreateProductConfigurationsPanel.selectAllByAttribute($$createSecondConfigProductAttribute.default_frontend_label$$)}}" stepKey="clickOnSelectAllInSecondAttribute"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton2"/> + + <!-- Add images to first product attribute options --> + <actionGroup ref="addUniqueImageToConfigurableProductOption" stepKey="addImageToConfigurableProductOptionOne"> + <argument name="image" value="MagentoLogo"/> + <argument name="frontend_label" value="$$createFirstConfigProductAttribute.default_frontend_label$$"/> + <argument name="label" value="$$createConfigProductAttributeOptionOne.option[store_labels][1][label]$$"/> + </actionGroup> + <actionGroup ref="addUniqueImageToConfigurableProductOption" stepKey="addImageToConfigurableProductOptionTwo"> + <argument name="image" value="TestImageNew"/> + <argument name="frontend_label" value="$$createFirstConfigProductAttribute.default_frontend_label$$"/> + <argument name="label" value="$$createConfigProductAttributeOptionTwo.option[store_labels][1][label]$$"/> + </actionGroup> + + <!-- Add price to second product attribute options --> + <actionGroup ref="addUniquePriceToConfigurableProductOption" stepKey="addPriceToConfigurableProductOptionThree"> + <argument name="frontend_label" value="$$createSecondConfigProductAttribute.default_frontend_label$$"/> + <argument name="label" value="$$createConfigProductAttributeOptionThree.option[store_labels][1][label]$$"/> + <argument name="price" value="{{virtualProductWithRequiredFields.price}}"/> + </actionGroup> + <actionGroup ref="addUniquePriceToConfigurableProductOption" stepKey="addPriceToConfigurableProductOptionFour"> + <argument name="frontend_label" value="$$createSecondConfigProductAttribute.default_frontend_label$$"/> + <argument name="label" value="$$createConfigProductAttributeOptionFour.option[store_labels][1][label]$$"/> + <argument name="price" value="{{virtualProductWithRequiredFields.price}}"/> + </actionGroup> + + <!-- Add quantity to product attribute options --> + <click selector="{{AdminCreateProductConfigurationsPanel.applySingleQuantityToEachSkus}}" stepKey="clickOnApplySingleQuantityToEachSku"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.quantity}}" userInput="100" stepKey="enterAttributeQuantity"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton3"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton4"/> + + <!-- Save product --> + <actionGroup ref="saveConfigurableProductAddToCurrentAttributeSet" stepKey="saveProduct"/> + + <!-- Assert configurable product in category --> + <amOnPage url="$$createCategory.name$$.html" stepKey="amOnCategoryPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="assertConfigurableProductInCategory"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="optionProduct" value="virtualProductWithRequiredFields"/> + </actionGroup> + + <!-- Assert product image in storefront product page --> + <amOnPage url="{{ApiConfigurableProduct.urlKey}}.html" stepKey="amOnProductPage"/> + <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + + <!-- Assert product options images in storefront product page --> + <actionGroup ref="assertOptionImageInStorefrontProductPage" stepKey="assertFirstOptionImageInStorefrontProductPage"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="label" value="$$createConfigProductAttributeOptionOne.option[store_labels][1][label]$$"/> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + <actionGroup ref="assertOptionImageInStorefrontProductPage" stepKey="assertSecondOptionImageInStorefrontProductPage"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="label" value="$$createConfigProductAttributeOptionTwo.option[store_labels][1][label]$$"/> + <argument name="image" value="TestImageNew"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithThreeProductDisplayOutOfStockProductsTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithThreeProductDisplayOutOfStockProductsTest.xml new file mode 100644 index 0000000000000..0b83fdc1788d3 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithThreeProductDisplayOutOfStockProductsTest.xml @@ -0,0 +1,140 @@ +<?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="AdminCreateConfigurableProductWithThreeProductDisplayOutOfStockProductsTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Create Configurable Product with three product, display out of stock products"/> + <description value="Admin should be able to create Configurable Product with one out of stock and several in stock options, display out of stock products"/> + <testCaseId value="MC-13714"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <!-- Create attribute with 3 options to be used in children products --> + <createData entity="productAttributeWithTwoOptionsNotVisible" stepKey="createConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOptionOne"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOptionTwo"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption3" stepKey="createConfigProductAttributeOptionThree"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOptionOne"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getConfigAttributeOptionTwo"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="3" stepKey="getConfigAttributeOptionThree"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + + <!-- Create the 3 children that will be a part of the configurable product --> + <createData entity="ApiSimpleOne" stepKey="createFirstSimpleProduct"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOptionOne"/> + </createData> + <createData entity="ApiSimpleTwo" stepKey="createSecondSimpleProduct"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOptionTwo"/> + </createData> + <createData entity="ApiSimpleOutOfStock" stepKey="createSimpleOutOfStockProduct"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOptionThree"/> + </createData> + + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Don't display out of stock product --> + <actionGroup ref="noDisplayOutOfStockProduct" stepKey="revertDisplayOutOfStockProduct"/> + + <!-- Delete configurable product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Delete created data --> + <deleteData createDataKey="createFirstSimpleProduct" stepKey="deleteFirstSimpleProduct"/> + <deleteData createDataKey="createSecondSimpleProduct" stepKey="deleteSecondSimpleProduct"/> + <deleteData createDataKey="createSimpleOutOfStockProduct" stepKey="deleteSimpleOutOfStockProduct"/> + <deleteData createDataKey="createConfigProductAttribute" stepKey="deleteConfigProductAttribute"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!--Fill configurable product values --> + <actionGroup ref="fillMainProductForm" stepKey="fillConfigurableProductValues"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Create product configurations and add attribute and select all options --> + <actionGroup ref="generateConfigurationsByAttributeCode" stepKey="generateConfigurationsByAttributeCode" after="fillConfigurableProductValues"> + <argument name="attributeCode" value="$$createConfigProductAttribute.attribute_code$$"/> + </actionGroup> + + <!-- Add configurable product to category --> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createCategory.name$$]" stepKey="fillCategory" after="fillConfigurableProductValues"/> + + <!-- Add child products to configurations grid --> + <actionGroup ref="addProductToConfigurationsGrid" stepKey="addFirstSimpleProduct"> + <argument name="sku" value="$$createFirstSimpleProduct.sku$$"/> + <argument name="name" value="$$createConfigProductAttributeOptionOne.option[store_labels][1][label]$$"/> + </actionGroup> + + <actionGroup ref="addProductToConfigurationsGrid" stepKey="addSecondSimpleProduct"> + <argument name="sku" value="$$createSecondSimpleProduct.sku$$"/> + <argument name="name" value="$$createConfigProductAttributeOptionTwo.option[store_labels][1][label]$$"/> + </actionGroup> + + <actionGroup ref="addProductToConfigurationsGrid" stepKey="addOutOfStockProduct"> + <argument name="sku" value="$$createSimpleOutOfStockProduct.sku$$"/> + <argument name="name" value="$$createConfigProductAttributeOptionThree.option[store_labels][1][label]$$"/> + </actionGroup> + + <!-- Save configurable product --> + <actionGroup ref="saveProductForm" stepKey="saveConfigurableProduct"/> + + <!-- Display out of stock product --> + <actionGroup ref="displayOutOfStockProduct" stepKey="displayOutOfStockProduct"/> + + <!-- Flash cache --> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + + <!--Assert configurable product in category --> + <amOnPage url="$$createCategory.name$$.html" stepKey="amOnCategoryPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="assertConfigurableProductInCategory"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="optionProduct" value="$$createFirstSimpleProduct$$"/> + </actionGroup> + + <!-- Assert out of stock option is absent on product page --> + <amOnPage url="{{ApiConfigurableProduct.urlKey}}.html" stepKey="amOnProductPage"/> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <dontSee userInput="$$createConfigProductAttributeOptionThree.option[store_labels][1][label]$$" selector="{{StorefrontProductInfoMainSection.optionByAttributeId($$createConfigProductAttribute.attribute_id$$)}}" stepKey="assertOptionNotAvailable" /> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithThreeProductDontDisplayOutOfStockProductsTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithThreeProductDontDisplayOutOfStockProductsTest.xml new file mode 100644 index 0000000000000..e24ac07c30d1e --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithThreeProductDontDisplayOutOfStockProductsTest.xml @@ -0,0 +1,134 @@ +<?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="AdminCreateConfigurableProductWithThreeProductDontDisplayOutOfStockProductsTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Create Configurable Product with three product, don't display out of stock products"/> + <description value="Admin should be able to create Configurable Product with one out of stock and several in stock options, don't display out of stock products"/> + <testCaseId value="MC-13715"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <!-- Create attribute with 3 options to be used in children products --> + <createData entity="productAttributeWithTwoOptionsNotVisible" stepKey="createConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOptionOne"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOptionTwo"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption3" stepKey="createConfigProductAttributeOptionThree"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOptionOne"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getConfigAttributeOptionTwo"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="3" stepKey="getConfigAttributeOptionThree"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + + <!-- Create the 3 children that will be a part of the configurable product --> + <createData entity="ApiSimpleOne" stepKey="createFirstSimpleProduct"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOptionOne"/> + </createData> + <createData entity="ApiSimpleTwo" stepKey="createSecondSimpleProduct"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOptionTwo"/> + </createData> + <createData entity="ApiSimpleOutOfStock" stepKey="createSimpleOutOfStockProduct"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOptionThree"/> + </createData> + + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Delete configurable product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Delete created data --> + <deleteData createDataKey="createFirstSimpleProduct" stepKey="deleteFirstSimpleProduct"/> + <deleteData createDataKey="createSecondSimpleProduct" stepKey="deleteSecondSimpleProduct"/> + <deleteData createDataKey="createSimpleOutOfStockProduct" stepKey="deleteSimpleOutOfStockProduct"/> + <deleteData createDataKey="createConfigProductAttribute" stepKey="deleteConfigProductAttribute"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!--Fill configurable product values --> + <actionGroup ref="fillMainProductForm" stepKey="fillConfigurableProductValues"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Create product configurations and add attribute and select all options --> + <actionGroup ref="generateConfigurationsByAttributeCode" stepKey="generateConfigurationsByAttributeCode" after="fillConfigurableProductValues"> + <argument name="attributeCode" value="$$createConfigProductAttribute.attribute_code$$"/> + </actionGroup> + + <!-- Add configurable product to category --> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createCategory.name$$]" stepKey="fillCategory" after="fillConfigurableProductValues"/> + + <!-- Add child products to configurations grid --> + <actionGroup ref="addProductToConfigurationsGrid" stepKey="addFirstSimpleProduct"> + <argument name="sku" value="$$createFirstSimpleProduct.sku$$"/> + <argument name="name" value="$$createConfigProductAttributeOptionOne.option[store_labels][1][label]$$"/> + </actionGroup> + + <actionGroup ref="addProductToConfigurationsGrid" stepKey="addSecondSimpleProduct"> + <argument name="sku" value="$$createSecondSimpleProduct.sku$$"/> + <argument name="name" value="$$createConfigProductAttributeOptionTwo.option[store_labels][1][label]$$"/> + </actionGroup> + + <actionGroup ref="addProductToConfigurationsGrid" stepKey="addOutOfStockProduct"> + <argument name="sku" value="$$createSimpleOutOfStockProduct.sku$$"/> + <argument name="name" value="$createConfigProductAttributeOptionThree.option[store_labels][1][label]$$"/> + </actionGroup> + + <!-- Save configurable product --> + <actionGroup ref="saveProductForm" stepKey="saveConfigurableProduct"/> + + <!-- Flash cache --> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + + <!--Assert configurable product in category --> + <amOnPage url="$$createCategory.name$$.html" stepKey="amOnCategoryPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="assertConfigurableProductInCategory"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="optionProduct" value="$$createFirstSimpleProduct$$"/> + </actionGroup> + + <!-- Assert out of stock option is absent on product page --> + <amOnPage url="{{ApiConfigurableProduct.urlKey}}.html" stepKey="amOnProductPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <dontSee userInput="$$createConfigProductAttributeOptionThree.option[store_labels][1][label]$$" selector="{{StorefrontProductInfoMainSection.optionByAttributeId($$createConfigProductAttribute.attribute_id$$)}}" stepKey="assertOptionNotAvailable"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTierPriceForOneItemTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTierPriceForOneItemTest.xml new file mode 100644 index 0000000000000..51f4bf0279942 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTierPriceForOneItemTest.xml @@ -0,0 +1,111 @@ +<?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="AdminCreateConfigurableProductWithTierPriceForOneItemTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Create configurable product with tier price for one item"/> + <description value="Admin should be able to create configurable product with tier price for one item"/> + <testCaseId value="MC-13695"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <!-- Create attribute with 2 options to be used in children products --> + <createData entity="productAttributeWithTwoOptionsNotVisible" stepKey="createConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOptionOne"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOptionTwo"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOptionOne"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getConfigAttributeOptionTwo"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + + <!-- Create the 2 children that will be a part of the configurable product --> + <createData entity="ApiSimpleOne" stepKey="createFirstSimpleProduct"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOptionOne"/> + </createData> + <createData entity="ApiSimpleTwo" stepKey="createSecondSimpleProduct"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOptionTwo"/> + </createData> + + <!--Add tier price in one product --> + <createData entity="tierProductPrice" stepKey="addTierPrice"> + <requiredEntity createDataKey="createFirstSimpleProduct" /> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Delete configurable product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Delete created data --> + <deleteData createDataKey="createFirstSimpleProduct" stepKey="deleteFirstSimpleProduct"/> + <deleteData createDataKey="createSecondSimpleProduct" stepKey="deleteSecondSimpleProduct"/> + <deleteData createDataKey="createConfigProductAttribute" stepKey="deleteConfigProductAttribute"/> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!--Fill configurable product values --> + <actionGroup ref="fillMainProductForm" stepKey="fillConfigurableProductValues"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Create product configurations and add attribute and select all options --> + <actionGroup ref="generateConfigurationsByAttributeCode" stepKey="generateConfigurationsByAttributeCode" after="fillConfigurableProductValues"> + <argument name="attributeCode" value="$$createConfigProductAttribute.attribute_code$$"/> + </actionGroup> + + <!-- Add associated products to configurations grid --> + <actionGroup ref="addProductToConfigurationsGrid" stepKey="addFirstSimpleProduct"> + <argument name="sku" value="$$createFirstSimpleProduct.sku$$"/> + <argument name="name" value="$$createConfigProductAttributeOptionOne.option[store_labels][1][label]$$"/> + </actionGroup> + + <actionGroup ref="addProductToConfigurationsGrid" stepKey="addSecondSimpleProduct"> + <argument name="sku" value="$$createSecondSimpleProduct.sku$$"/> + <argument name="name" value="$$createConfigProductAttributeOptionTwo.option[store_labels][1][label]$$"/> + </actionGroup> + + <!-- Save configurable product --> + <actionGroup ref="saveProductForm" stepKey="saveConfigurableProduct"/> + + <!-- Assert product tier price on product page --> + <amOnPage url="{{ApiConfigurableProduct.urlKey}}.html" stepKey="amOnProductPage"/> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <selectOption userInput="$$createConfigProductAttributeOptionOne.option[store_labels][1][label]$$" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOption1"/> + <grabTextFrom selector="{{StorefrontProductInfoMainSection.tierPriceText}}" stepKey="tierPriceText"/> + <assertEquals stepKey="assertTierPriceTextOnProductPage"> + <expectedResult type="string">Buy {{tierProductPrice.quantity}} for ${{tierProductPrice.price}} each and save 27%</expectedResult> + <actualResult type="variable">tierPriceText</actualResult> + </assertEquals> + </test> +</tests> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTwoOptionsAssignedToCategoryTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTwoOptionsAssignedToCategoryTest.xml new file mode 100644 index 0000000000000..981985b3f4ea8 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTwoOptionsAssignedToCategoryTest.xml @@ -0,0 +1,154 @@ +<?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="AdminCreateConfigurableProductWithTwoOptionsAssignedToCategoryTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Create configurable product with two new options assigned to category with not visible child products"/> + <description value="Admin should be able to create configurable product with two new options, assigned to category, child products are not visible individually"/> + <testCaseId value="MC-13685"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <!-- Create category --> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + + <!-- Login as admin --> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Delete configurable product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Delete children products --> + <actionGroup ref="deleteProductBySku" stepKey="deleteFirstChildProduct"> + <argument name="sku" value="{{colorConfigurableProductAttribute1.sku}}"/> + </actionGroup> + <actionGroup ref="deleteProductBySku" stepKey="deleteSecondChildProduct"> + <argument name="sku" value="{{colorConfigurableProductAttribute2.sku}}"/> + </actionGroup> + + <!-- Delete product attribute --> + <actionGroup ref="deleteProductAttributeByLabel" stepKey="deleteProductAttribute"> + <argument name="ProductAttribute" value="colorProductAttribute"/> + </actionGroup> + + <!-- Delete attribute set --> + <actionGroup ref="deleteAttributeSetByLabel" stepKey="deleteAttributeSet"> + <argument name="label" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + + <!-- Delete category --> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Fill configurable product values --> + <actionGroup ref="fillMainProductForm" stepKey="fillConfigurableProductValues"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Create product configurations --> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations" after="fillConfigurableProductValues"/> + <waitForElementVisible selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" time="30" stepKey="waitForConfigurationModalOpen" after="clickCreateConfigurations"/> + + <!--Create new attribute with two options --> + <actionGroup ref="addNewProductConfigurationAttribute" stepKey="createProductConfigurationAttribute"> + <argument name="attribute" value="colorProductAttribute"/> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Change product configurations in grid --> + <actionGroup ref="changeProductConfigurationsInGrid" stepKey="changeProductConfigurationsInGrid"> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Add configurable product to category --> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createCategory.name$$]" stepKey="fillCategory" after="fillConfigurableProductValues"/> + + <!-- Save configurable product; add product to new attribute set --> + <actionGroup ref="saveConfigurableProductWithNewAttributeSet" stepKey="saveConfigurableProduct"/> + + <!-- Assert child products in grid --> + <actionGroup ref="viewProductInAdminGrid" stepKey="viewFirstChildProductInAdminGrid"> + <argument name="product" value="colorConfigurableProductAttribute1"/> + </actionGroup> + <actionGroup ref="viewProductInAdminGrid" stepKey="viewSecondChildProductInAdminGrid"> + <argument name="product" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Assert configurable product in grid --> + <actionGroup ref="filterProductGridBySkuAndName" stepKey="findCreatedConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + <see selector="{{AdminProductGridSection.productGridCell('1', 'Type')}}" userInput="{{ApiConfigurableProduct.type_id}}" stepKey="seeProductTypeInGrid"/> + <click selector="{{AdminProductGridFilterSection.clearFilters}}" stepKey="clickClearFiltersAfter"/> + + <!-- Flash cache --> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + + <!--Assert configurable product in category --> + <amOnPage url="$$createCategory.name$$.html" stepKey="amOnCategoryPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="assertConfigurableProductInCategory"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="optionProduct" value="colorConfigurableProductAttribute1"/> + </actionGroup> + + <!--Assert configurable product on product page --> + <amOnPage url="{{ApiConfigurableProduct.urlKey}}.html" stepKey="amOnProductPage" after="assertConfigurableProductInCategory"/> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <actionGroup ref="storefrontCheckConfigurableProductOptions" stepKey="checkConfigurableProductOptions"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Add configurable product to the cart with selected first option --> + <selectOption userInput="{{colorConfigurableProductAttribute1.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOptionForAddingToCart"/> + <click selector="{{StorefrontProductInfoMainSection.AddToCart}}" stepKey="clickAddToCart"/> + <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" stepKey="waitForSuccessMessage"/> + + <!-- Assert configurable product in cart --> + <amOnPage url="/checkout/cart/" stepKey="amOnShoppingCartPage"/> + <waitForPageLoad stepKey="waitForShoppingCartPageLoad"/> + <actionGroup ref="StorefrontCheckCartConfigurableProductActionGroup" stepKey="storefrontCheckCartConfigurableProductActionGroup"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="optionProduct" value="colorConfigurableProductAttribute1"/> + <argument name="productQuantity" value="CONST.one"/> + </actionGroup> + + <!-- Assert child products are not displayed separately: two next step --> + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToStoreFront"/> + <waitForPageLoad stepKey="waitForStoreFrontPageLoad"/> + + <!-- Quick search the storefront for the first attribute option --> + <submitForm selector="{{StorefrontQuickSearchSection.searchMiniForm}}" parameterArray="['q' => {{colorConfigurableProductAttribute1.sku}}]" stepKey="searchStorefrontFistChildProduct"/> + <dontSee selector="{{StorefrontCategoryProductSection.ProductTitleByName(colorConfigurableProductAttribute1.name)}}" stepKey="dontSeeConfigurableProductFirstChild"/> + + <!-- Quick search the storefront for the second attribute option --> + <submitForm selector="{{StorefrontQuickSearchSection.searchMiniForm}}" parameterArray="['q' => {{colorConfigurableProductAttribute2.sku}}]" stepKey="searchStorefrontSecondChildProduct"/> + <dontSee selector="{{StorefrontCategoryProductSection.ProductTitleByName(colorConfigurableProductAttribute2.name)}}" stepKey="dontSeeConfigurableProductSecondChild"/> + </test> +</tests> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTwoOptionsWithoutAssignedToCategoryTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTwoOptionsWithoutAssignedToCategoryTest.xml new file mode 100644 index 0000000000000..e278018330aa6 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithTwoOptionsWithoutAssignedToCategoryTest.xml @@ -0,0 +1,136 @@ +<?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="AdminCreateConfigurableProductWithTwoOptionsWithoutAssignedToCategoryTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Create configurable product"/> + <title value="Create configurable product with two new options without assigned to category with not visible child products"/> + <description value="Admin should be able to create configurable product with two options without assigned to category, child products are not visible individually"/> + <testCaseId value="MC-13686"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Delete configurable product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Delete children products --> + <actionGroup ref="deleteProductBySku" stepKey="deleteFirstChildProduct"> + <argument name="sku" value="{{colorConfigurableProductAttribute1.sku}}"/> + </actionGroup> + <actionGroup ref="deleteProductBySku" stepKey="deleteSecondChildProduct"> + <argument name="sku" value="{{colorConfigurableProductAttribute2.sku}}"/> + </actionGroup> + + <!-- Delete product attribute --> + <actionGroup ref="deleteProductAttributeByLabel" stepKey="deleteProductAttribute"> + <argument name="ProductAttribute" value="colorProductAttribute"/> + </actionGroup> + + <!-- Delete attribute set --> + <actionGroup ref="deleteAttributeSetByLabel" stepKey="deleteAttributeSet"> + <argument name="label" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + + <!-- Log out --> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create configurable product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="createConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!-- Fill configurable product values --> + <actionGroup ref="fillMainProductForm" stepKey="fillConfigurableProductValues"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + + <!--Create product configurations--> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations" after="fillConfigurableProductValues"/> + <waitForElementVisible selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" time="30" stepKey="waitForConfigurationModalOpen" after="clickCreateConfigurations"/> + + <!--Create new attribute with two option --> + <actionGroup ref="addNewProductConfigurationAttribute" stepKey="createProductConfigurationAttribute"> + <argument name="attribute" value="colorProductAttribute"/> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Change product configurations in grid --> + <actionGroup ref="changeProductConfigurationsInGrid" stepKey="changeProductConfigurationsInGrid"> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Save configurable product; add product to new attribute set --> + <actionGroup ref="saveConfigurableProductWithNewAttributeSet" stepKey="saveConfigurableProduct"/> + + <!-- Assert Child Products in grid --> + <actionGroup ref="viewProductInAdminGrid" stepKey="viewFirstChildProductInAdminGrid"> + <argument name="product" value="colorConfigurableProductAttribute1"/> + </actionGroup> + <actionGroup ref="viewProductInAdminGrid" stepKey="viewSecondChildProductInAdminGrid"> + <argument name="product" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Assert Configurable Product in grid --> + <actionGroup ref="filterProductGridBySkuAndName" stepKey="findCreatedConfigurableProduct"> + <argument name="product" value="ApiConfigurableProduct"/> + </actionGroup> + <see selector="{{AdminProductGridSection.productGridCell('1', 'Type')}}" userInput="{{ApiConfigurableProduct.type_id}}" stepKey="seeProductTypeInGrid"/> + <click selector="{{AdminProductGridFilterSection.clearFilters}}" stepKey="clickClearFiltersAfter"/> + + <!-- Flash cache --> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + + <!-- Assert configurable product on product page --> + <amOnPage url="{{ApiConfigurableProduct.urlKey}}.html" stepKey="amOnProductPage"/> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <actionGroup ref="storefrontCheckConfigurableProductOptions" stepKey="checkConfigurableProductOptions"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="firstOption" value="colorConfigurableProductAttribute1"/> + <argument name="secondOption" value="colorConfigurableProductAttribute2"/> + </actionGroup> + + <!-- Add configurable product to the cart with selected first option --> + <selectOption userInput="{{colorConfigurableProductAttribute1.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOptionForAddingToCart"/> + <click selector="{{StorefrontProductInfoMainSection.AddToCart}}" stepKey="clickAddToCart"/> + <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" stepKey="waitForSuccessMessage"/> + + <!-- Assert configurable product in cart --> + <amOnPage url="/checkout/cart/" stepKey="amOnShoppingCartPage"/> + <waitForPageLoad stepKey="waitForShoppingCartPageLoad"/> + <actionGroup ref="StorefrontCheckCartConfigurableProductActionGroup" stepKey="storefrontCheckCartConfigurableProductActionGroup"> + <argument name="product" value="ApiConfigurableProduct"/> + <argument name="optionProduct" value="colorConfigurableProductAttribute1"/> + <argument name="productQuantity" value="CONST.one"/> + </actionGroup> + + <!-- Assert child products are not displayed separately: two next step --> + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToStoreFront"/> + <waitForPageLoad stepKey="waitForStoreFrontPageLoad"/> + + <!-- Quick search the storefront for the first attribute option --> + <submitForm selector="{{StorefrontQuickSearchSection.searchMiniForm}}" parameterArray="['q' => {{colorConfigurableProductAttribute1.sku}}]" stepKey="searchStorefrontFistChildProduct"/> + <dontSee selector="{{StorefrontCategoryProductSection.ProductTitleByName(colorConfigurableProductAttribute1.name)}}" stepKey="dontSeeConfigurableProductFirstChild"/> + + <!-- Quick search the storefront for the second attribute option --> + <submitForm selector="{{StorefrontQuickSearchSection.searchMiniForm}}" parameterArray="['q' => {{colorConfigurableProductAttribute2.sku}}]" stepKey="searchStorefrontSecondChildProduct"/> + <dontSee selector="{{StorefrontCategoryProductSection.ProductTitleByName(colorConfigurableProductAttribute2.name)}}" stepKey="dontSeeConfigurableProductSecondChild"/> + </test> +</tests> diff --git a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurablePanel.php b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurablePanel.php index fbab25ff1bea6..e0cc83922e03e 100644 --- a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurablePanel.php +++ b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurablePanel.php @@ -5,14 +5,14 @@ */ namespace Magento\ConfigurableProduct\Ui\DataProvider\Product\Form\Modifier; +use Magento\Catalog\Model\Locator\LocatorInterface; use Magento\Catalog\Model\Product\Attribute\Backend\Sku; use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; +use Magento\Framework\UrlInterface; use Magento\Ui\Component\Container; -use Magento\Ui\Component\Form; use Magento\Ui\Component\DynamicRows; +use Magento\Ui\Component\Form; use Magento\Ui\Component\Modal; -use Magento\Framework\UrlInterface; -use Magento\Catalog\Model\Locator\LocatorInterface; /** * Data provider for Configurable panel @@ -90,7 +90,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function modifyData(array $data) { @@ -98,7 +98,7 @@ public function modifyData(array $data) } /** - * {@inheritdoc} + * @inheritdoc * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function modifyMeta(array $meta) @@ -197,7 +197,7 @@ public function modifyMeta(array $meta) 'autoRender' => false, 'componentType' => 'insertListing', 'component' => 'Magento_ConfigurableProduct/js' - .'/components/associated-product-insert-listing', + . '/components/associated-product-insert-listing', 'dataScope' => $this->associatedListingPrefix . static::ASSOCIATED_PRODUCT_LISTING, 'externalProvider' => $this->associatedListingPrefix @@ -328,14 +328,12 @@ protected function getButtonSet() 'component' => 'Magento_Ui/js/form/components/button', 'actions' => [ [ - 'targetName' => - $this->dataScopeName . '.configurableModal', + 'targetName' => $this->dataScopeName . '.configurableModal', 'actionName' => 'trigger', 'params' => ['active', true], ], [ - 'targetName' => - $this->dataScopeName . '.configurableModal', + 'targetName' => $this->dataScopeName . '.configurableModal', 'actionName' => 'openModal', ], ], @@ -471,8 +469,7 @@ protected function getRows() 'sku', __('SKU'), [ - 'validation' => - [ + 'validation' => [ 'required-entry' => true, 'max_text_length' => Sku::SKU_MAX_LENGTH, ], @@ -577,6 +574,7 @@ protected function getColumn( 'dataType' => Form\Element\DataType\Text::NAME, 'dataScope' => $name, 'visibleIfCanEdit' => false, + 'labelVisible' => false, 'imports' => [ 'visible' => '!${$.provider}:${$.parentScope}.canEdit' ], @@ -595,6 +593,7 @@ protected function getColumn( 'component' => 'Magento_Ui/js/form/components/group', 'label' => $label, 'dataScope' => '', + 'showLabel' => false ]; $container['children'] = [ $name . '_edit' => $fieldEdit, diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/price-configurable.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/price-configurable.js index 6bbab77a3a0ab..b2ef35546eea8 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/price-configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/price-configurable.js @@ -11,9 +11,6 @@ define([ return Abstract.extend({ defaults: { - listens: { - isConfigurable: 'handlePriceValue' - }, imports: { isConfigurable: '!ns = ${ $.ns }, index = configurable-matrix:isEmpty' }, @@ -22,12 +19,15 @@ define([ } }, - /** - * Invokes initialize method of parent class, - * contains initialization logic - */ + /** @inheritdoc */ initialize: function () { this._super(); + // resolve initial disable state + this.handlePriceValue(this.isConfigurable); + // add listener to track "configurable" type + this.setListeners({ + isConfigurable: 'handlePriceValue' + }); return this; }, @@ -50,11 +50,10 @@ define([ * @param {String} isConfigurable */ handlePriceValue: function (isConfigurable) { + this.disabled(!!this.isUseDefault() || isConfigurable); + if (isConfigurable) { - this.disable(); this.clear(); - } else { - this.enable(); } } }); diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Orders.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Orders.php index f2b8133e352ad..2fb59ec767e8a 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Orders.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Orders.php @@ -63,7 +63,8 @@ protected function _construct() { parent::_construct(); $this->setId('customer_orders_grid'); - $this->setDefaultSort('created_at', 'desc'); + $this->setDefaultSort('created_at'); + $this->setDefaultDir('desc'); $this->setUseAjax(true); } diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php index 1bc6bb1da3680..e63c00ba18d29 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Cart.php @@ -77,7 +77,8 @@ protected function _construct() { parent::_construct(); $this->setId('customer_view_cart_grid'); - $this->setDefaultSort('added_at', 'desc'); + $this->setDefaultSort('added_at'); + $this->setDefaultDir('desc'); $this->setSortable(false); $this->setPagerVisibility(false); $this->setFilterVisibility(false); diff --git a/app/code/Magento/Customer/Block/Form/Register.php b/app/code/Magento/Customer/Block/Form/Register.php index 322dd2cbfe915..59966768a2eda 100644 --- a/app/code/Magento/Customer/Block/Form/Register.php +++ b/app/code/Magento/Customer/Block/Form/Register.php @@ -86,17 +86,6 @@ public function getConfig($path) return $this->_scopeConfig->getValue($path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE); } - /** - * Prepare layout - * - * @return $this - */ - protected function _prepareLayout() - { - $this->pageConfig->getTitle()->set(__('Create New Customer Account')); - return parent::_prepareLayout(); - } - /** * Retrieve form posting url * diff --git a/app/code/Magento/Customer/Model/Attribute/Data/Postcode.php b/app/code/Magento/Customer/Model/Attribute/Data/Postcode.php index 380b8a4d3446f..b1602e8ca1939 100644 --- a/app/code/Magento/Customer/Model/Attribute/Data/Postcode.php +++ b/app/code/Magento/Customer/Model/Attribute/Data/Postcode.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Customer\Model\Attribute\Data; use Magento\Directory\Helper\Data as DirectoryHelper; @@ -13,7 +14,8 @@ use Magento\Framework\Stdlib\DateTime\TimezoneInterface as MagentoTimezone; /** - * Customer Address Postal/Zip Code Attribute Data Model + * Customer Address Postal/Zip Code Attribute Data Model. + * * This Data Model Has to Be Set Up in additional EAV attribute table */ class Postcode extends \Magento\Eav\Model\Attribute\Data\AbstractData @@ -40,7 +42,8 @@ public function __construct( } /** - * Validate postal/zip code + * Validate postal/zip code. + * * Return true and skip validation if country zip code is optional * * @param array|string $value @@ -104,7 +107,7 @@ public function restoreValue($value) } /** - * Return formated attribute value from entity model + * Return formatted attribute value from entity model * * @param string $format * @return string|array diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertAddressInCustomersAddressGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertAddressInCustomersAddressGridActionGroup.xml new file mode 100644 index 0000000000000..53dba774d6c43 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertAddressInCustomersAddressGridActionGroup.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"> + <!--Assert customer info in customers grid row --> + <actionGroup name="AdminAssertAddressInCustomersAddressGrid"> + <arguments> + <argument name="text" type="string"/> + </arguments> + <see selector="{{AdminCustomerAddressesGridSection.rowsInGrid}}" userInput="{{text}}" stepKey="seeTextInGrid"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerAccountInformationActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerAccountInformationActionGroup.xml new file mode 100644 index 0000000000000..a908d042fcc59 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerAccountInformationActionGroup.xml @@ -0,0 +1,22 @@ +<?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"> + <!-- Assert Customer Account Information --> + <actionGroup name="AdminAssertCustomerAccountInformation" > + <arguments> + <argument name="firstName" type="string" defaultValue=""/> + <argument name="lastName" type="string" defaultValue=""/> + <argument name="email" type="string" defaultValue=""/> + </arguments> + <click selector="{{AdminCustomerAccountInformationSection.accountInformationTab}}" stepKey="proceedToAccountInformation"/> + <seeInField userInput="{{firstName}}" selector="{{AdminCustomerAccountInformationSection.firstName}}" stepKey="firstName"/> + <seeInField userInput="{{lastName}}" selector="{{AdminCustomerAccountInformationSection.lastName}}" stepKey="lastName"/> + <seeInField userInput="{{email}}" selector="{{AdminCustomerAccountInformationSection.email}}" stepKey="email"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerDefaultBillingAddressActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerDefaultBillingAddressActionGroup.xml new file mode 100644 index 0000000000000..32b624706102f --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerDefaultBillingAddressActionGroup.xml @@ -0,0 +1,30 @@ +<?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"> + <!-- Assert Customer Default Billing Address --> + <actionGroup name="AdminAssertCustomerDefaultBillingAddress" > + <arguments> + <argument name="firstName" type="string" defaultValue=""/> + <argument name="lastName" type="string" defaultValue=""/> + <argument name="street1" type="string" defaultValue=""/> + <argument name="state" type="string" defaultValue=""/> + <argument name="postcode" type="string" defaultValue=""/> + <argument name="country" type="string" defaultValue=""/> + <argument name="telephone" type="string" defaultValue=""/> + </arguments> + <click selector="{{AdminEditCustomerAddressesSection.addresses}}" stepKey="proceedToAddresses"/> + <see userInput="{{firstName}}" selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" stepKey="firstName"/> + <see userInput="{{lastName}}" selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" stepKey="lastName"/> + <see userInput="{{street1}}" selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" stepKey="street1"/> + <see userInput="{{state}}" selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" stepKey="state"/> + <see userInput="{{postcode}}" selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" stepKey="postcode"/> + <see userInput="{{country}}" selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" stepKey="country"/> + <see userInput="{{telephone}}" selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" stepKey="telephone"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerDefaultShippingAddressActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerDefaultShippingAddressActionGroup.xml new file mode 100644 index 0000000000000..9d7c209121fd6 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerDefaultShippingAddressActionGroup.xml @@ -0,0 +1,30 @@ +<?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"> + <!-- Assert Customer Default Shipping Address --> + <actionGroup name="AdminAssertCustomerDefaultShippingAddress" > + <arguments> + <argument name="firstName" type="string" defaultValue=""/> + <argument name="lastName" type="string" defaultValue=""/> + <argument name="street1" type="string" defaultValue=""/> + <argument name="state" type="string" defaultValue="" /> + <argument name="postcode" type="string" defaultValue=""/> + <argument name="country" type="string" defaultValue=""/> + <argument name="telephone" type="string" defaultValue=""/> + </arguments> + <click selector="{{AdminEditCustomerAddressesSection.addresses}}" stepKey="proceedToAddresses"/> + <see userInput="{{firstName}}" selector="{{AdminCustomerAddressesDefaultShippingSection.addressDetails}}" stepKey="firstName"/> + <see userInput="{{lastName}}" selector="{{AdminCustomerAddressesDefaultShippingSection.addressDetails}}" stepKey="lastName"/> + <see userInput="{{street1}}" selector="{{AdminCustomerAddressesDefaultShippingSection.addressDetails}}" stepKey="street1"/> + <see userInput="{{state}}" selector="{{AdminCustomerAddressesDefaultShippingSection.addressDetails}}" stepKey="state"/> + <see userInput="{{postcode}}" selector="{{AdminCustomerAddressesDefaultShippingSection.addressDetails}}" stepKey="postcode"/> + <see userInput="{{country}}" selector="{{AdminCustomerAddressesDefaultShippingSection.addressDetails}}" stepKey="country"/> + <see userInput="{{telephone}}" selector="{{AdminCustomerAddressesDefaultShippingSection.addressDetails}}" stepKey="telephone"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerInCustomersGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerInCustomersGridActionGroup.xml new file mode 100644 index 0000000000000..d7529b3bdd58e --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerInCustomersGridActionGroup.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"> + <!--Assert customer info in customers grid row --> + <actionGroup name="AdminAssertCustomerInCustomersGrid"> + <arguments> + <argument name="text" type="string"/> + <argument name="row" type="string"/> + </arguments> + <see selector="{{AdminCustomerGridSection.gridRow(row)}}" userInput="{{text}}" stepKey="seeCustomerInGrid"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerNoDefaultBillingAddressActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerNoDefaultBillingAddressActionGroup.xml new file mode 100644 index 0000000000000..5557025c4b1de --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerNoDefaultBillingAddressActionGroup.xml @@ -0,0 +1,15 @@ +<?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"> + <!-- Assert Customer Have No Default Billing Address --> + <actionGroup name="AdminAssertCustomerNoDefaultBillingAddress" > + <click selector="{{AdminEditCustomerAddressesSection.addresses}}" stepKey="proceedToAddresses"/> + <see userInput="The customer does not have default billing address" selector="{{AdminCustomerAddressesDefaultBillingSection.address}}" stepKey="see"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerNoDefaultShippingAddressActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerNoDefaultShippingAddressActionGroup.xml new file mode 100644 index 0000000000000..e33ebbb96ee19 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertCustomerNoDefaultShippingAddressActionGroup.xml @@ -0,0 +1,15 @@ +<?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"> + <!-- Assert Customer Have No Default Shipping Address --> + <actionGroup name="AdminAssertCustomerNoDefaultShippingAddress" > + <click selector="{{AdminEditCustomerAddressesSection.addresses}}" stepKey="proceedToAddresses"/> + <see userInput="The customer does not have default shipping address" selector="{{AdminCustomerAddressesDefaultShippingSection.address}}" stepKey="see"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertNumberOfRecordsInCustomersAddressGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertNumberOfRecordsInCustomersAddressGridActionGroup.xml new file mode 100644 index 0000000000000..390f723d91f17 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAssertNumberOfRecordsInCustomersAddressGridActionGroup.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"> + <!--Assert number of records in customer address grid --> + <actionGroup name="AdminAssertNumberOfRecordsInCustomersAddressGrid"> + <arguments> + <argument name="number" type="string"/> + </arguments> + <see userInput="{{number}} records found" selector="{{AdminCustomerAddressesGridActionsSection.headerRow}}" stepKey="seeRecords"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGridActionGroup.xml new file mode 100644 index 0000000000000..86039056999b0 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGridActionGroup.xml @@ -0,0 +1,23 @@ +<?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="AdminFilterCustomerByEmail"> + <arguments> + <argument name="email" type="string"/> + </arguments> + <amOnPage url="{{AdminCustomerPage.url}}" stepKey="openCustomerIndexPage"/> + <waitForPageLoad stepKey="waitToCustomerIndexPageToLoad"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openFiltersSectionOnCustomerIndexPage"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="cleanFiltersIfTheySet"/> + <fillField userInput="{{email}}" selector="{{AdminCustomerFiltersSection.emailInput}}" stepKey="filterEmail"/> + <click selector="{{AdminCustomerFiltersSection.apply}}" stepKey="applyFilter"/> + <waitForPageLoad stepKey="waitForPageToLoad"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerSaveAndContinueActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerSaveAndContinueActionGroup.xml new file mode 100644 index 0000000000000..03b950a6dbe6f --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerSaveAndContinueActionGroup.xml @@ -0,0 +1,14 @@ +<?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"> + <!-- Save Customer and Assert Success Message --> + <actionGroup name="AdminCustomerSaveAndContinue" > + <click selector="{{AdminCustomerMainActionsSection.saveAndContinue}}" stepKey="saveAndContinue"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteAddressInCustomersAddressGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteAddressInCustomersAddressGridActionGroup.xml new file mode 100644 index 0000000000000..b61b353714e19 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteAddressInCustomersAddressGridActionGroup.xml @@ -0,0 +1,22 @@ +<?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"> + <!--Delete customer address from grid row, row starts at 0 --> + <actionGroup name="AdminDeleteAddressInCustomersAddressGrid"> + <arguments> + <argument name="row" type="string"/> + </arguments> + <click selector="{{AdminCustomerAddressesGridSection.checkboxByRow(row)}}" stepKey="clickRowCustomerAddressCheckbox"/> + <click selector="{{AdminCustomerAddressesGridSection.selectLinkByRow(row)}}" stepKey="openActionsDropdown"/> + <click selector="{{AdminCustomerAddressesGridSection.deleteLinkByRow(row)}}" stepKey="chooseDeleteOption"/> + <waitForPageLoad stepKey="waitForCustomerAddressesGridPageLoad"/> + <click selector="{{AdminCustomerAddressesGridActionsSection.ok}}" stepKey="clickOkOnPopup"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerAddressNoZipNoStateActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerAddressNoZipNoStateActionGroup.xml new file mode 100644 index 0000000000000..954b83bead1d3 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerAddressNoZipNoStateActionGroup.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="AdminEditCustomerAddressNoZipNoState" extends="AdminEditCustomerAddressesFrom"> + <remove keyForRemoval="selectState"/> + <remove keyForRemoval="fillZipCode"/> + <click selector="{{AdminEditCustomerAddressesSection.defaultBillingAddressButton}}" stepKey="setDefaultBilling" before="setDefaultShipping"/> + <click selector="{{AdminEditCustomerAddressesSection.defaultShippingAddressButton}}" stepKey="setDefaultShipping" before="fillPrefixName"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerAddressSetDefaultShippingAndBillingActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerAddressSetDefaultShippingAndBillingActionGroup.xml new file mode 100644 index 0000000000000..0c1af1cb5b67c --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerAddressSetDefaultShippingAndBillingActionGroup.xml @@ -0,0 +1,14 @@ +<?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="AdminEditCustomerAddressSetDefaultShippingAndBilling" extends="AdminEditCustomerAddressesFrom"> + <click selector="{{AdminEditCustomerAddressesSection.defaultBillingAddressButton}}" stepKey="setDefaultBilling" before="setDefaultShipping"/> + <click selector="{{AdminEditCustomerAddressesSection.defaultShippingAddressButton}}" stepKey="setDefaultShipping" before="fillPrefixName"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerAddressesFromActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerAddressesFromActionGroup.xml new file mode 100644 index 0000000000000..594337c1a6922 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerAddressesFromActionGroup.xml @@ -0,0 +1,42 @@ +<?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"> + <!-- Same as "EditCustomerAddressesFromAdminActionGroup" but taking country and state from input "customerAddress" --> + <actionGroup name="AdminEditCustomerAddressesFrom" > + <arguments> + <argument name="customerAddress" type="entity"/> + </arguments> + <click selector="{{AdminEditCustomerAddressesSection.addresses}}" stepKey="proceedToAddresses"/> + <click selector="{{AdminEditCustomerAddressesSection.addNewAddress}}" stepKey="addNewAddresses"/> + <waitForPageLoad time="60" stepKey="wait5678" /> + <fillField stepKey="fillPrefixName" userInput="{{customerAddress.prefix}}" selector="{{AdminEditCustomerAddressesSection.prefixName}}"/> + <fillField stepKey="fillMiddleName" userInput="{{customerAddress.middlename}}" selector="{{AdminEditCustomerAddressesSection.middleName}}"/> + <fillField stepKey="fillSuffixName" userInput="{{customerAddress.suffix}}" selector="{{AdminEditCustomerAddressesSection.suffixName}}"/> + <fillField stepKey="fillCompany" userInput="{{customerAddress.company}}" selector="{{AdminEditCustomerAddressesSection.company}}"/> + <fillField stepKey="fillStreetAddress" userInput="{{customerAddress.street[0]}}" selector="{{AdminEditCustomerAddressesSection.streetAddress}}"/> + <fillField stepKey="fillCity" userInput="{{customerAddress.city}}" selector="{{AdminEditCustomerAddressesSection.city}}"/> + <selectOption stepKey="selectCountry" selector="{{AdminEditCustomerAddressesSection.country}}" userInput="{{customerAddress.country_id}}"/> + <selectOption stepKey="selectState" selector="{{AdminEditCustomerAddressesSection.state}}" userInput="{{customerAddress.state}}"/> + <fillField stepKey="fillZipCode" userInput="{{customerAddress.postcode}}" selector="{{AdminEditCustomerAddressesSection.zipCode}}"/> + <fillField stepKey="fillPhone" userInput="{{customerAddress.telephone}}" selector="{{AdminEditCustomerAddressesSection.phone}}"/> + <fillField stepKey="fillVAT" userInput="{{customerAddress.vat_id}}" selector="{{AdminEditCustomerAddressesSection.vat}}"/> + <click selector="{{AdminEditCustomerAddressesSection.save}}" stepKey="saveAddress"/> + <waitForPageLoad stepKey="waitForAddressSaved"/> + </actionGroup> + <actionGroup name="AdminEditCustomerAddressSetDefaultShippingAndBilling" extends="AdminEditCustomerAddressesFrom"> + <click selector="{{AdminEditCustomerAddressesSection.defaultBillingAddressButton}}" stepKey="setDefaultBilling" before="setDefaultShipping"/> + <click selector="{{AdminEditCustomerAddressesSection.defaultShippingAddressButton}}" stepKey="setDefaultShipping" before="fillPrefixName"/> + </actionGroup> + <actionGroup name="AdminEditCustomerAddressNoZipNoState" extends="AdminEditCustomerAddressesFrom"> + <remove keyForRemoval="selectState"/> + <remove keyForRemoval="fillZipCode"/> + <click selector="{{AdminEditCustomerAddressesSection.defaultBillingAddressButton}}" stepKey="setDefaultBilling" before="setDefaultShipping"/> + <click selector="{{AdminEditCustomerAddressesSection.defaultShippingAddressButton}}" stepKey="setDefaultShipping" before="fillPrefixName"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerInformationFromActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerInformationFromActionGroup.xml new file mode 100644 index 0000000000000..ddeefeb3c3742 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminEditCustomerInformationFromActionGroup.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"> + <!-- Edit Customer Account Information Required Fields in Admin --> + <actionGroup name="AdminEditCustomerAccountInformationActionGroup" > + <arguments> + <argument name="firstName" type="string"/> + <argument name="lastName" type="string"/> + <argument name="email" type="string"/> + </arguments> + <click selector="{{AdminCustomerAccountInformationSection.accountInformationTab}}" stepKey="goToAccountInformation"/> + <clearField stepKey="clearFirstName" selector="{{AdminCustomerAccountInformationSection.firstName}}"/> + <fillField stepKey="fillFirstName" userInput="{{firstName}}" selector="{{AdminCustomerAccountInformationSection.firstName}}"/> + <clearField stepKey="clearLastName" selector="{{AdminCustomerAccountInformationSection.lastName}}"/> + <fillField stepKey="fillLastName" userInput="{{lastName}}" selector="{{AdminCustomerAccountInformationSection.lastName}}"/> + <clearField stepKey="clearEmail" selector="{{AdminCustomerAccountInformationSection.email}}"/> + <fillField stepKey="fillEmail" userInput="{{email}}" selector="{{AdminCustomerAccountInformationSection.email}}"/> + <click selector="{{AdminCustomerMainActionsSection.saveAndContinue}}" stepKey="saveAndContinue"/> + <waitForPageLoad stepKey="wait"/> + <scrollToTopOfPage stepKey="scrollToTop"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerAddressGridByPhoneNumberActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerAddressGridByPhoneNumberActionGroup.xml new file mode 100644 index 0000000000000..2d0d44a4cc529 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerAddressGridByPhoneNumberActionGroup.xml @@ -0,0 +1,21 @@ +<?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"> + <!--Filter customer address grid by phone number --> + <actionGroup name="AdminFilterCustomerAddressGridByPhoneNumber"> + <arguments> + <argument name="phone" type="string"/> + </arguments> + <conditionalClick selector="{{AdminCustomerAddressFiltersSection.clearAll}}" dependentSelector="{{AdminCustomerAddressFiltersSection.clearAll}}" visible="true" stepKey="clickClearFilters"/> + <click selector="{{AdminCustomerAddressFiltersSection.filtersButton}}" stepKey="openFilters"/> + <fillField selector="{{AdminCustomerAddressFiltersSection.telephoneInput}}" userInput="{{phone}}" stepKey="fill"/> + <click selector="{{AdminCustomerAddressFiltersSection.applyFilter}}" stepKey="clickApplyFilters"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGridByEmailActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGridByEmailActionGroup.xml new file mode 100644 index 0000000000000..9cab8a790ff58 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGridByEmailActionGroup.xml @@ -0,0 +1,21 @@ +<?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"> + <!--Filter customer grid by the email --> + <actionGroup name="AdminFilterCustomerGridByEmail"> + <arguments> + <argument name="email" type="string"/> + </arguments> + <conditionalClick selector="{{AdminCustomerFiltersSection.clearAll}}" dependentSelector="{{AdminCustomerFiltersSection.clearAll}}" visible="true" stepKey="clickClearFilters"/> + <click selector="{{AdminCustomerFiltersSection.filtersButton}}" stepKey="openFilters"/> + <fillField selector="{{AdminCustomerFiltersSection.emailInput}}" userInput="{{email}}" stepKey="fillEmail"/> + <click selector="{{AdminCustomerFiltersSection.apply}}" stepKey="clickApplyFilters"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminResetFilterInCustomerAddressGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminResetFilterInCustomerAddressGridActionGroup.xml new file mode 100644 index 0000000000000..135f010784199 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminResetFilterInCustomerAddressGridActionGroup.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"> + <!--Reset customers grid filter and to default view --> + <actionGroup name="AdminResetFilterInCustomerAddressGrid"> + <conditionalClick selector="{{AdminCustomerAddressFiltersSection.clearAll}}" dependentSelector="{{AdminCustomerAddressFiltersSection.clearAll}}" visible="true" stepKey="clickClearFilters"/> + <click selector="{{AdminCustomerAddressFiltersSection.viewDropdown}}" stepKey="openViewBookmarksTab"/> + <click selector="{{AdminCustomerAddressFiltersSection.viewBookmark('Default View')}}" stepKey="resetToDefaultGridView"/> + <waitForPageLoad stepKey="waitForGridLoad"/> + <see selector="{{AdminCustomerFiltersSection.viewDropdown}}" userInput="Default View" stepKey="seeDefaultViewSelected"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminResetFilterInCustomerGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminResetFilterInCustomerGridActionGroup.xml new file mode 100644 index 0000000000000..5c6ff347d565a --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminResetFilterInCustomerGridActionGroup.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"> + <!--Reset customers grid filter and to default view --> + <actionGroup name="AdminResetFilterInCustomerGrid"> + <conditionalClick selector="{{AdminCustomerFiltersSection.clearAll}}" dependentSelector="{{AdminCustomerFiltersSection.clearAll}}" visible="true" stepKey="clickClearFilters"/> + <click selector="{{AdminCustomerFiltersSection.viewDropdown}}" stepKey="openViewBookmarksTab"/> + <click selector="{{AdminCustomerFiltersSection.viewBookmark('Default View')}}" stepKey="resetToDefaultGridView"/> + <waitForPageLoad stepKey="waitForGridLoad"/> + <see selector="{{AdminCustomerFiltersSection.viewDropdown}}" userInput="Default View" stepKey="seeDefaultViewSelected"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminSaveCustomerAndAssertSuccessMessageActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminSaveCustomerAndAssertSuccessMessageActionGroup.xml new file mode 100644 index 0000000000000..d3907e96b0d77 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminSaveCustomerAndAssertSuccessMessageActionGroup.xml @@ -0,0 +1,15 @@ +<?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"> + <!-- Save Customer and Assert Success Message --> + <actionGroup name="AdminSaveCustomerAndAssertSuccessMessage" > + <click selector="{{AdminCustomerMainActionsSection.saveButton}}" stepKey="saveCustomer"/> + <see userInput="You saved the customer" selector="{{AdminCustomerMessagesSection.successMessage}}" stepKey="seeMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/LoginToStorefrontWithEmailAndPasswordActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/LoginToStorefrontWithEmailAndPasswordActionGroup.xml index 33852fcf80864..071450001051e 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/LoginToStorefrontWithEmailAndPasswordActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/LoginToStorefrontWithEmailAndPasswordActionGroup.xml @@ -13,6 +13,7 @@ <argument name="password" type="string"/> </arguments> <amOnPage stepKey="amOnSignInPage" url="{{StorefrontCustomerSignInPage.url}}"/> + <waitForPageLoad stepKey="wait"/> <fillField stepKey="fillEmail" userInput="{{email}}" selector="{{StorefrontCustomerSignInFormSection.emailField}}"/> <fillField stepKey="fillPassword" userInput="{{password}}" selector="{{StorefrontCustomerSignInFormSection.passwordField}}"/> <click stepKey="clickSignInAccountButton" selector="{{StorefrontCustomerSignInFormSection.signInAccountButton}}"/> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/OpenEditCustomerFromAdminActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/OpenEditCustomerFromAdminActionGroup.xml index af918e8208566..14bda9ebe5b36 100755 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/OpenEditCustomerFromAdminActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/OpenEditCustomerFromAdminActionGroup.xml @@ -5,6 +5,7 @@ * 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="OpenEditCustomerFromAdminActionGroup"> @@ -12,13 +13,13 @@ <argument name="customer"/> </arguments> <amOnPage url="{{AdminCustomerPage.url}}" stepKey="navigateToCustomers"/> - <waitForPageLoad stepKey="waitForPageLoad1" /> + <waitForPageLoad stepKey="waitForPageLoad1"/> <click selector="{{AdminCustomerFiltersSection.filtersButton}}" stepKey="openFilter"/> <fillField userInput="{{customer.email}}" selector="{{AdminCustomerFiltersSection.emailInput}}" stepKey="filterEmail"/> <click selector="{{AdminCustomerFiltersSection.apply}}" stepKey="applyFilter"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickEdit"/> - <waitForPageLoad stepKey="waitForPageLoad2" /> + <waitForPageLoad stepKey="waitForPageLoad3"/> </actionGroup> <actionGroup name="OpenEditCustomerAddressFromAdminActionGroup"> <arguments> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontAssertSuccessLoginToStorefrontActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontAssertSuccessLoginToStorefrontActionGroup.xml new file mode 100644 index 0000000000000..475702ad69221 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontAssertSuccessLoginToStorefrontActionGroup.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="StorefrontAssertSuccessLoginToStorefront" extends="LoginToStorefrontActionGroup"> + <arguments> + <argument name="Customer" type="entity"/> + </arguments> + <see stepKey="assertWelcome" userInput="{{Customer.firstname}}" selector="{{StorefrontPanelHeaderSection.customerWelcome}}" after="clickSignInAccountButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerAddressBookContainsActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerAddressBookContainsActionGroup.xml new file mode 100644 index 0000000000000..8385dc17ecf98 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerAddressBookContainsActionGroup.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"> + <!-- Go to Address Book --> + <actionGroup name="StorefrontCustomerAddressBookContains"> + <arguments> + <argument name="text" type="string"/> + </arguments> + <see userInput="{{text}}" selector="{{StorefrontCustomerAddressesSection.addressesList}}" stepKey="containsText"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerAddressBookNotContainsActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerAddressBookNotContainsActionGroup.xml new file mode 100644 index 0000000000000..afef2d9a04e34 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerAddressBookNotContainsActionGroup.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"> + <!-- Go to Address Book --> + <actionGroup name="StorefrontCustomerAddressBookNotContains"> + <arguments> + <argument name="text" type="string"/> + </arguments> + <dontSee userInput="{{text}}" selector="{{StorefrontCustomerAddressesSection.addressesList}}" stepKey="doesNotContainsText"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerAddressBookNumberOfAddressesActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerAddressBookNumberOfAddressesActionGroup.xml new file mode 100644 index 0000000000000..febc482d62e8b --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerAddressBookNumberOfAddressesActionGroup.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"> + <!-- Go to Address Book --> + <actionGroup name="StorefrontCustomerAddressBookNumberOfAddresses"> + <arguments> + <argument name="number" type="string"/> + </arguments> + <see userInput="{{number}} Item" selector="{{StorefrontCustomerAddressesSection.numberOfAddresses}}" stepKey="checkNumberOfAddresses"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerGoToSidebarMenuActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerGoToSidebarMenuActionGroup.xml new file mode 100644 index 0000000000000..84d2f353b51d2 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/StorefrontCustomerGoToSidebarMenuActionGroup.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"> + <!-- Go to Address Book --> + <actionGroup name="StorefrontCustomerGoToSidebarMenu"> + <arguments> + <argument name="menu" type="string"/> + </arguments> + <click selector="{{StorefrontCustomerSidebarSection.sidebarTab(menu)}}" stepKey="goToAddressBook"/> + <waitForPageLoad stepKey="waitForPageLoad" /> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index e456ddbec5d4d..5d1a900167144 100755 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -191,6 +191,23 @@ <data key="default_billing">true</data> <data key="default_shipping">false</data> </entity> + <entity name="addressNoZipNoState" type="address"> + <data key="country_id">United Kingdom</data> + <array key="street"> + <item>3962 Horner Street</item> + </array> + <data key="company">Magento</data> + <data key="telephone">334-200-4061</data> + <data key="city">London</data> + <data key="firstname">Fn</data> + <data key="lastname">Ln</data> + <data key="middlename">Mn</data> + <data key="prefix">Mr</data> + <data key="suffix">Sr</data> + <data key="vat_id">U1234567891</data> + <data key="default_shipping">true</data> + <data key="default_billing">true</data> + </entity> <entity name="updateCustomerUKAddress" type="address"> <data key="firstname">John</data> <data key="lastname">Doe</data> @@ -237,4 +254,21 @@ <data key="state">Colorado</data> <data key="postcode">12345</data> </entity> -</entities> \ No newline at end of file + <entity name="PolandAddress" type="address"> + <data key="firstname">Mag</data> + <data key="lastname">Ento</data> + <data key="company">Magento</data> + <array key="street"> + <item>Piwowarska 6</item> + </array> + <data key="city">Bielsko-Biała</data> + <data key="state"> Bielsko</data> + <data key="country_id">PL</data> + <data key="country">Poland</data> + <data key="postcode">43-310</data> + <data key="telephone">799885616</data> + <data key="default_billing">Yes</data> + <data key="default_shipping">Yes</data> + <requiredEntity type="region">RegionUT</requiredEntity> + </entity> +</entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/CustomerGroupData.xml b/app/code/Magento/Customer/Test/Mftf/Data/CustomerGroupData.xml index 6b4f3fc9d6b6e..9b6155e982013 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/CustomerGroupData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/CustomerGroupData.xml @@ -23,4 +23,9 @@ <item>General</item> </array> </entity> + <entity name="CustomCustomerGroup" type="customerGroup"> + <data key="code" unique="suffix">Group </data> + <data key="tax_class_id">3</data> + <data key="tax_class_name">Retail Customer</data> + </entity> </entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Metadata/customer_group-meta.xml b/app/code/Magento/Customer/Test/Mftf/Metadata/customer_group-meta.xml new file mode 100644 index 0000000000000..3139ea278a0dd --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Metadata/customer_group-meta.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateCustomerGroup" dataType="customerGroup" type="create" auth="adminOauth" url="/V1/customerGroups" method="POST"> + <contentType>application/json</contentType> + <object dataType="customerGroup" key="group"> + <field key="code">string</field> + <field key="tax_class_id">integer</field> + <field key="tax_class_name">string</field> + </object> + </operation> + <operation name="DeleteCustomerGroup" dataType="customerGroup" type="delete" auth="adminOauth" url="/V1/customerGroups/{id}" method="DELETE"> + <contentType>application/json</contentType> + </operation> +</operations> \ No newline at end of file diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml index 6a3687bb77c8f..71e3e673477d2 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountInformationSection.xml @@ -9,7 +9,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminCustomerAccountInformationSection"> - <element name="accountInformationTab" type="button" selector="#tab_customer"/> + <element name="accountInformationTab" type="button" selector="#tab_customer" timeout="30"/> <element name="statusInactive" type="button" selector=".admin__actions-switch-label"/> <element name="accountInformationTitle" type="text" selector=".admin__page-nav-title"/> <element name="accountInformationButton" type="text" selector="//a/span[text()='Account Information']"/> @@ -18,10 +18,18 @@ <element name="lastName" type="input" selector="input[name='customer[lastname]']"/> <element name="email" type="input" selector="input[name='customer[email]']"/> <element name="group" type="select" selector="[name='customer[group_id]']"/> + <element name="groupIdValue" type="text" selector="//*[@name='customer[group_id]']/option"/> <element name="groupValue" type="button" selector="//span[text()='{{groupValue}}']" parameterized="true"/> <element name="associateToWebsite" type="select" selector="//select[@name='customer[website_id]']"/> <element name="saveCustomer" type="button" selector="//button[@title='Save Customer']"/> <element name="saveCustomerAndContinueEdit" type="button" selector="//button[@title='Save and Continue Edit']"/> <element name="storeView" type="select" selector="//select[@name='customer[sendemail_store_id]']"/> + <element name="namePrefix" type="input" selector="//input[contains(@name, 'customer[prefix]')]"/> + <element name="nameSuffix" type="input" selector="//input[contains(@name, 'customer[suffix]')]"/> + <element name="dateOfBirth" type="input" selector="//input[contains(@name, 'customer[dob]')]"/> + <element name="gender" type="select" selector="//select[contains(@name, 'customer[gender]')]"/> + <element name="firstNameRequiredMessage" type="text" selector="//input[@name='customer[firstname]']/../label[contains(.,'This is a required field.')]"/> + <element name="lastNameRequiredMessage" type="text" selector="//input[@name='customer[lastname]']/../label[contains(.,'This is a required field.')]"/> + <element name="emailRequiredMessage" type="text" selector="//input[@name='customer[email]']/../label[contains(.,'This is a required field.')]"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressFiltersSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressFiltersSection.xml index b9a3839ff9894..f3df6cc5e8c00 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressFiltersSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressFiltersSection.xml @@ -20,5 +20,7 @@ <element name="telephoneInput" type="input" selector="input[name=telephone]"/> <element name="applyFilter" type="button" selector="button[data-action=grid-filter-apply]" timeout="30"/> <element name="clearAll" type="button" selector=".admin__data-grid-header .action-tertiary.action-clear" timeout="30"/> + <element name="viewDropdown" type="button" selector=".admin__data-grid-action-bookmarks button.admin__action-dropdown"/> + <element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressGridSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressGridSection.xml index fb153a7c102a5..e639fca834b2b 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressGridSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressGridSection.xml @@ -12,6 +12,5 @@ <element name="customerGrid" type="text" selector="table[data-role='grid']"/> <element name="firstRowSelectActionLink" type="text" selector="tr[data-repeat-index='0'] .action-select" timeout="30"/> <element name="firstRowEditActionLink" type="text" selector="tr[data-repeat-index='0'] [data-action='item-edit']" timeout="30"/> - </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesGridActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesGridActionsSection.xml index d8d93814333ca..e743c4af66d9f 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesGridActionsSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesGridActionsSection.xml @@ -12,9 +12,10 @@ <element name="spinner" type="button" selector=".spinner"/> <element name="gridLoadingMask" type="button" selector=".admin__data-grid-loading-mask"/> <element name="search" type="input" selector="#fulltext"/> - <element name="delete" type="button" selector="//*[contains(@class, 'admin__data-grid-header')]//span[contains(@class,'action-menu-item') and text()='Delete']"/> + <element name="delete" type="button" selector="//*[contains(@class, 'admin__data-grid-header')]//span[contains(@class,'action-menu-item') and text()='Delete']" timeout="30"/> <element name="actions" type="text" selector="//div[@class='admin__data-grid-header']//button[@class='action-select']"/> <element name="filters" type="button" selector="button[data-action='grid-filter-expand']" timeout="30"/> - <element name="ok" type="button" selector="//button[@data-role='action']//span[text()='OK']"/> + <element name="ok" type="button" selector="//button[@data-role='action']//span[text()='OK']" timeout="30"/> + <element name="headerRow" type="text" selector=".admin__data-grid-header-row.row.row-gutter"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesGridSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesGridSection.xml index 85c086d01848b..5393d6c1ab9b9 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesGridSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesGridSection.xml @@ -19,5 +19,8 @@ <element name="secondRowCheckbox" type="checkbox" selector="//tr[contains(@data-repeat-index, '1')]//input[contains(@data-action, 'select-row')]"/> <element name="checkboxByName" type="checkbox" selector="//div[contains(text(),'{{customer}}')]/ancestor::tr[contains(@class, 'data-row')]//input[@class='admin__control-checkbox']" parameterized="true" /> <element name="rowsInGrid" type="text" selector="//tr[contains(@class,'data-row')]"/> + <element name="checkboxByRow" type="checkbox" selector="//tr[contains(@data-repeat-index, '{{row}}')]//input[contains(@data-action, 'select-row')]" parameterized="true"/> + <element name="selectLinkByRow" type="text" selector="//tr[contains(@data-repeat-index, '{{row}}')]//button[@class='action-select']" parameterized="true"/> + <element name="deleteLinkByRow" type="text" selector="//tr[contains(@data-repeat-index, '{{row}}')]//a[contains(@data-action,'item-delete')]" parameterized="true" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesSection.xml index 8068f94032730..26df107708c47 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAddressesSection.xml @@ -30,5 +30,10 @@ <element name="customerAddressRow" type="input" selector="//tbody//tr//td//div[contains(., '{{var1}}')]" parameterized="true"/> <element name="deleteButton" type="button" selector="//button[@id='delete']"/> <element name="ok" type="button" selector="//button[@data-role='action']//span[text()='OK']"/> + <element name="streetRequiredMessage" type="text" selector="//input[@name='street[0]']/../label[contains(.,'This is a required field.')]"/> + <element name="cityRequiredMessage" type="text" selector="//input[@name='city']/../label[contains(.,'This is a required field.')]"/> + <element name="countryRequiredMessage" type="text" selector="//select[@name='country_id']/../label[contains(.,'This is a required field.')]"/> + <element name="postcodeRequiredMessage" type="text" selector="//input[@name='postcode']/../label[contains(.,'This is a required field.')]"/> + <element name="phoneNumberRequiredMessage" type="text" selector="//input[@name='telephone']/../label[contains(.,'This is a required field.')]"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerFiltersSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerFiltersSection.xml index 02d9bc2eb5f12..25617ca05dd44 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerFiltersSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerFiltersSection.xml @@ -16,5 +16,7 @@ <element name="apply" type="button" selector="button[data-action=grid-filter-apply]" timeout="30"/> <element name="clearAllFilters" type="text" selector=".admin__current-filters-actions-wrap.action-clear"/> <element name="clearAll" type="button" selector=".admin__data-grid-header .action-tertiary.action-clear" timeout="30"/> + <element name="viewDropdown" type="button" selector=".admin__data-grid-action-bookmarks button.admin__action-dropdown"/> + <element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridSection.xml index ad35f4bdfa28e..91363c614c1f8 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridSection.xml @@ -11,9 +11,10 @@ <section name="AdminCustomerGridSection"> <element name="customerGrid" type="text" selector="table[data-role='grid']"/> <element name="firstRowEditLink" type="text" selector="tr[data-repeat-index='0'] .action-menu-item" timeout="30"/> + <element name="gridRow" type="text" selector="//*[@data-role='sticky-el-root']/parent::div/parent::div/following-sibling::div//tbody//*[@class='data-row'][{{row}}]" parameterized="true"/> <element name="selectFirstRow" type="checkbox" selector="//td[@class='data-grid-checkbox-cell']"/> <element name="customerCheckboxByEmail" type="checkbox" selector="//tr[@class='data-row' and //div[text()='{{customerEmail}}']]//input[@type='checkbox']" parameterized="true" timeout="30"/> <element name="customerEditLinkByEmail" type="text" selector="//tr[@class='data-row' and //div[text()='{{customerEmail}}']]//a[@class='action-menu-item']" parameterized="true" timeout="30"/> <element name="customerGroupByEmail" type="text" selector="//tr[@class='data-row' and //div[text()='{{customerEmail}}']]//div[text()='{{customerGroup}}']" parameterized="true"/> </section> -</sections> \ No newline at end of file +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerMainActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerMainActionsSection.xml index 0a56763b66704..304068d89b729 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerMainActionsSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerMainActionsSection.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminCustomerMainActionsSection"> <element name="saveButton" type="button" selector="#save" timeout="30"/> + <element name="saveAndContinue" type="button" selector="#save_and_continue" timeout="30"/> <element name="resetPassword" type="button" selector="#resetPassword" timeout="30"/> <element name="manageShoppingCart" type="button" selector="#manage_quote" timeout="30"/> </section> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminEditCustomerAddressesSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminEditCustomerAddressesSection.xml index 04d6c4dc2a09d..ffddc6292ef5d 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminEditCustomerAddressesSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminEditCustomerAddressesSection.xml @@ -13,6 +13,8 @@ <element name="addNewAddress" type="button" selector="//span[text()='Add New Address']"/> <element name="defaultBillingAddress" type="text" selector="input[name='default_billing']"/> <element name="defaultShippingAddress" type="text" selector="input[name='default_shipping']"/> + <element name="defaultBillingAddressButton" type="text" selector="//input[@name='default_billing']/following-sibling::label"/> + <element name="defaultShippingAddressButton" type="text" selector="//input[@name='default_shipping']/following-sibling::label"/> <element name="prefixName" type="text" selector="input[name='prefix']"/> <element name="firstName" type="text" selector="input[name='firstname']" /> <element name="middleName" type="text" selector="input[name='middlename']" /> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminEditCustomerInformationSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminEditCustomerInformationSection.xml index 8ae4552860f59..1c5bbc76e4d6e 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminEditCustomerInformationSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminEditCustomerInformationSection.xml @@ -13,5 +13,6 @@ <element name="addresses" type="button" selector="//a[@id='tab_address']" timeout="30"/> <element name="newsLetter" type="button" selector="//a[@class='admin__page-nav-link' and @id='tab_newsletter_content']" timeout="30"/> <element name="group" type="text" selector="//th[text()='Customer Group:']/../td"/> + <element name="customerTitle" type="text" selector="h1.page-title"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerAddressesSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerAddressesSection.xml index 29a2f549274a7..aad9d02842271 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerAddressesSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerAddressesSection.xml @@ -17,5 +17,6 @@ <element name="deleteAdditionalAddress" type="button" selector="//tbody//tr[{{var}}]//a[@class='action delete']" parameterized="true"/> <element name="editAdditionalAddress" type="button" selector="//tbody//tr[{{var}}]//a[@class='action edit']" parameterized="true" timeout="30"/> <element name="addNewAddress" type="button" selector="//span[text()='Add New Address']"/> + <element name="numberOfAddresses" type="text" selector=".toolbar-number"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerRetailerWithoutAddressTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerRetailerWithoutAddressTest.xml new file mode 100644 index 0000000000000..36592ab38e91d --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerRetailerWithoutAddressTest.xml @@ -0,0 +1,63 @@ +<?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="AdminCreateCustomerRetailerWithoutAddressTest"> + <annotations> + <stories value="Create customer"/> + <title value="Create customer, retailer without address"/> + <description value="Login as admin and create customer retailer without address"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5310"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + </before> + <after> + <actionGroup ref="DeleteCustomerByEmailActionGroup" stepKey="deleteCustomer"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Filter the customer From grid--> + <amOnPage url="{{AdminNewCustomerPage.url}}" stepKey="navigateToNewCustomerPage"/> + <waitForPageLoad time="30" stepKey="waitToCustomerPageLoad"/> + <selectOption selector="{{AdminCustomerAccountInformationSection.group}}" userInput="Retailer" stepKey="fillCustomerGroup"/> + <fillField userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminCustomerAccountInformationSection.firstName}}" stepKey="fillFirstName"/> + <fillField userInput="{{CustomerEntityOne.lastname}}" selector="{{AdminCustomerAccountInformationSection.lastName}}" stepKey="fillLastName"/> + <fillField userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerAccountInformationSection.email}}" stepKey="fillEmail"/> + <click selector="{{AdminCustomerMainActionsSection.saveButton}}" stepKey="saveCustomer"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> + <seeElement selector="{{AdminCustomerMessagesSection.successMessage}}" stepKey="assertSuccessMessage"/> + <reloadPage stepKey="reloadPage"/> + + <!--Verify Customer in grid --> + <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail1"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <waitForPageLoad stepKey="waitForCustomerPageToLoad"/> + <see selector="{{AdminCustomerGridSection.customerGrid}}" userInput="Retailer" stepKey="assertGroup"/> + <see userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertFirstName"/> + <see userInput="{{CustomerEntityOne.lastname}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertLastName"/> + <see userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertEmail"/> + + <!--Assert Customer Form --> + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> + <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> + <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> + <see selector="{{AdminCustomerAccountInformationSection.groupIdValue}}" userInput="Retailer" stepKey="seeCustomerGroup1"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="seeCustomerFirstName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="seeCustomerLastName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="seeCustomerEmail"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryPolandTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryPolandTest.xml new file mode 100644 index 0000000000000..cbc8b89d3f242 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryPolandTest.xml @@ -0,0 +1,92 @@ +<?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="AdminCreateCustomerWithCountryPolandTest"> + <annotations> + <stories value="Create customer"/> + <title value="Create customer, from Poland"/> + <description value="Login as admin and create customer with Poland address"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5311"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + <createData entity="Simple_Customer_Without_Address" stepKey="createCustomer"/> + </before> + <after> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Filter the created customer From grid--> + <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail"> + <argument name="email" value="$$createCustomer.email$$"/> + </actionGroup> + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton"/> + <waitForPageLoad stepKey="waitForCustomerEditPageToLoad"/> + + <!--Add the Address --> + <click selector="{{AdminEditCustomerAddressesSection.addresses}}" stepKey="selectAddress"/> + <waitForPageLoad stepKey="waitForAddressPageToLoad"/> + <click selector="{{AdminEditCustomerAddressesSection.addNewAddress}}" stepKey="ClickOnAddNewAddressButton"/> + <waitForPageLoad stepKey="waitForNewAddressPageToLoad"/> + <checkOption selector="{{AdminCustomerAddressesSection.defaultBillingAddress}}" stepKey="EnableDefaultBillingAddress"/> + <fillField selector="{{AdminEditCustomerAddressesSection.streetAddress}}" userInput="{{PolandAddress.street}}" stepKey="fillStreetAddress"/> + <fillField selector="{{AdminEditCustomerAddressesSection.city}}" userInput="{{PolandAddress.city}}" stepKey="fillCity"/> + <scrollTo selector="{{AdminEditCustomerAddressesSection.phone}}" x="0" y="-80" stepKey="scrollToPhone"/> + <selectOption selector="{{AdminEditCustomerAddressesSection.country}}" userInput="{{PolandAddress.country}}" stepKey="fillCountry"/> + <fillField selector="{{AdminEditCustomerAddressesSection.zipCode}}" userInput="{{PolandAddress.postcode}}" stepKey="fillPostCode"/> + <fillField selector="{{AdminEditCustomerAddressesSection.phone}}" userInput="{{PolandAddress.telephone}}" stepKey="fillPhoneNumber"/> + <scrollToTopOfPage stepKey="scrollToTopOfPage"/> + <click selector="{{AdminEditCustomerAddressesSection.save}}" stepKey="clickOnSaveButton"/> + <waitForPageLoad stepKey="waitForPageToBeSaved"/> + <click selector="{{AdminCustomerMainActionsSection.saveButton}}" stepKey="saveCustomer"/> + <seeElement selector="{{AdminCustomerMessagesSection.successMessage}}" stepKey="assertSuccessMessage"/> + + <!-- Assert Customer in grid --> + <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail1"> + <argument name="email" value="$$createCustomer.email$$"/> + </actionGroup> + <waitForPageLoad stepKey="waitForPageToLoad"/> + <see userInput="$$createCustomer.firstname$$" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertFirstName"/> + <see userInput="$$createCustomer.lastname$$" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertLastName"/> + <see userInput="$$createCustomer.email$$" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertEmail"/> + <see userInput="{{PolandAddress.country}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertCountry"/> + <see userInput="{{PolandAddress.postcode}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertPostCode"/> + <see userInput="{{PolandAddress.telephone}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertPhoneNumber"/> + + <!--Assert Customer Form --> + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> + <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> + <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="$$createCustomer.firstname$$" stepKey="seeCustomerFirstName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.lastName}}" userInput="$$createCustomer.lastname$$" stepKey="seeCustomerLastName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.email}}" userInput="$$createCustomer.email$$" stepKey="seeCustomerEmail"/> + <click selector="{{AdminCustomerAccountInformationSection.addressesButton}}" stepKey="clickOnAddressButton"/> + <waitForPageLoad stepKey="waitForAddressGridToLoad"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="$$createCustomer.firstname$$" stepKey="seeAFirstNameInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="$$createCustomer.lastname$$" stepKey="seeLastNameInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{PolandAddress.street}}" stepKey="seeStreetInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{PolandAddress.city}}" stepKey="seeLCityInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{PolandAddress.country}}" stepKey="seeCountrynDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{PolandAddress.postcode}}" stepKey="seePostCodeInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{PolandAddress.telephone}}" stepKey="seePhoneNumberInDefaultAddressSection"/> + + <!--Assert Customer Address Grid --> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{PolandAddress.street}}" stepKey="seeStreetAddress"/> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{PolandAddress.city}}" stepKey="seeCity"/> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{PolandAddress.country}}" stepKey="seeCountry"/> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{PolandAddress.postcode}}" stepKey="seePostCode"/> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{PolandAddress.telephone}}" stepKey="seePhoneNumber"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml new file mode 100644 index 0000000000000..43f2aa7f8de95 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml @@ -0,0 +1,95 @@ +<?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="AdminCreateCustomerWithCountryUSATest"> + <annotations> + <stories value="Create customer"/> + <title value="Create customer, from USA"/> + <description value="Login as admin and create customer with USA address"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5309"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + <createData entity="Simple_Customer_Without_Address" stepKey="createCustomer"/> + </before> + <after> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Filter the customer From grid--> + <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail"> + <argument name="email" value="$$createCustomer.email$$"/> + </actionGroup> + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton"/> + <waitForPageLoad stepKey="waitForCustomerEditPageToLoad"/> + + <!-- Add the Address --> + <click selector="{{AdminEditCustomerAddressesSection.addresses}}" stepKey="selectAddress"/> + <waitForPageLoad stepKey="waitForAddressPageToLoad"/> + <click selector="{{AdminEditCustomerAddressesSection.addNewAddress}}" stepKey="ClickOnAddNewAddressButton"/> + <waitForPageLoad stepKey="waitForNewAddressPageToLoad"/> + <checkOption selector="{{AdminCustomerAddressesSection.defaultBillingAddress}}" stepKey="EnableDefaultBillingAddress"/> + <fillField selector="{{AdminEditCustomerAddressesSection.streetAddress}}" userInput="{{US_Address_CA.street}}" stepKey="fillStreetAddress"/> + <fillField selector="{{AdminEditCustomerAddressesSection.city}}" userInput="{{US_Address_CA.city}}" stepKey="fillCity"/> + <scrollTo selector="{{AdminEditCustomerAddressesSection.phone}}" x="0" y="-80" stepKey="scrollToPhone"/> + <selectOption selector="{{AdminEditCustomerAddressesSection.country}}" userInput="{{US_Address_CA.country}}" stepKey="fillCountry"/> + <selectOption selector="{{AdminEditCustomerAddressesSection.state}}" userInput="{{US_Address_CA.state}}" stepKey="fillState"/> + <fillField selector="{{AdminEditCustomerAddressesSection.zipCode}}" userInput="{{US_Address_CA.postcode}}" stepKey="fillPostCode"/> + <fillField selector="{{AdminEditCustomerAddressesSection.phone}}" userInput="{{US_Address_CA.telephone}}" stepKey="fillPhoneNumber"/> + <scrollToTopOfPage stepKey="scrollToTopOfPage"/> + <click selector="{{AdminEditCustomerAddressesSection.save}}" stepKey="clickOnSaveButton"/> + <waitForPageLoad stepKey="waitForPageToBeSaved"/> + <click selector="{{AdminCustomerMainActionsSection.saveButton}}" stepKey="saveCustomer"/> + <seeElement selector="{{AdminCustomerMessagesSection.successMessage}}" stepKey="assertSuccessMessage"/> + + <!-- Assert Customer in grid --> + <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail1"> + <argument name="email" value="$$createCustomer.email$$"/> + </actionGroup> + <waitForPageLoad stepKey="waitForPageToLoad"/> + <see userInput="$$createCustomer.firstname$$" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertFirstName"/> + <see userInput="$$createCustomer.lastname$$" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertLastName"/> + <see userInput="$$createCustomer.email$$" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertEmail"/> + <see userInput="{{US_Address_CA.state}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertState"/> + <see userInput="{{US_Address_CA.country}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertCountry"/> + <see userInput="{{US_Address_CA.postcode}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertPostCode"/> + <see userInput="{{US_Address_CA.telephone}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertPhoneNumber"/> + + <!--Assert Customer Form --> + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> + <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> + <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="$$createCustomer.firstname$$" stepKey="seeCustomerFirstName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.lastName}}" userInput="$$createCustomer.lastname$$" stepKey="seeCustomerLastName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.email}}" userInput="$$createCustomer.email$$" stepKey="seeCustomerEmail"/> + <click selector="{{AdminCustomerAccountInformationSection.addressesButton}}" stepKey="clickOnAddressButton"/> + <waitForPageLoad stepKey="waitForAddressGridToLoad"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="$$createCustomer.firstname$$" stepKey="seeAFirstNameInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="$$createCustomer.lastname$$" stepKey="seeLastNameInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{US_Address_CA.street}}" stepKey="seeStreetInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{US_Address_CA.city}}" stepKey="seeLCityInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{US_Address_CA.country}}" stepKey="seeCountrynDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{US_Address_CA.postcode}}" stepKey="seePostCodeInDefaultAddressSection"/> + <see selector="{{AdminCustomerAddressesDefaultBillingSection.addressDetails}}" userInput="{{US_Address_CA.telephone}}" stepKey="seePhoneNumberInDefaultAddressSection"/> + + <!--Assert Customer Address Grid --> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{US_Address_CA.street}}" stepKey="seeStreetAddress"/> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{US_Address_CA.city}}" stepKey="seeCity"/> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{US_Address_CA.country}}" stepKey="seeCountry"/> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{US_Address_CA.state}}" stepKey="seeState"/> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{US_Address_CA.postcode}}" stepKey="seePostCode"/> + <see selector="{{AdminCustomerAddressesGridSection.customerAddressGrid}}" userInput="{{US_Address_CA.telephone}}" stepKey="seePhoneNumber"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCustomGroupTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCustomGroupTest.xml new file mode 100644 index 0000000000000..872da149ed0b2 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCustomGroupTest.xml @@ -0,0 +1,65 @@ +<?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="AdminCreateCustomerWithCustomGroupTest"> + <annotations> + <stories value="Create customer"/> + <title value="Create customer, with custom group"/> + <description value="Login as admin and create customer with custom group"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5313"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="CustomCustomerGroup" stepKey="customerGroup" /> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + </before> + <after> + <actionGroup ref="DeleteCustomerByEmailActionGroup" stepKey="deleteCustomer"> + <argument name="email" value="{{CustomerEntityOne.email}}" /> + </actionGroup> + <deleteData createDataKey="customerGroup" stepKey="deleteCustomerGroup"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Open New Customer Page --> + <amOnPage url="{{AdminNewCustomerPage.url}}" stepKey="navigateToNewCustomerPage"/> + <waitForPageLoad stepKey="waitToCustomerPageLoad"/> + <selectOption selector="{{AdminCustomerAccountInformationSection.group}}" userInput="$$customerGroup.code$$" stepKey="fillCustomerGroup"/> + <fillField userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminCustomerAccountInformationSection.firstName}}" stepKey="fillFirstName"/> + <fillField userInput="{{CustomerEntityOne.lastname}}" selector="{{AdminCustomerAccountInformationSection.lastName}}" stepKey="fillLastName"/> + <fillField userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerAccountInformationSection.email}}" stepKey="fillEmail"/> + <click selector="{{AdminCustomerMainActionsSection.saveButton}}" stepKey="saveCustomer"/> + <seeElement selector="{{AdminCustomerMessagesSection.successMessage}}" stepKey="assertSuccessMessage"/> + <magentoCLI stepKey="flushMagentoCache" command="cache:flush" /> + <reloadPage stepKey="reloadPage"/> + + <!--Verify Customer in grid --> + <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail1"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <waitForPageLoad stepKey="waitForCustomerPageToLoad"/> + <see selector="{{AdminCustomerGridSection.customerGrid}}" userInput="$$customerGroup.code$$" stepKey="assertGroup"/> + <see userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertFirstName"/> + <see userInput="{{CustomerEntityOne.lastname}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertLastName"/> + <see userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertEmail"/> + + <!--Assert Customer Form --> + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> + <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> + <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> + <see selector="{{AdminCustomerAccountInformationSection.groupIdValue}}" userInput="$$customerGroup.code$$" stepKey="seeCustomerGroup1"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="seeCustomerFirstName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="seeCustomerLastName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="seeCustomerEmail"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithPrefixTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithPrefixTest.xml new file mode 100644 index 0000000000000..1b901a7b3e1cd --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithPrefixTest.xml @@ -0,0 +1,70 @@ +<?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="AdminCreateCustomerWithPrefixTest"> + <annotations> + <stories value="Create customer"/> + <title value="Create customer, with prefix"/> + <description value="Login as admin and create a customer with name prefix and suffix"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5308"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + </before> + <after> + <actionGroup ref="DeleteCustomerByEmailActionGroup" stepKey="deleteCustomer"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Open New Customer Page and create a customer with Prefix and Suffix--> + <amOnPage url="{{AdminNewCustomerPage.url}}" stepKey="navigateToNewCustomerPage"/> + <waitForPageLoad stepKey="waitToCustomerPageLoad"/> + <selectOption selector="{{AdminCustomerAccountInformationSection.group}}" userInput="Wholesale" stepKey="fillCustomerGroup"/> + <fillField selector="{{AdminCustomerAccountInformationSection.namePrefix}}" userInput="{{CustomerEntityOne.prefix}}" stepKey="fillNamePrefix"/> + <fillField userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminCustomerAccountInformationSection.firstName}}" stepKey="fillFirstName"/> + <fillField userInput="{{CustomerEntityOne.lastname}}" selector="{{AdminCustomerAccountInformationSection.lastName}}" stepKey="fillLastName"/> + <fillField selector="{{AdminCustomerAccountInformationSection.nameSuffix}}" userInput="{{CustomerEntityOne.suffix}}" stepKey="fillNameSuffix"/> + <fillField userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerAccountInformationSection.email}}" stepKey="fillEmail"/> + <fillField userInput="{{CustomerEntityOne.dob}}" selector="{{AdminCustomerAccountInformationSection.dateOfBirth}}" stepKey="fillDateOfBirth"/> + <selectOption userInput="Male" selector="{{AdminCustomerAccountInformationSection.gender}}" stepKey="fillGender"/> + <click selector="{{AdminCustomerMainActionsSection.saveButton}}" stepKey="saveCustomer"/> + <seeElement selector="{{AdminCustomerMessagesSection.successMessage}}" stepKey="assertSuccessMessage"/> + <reloadPage stepKey="reloadPage"/> + + <!--Filter the customer From grid--> + <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <waitForPageLoad stepKey="waitForPageToLoad"/> + + <!-- Assert Customer in grid --> + <see userInput="{{CustomerEntityOne.prefix}} {{CustomerEntityOne.firstname}} {{CustomerEntityOne.lastname}} {{CustomerEntityOne.suffix}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertFirstName"/> + <see userInput="Wholesale" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertCustomerGroup"/> + <see userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertEmail"/> + <see userInput="Jan 1, 1970" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertDateOfBirth"/> + <see userInput="Male" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertGender"/> + + <!--Assert Customer Form --> + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> + <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> + <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.namePrefix}}" userInput="{{CustomerEntityOne.prefix}}" stepKey="seeCustomerNamePrefix"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="seeCustomerFirstName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="seeCustomerLastName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.nameSuffix}}" userInput="{{CustomerEntityOne.suffix}}" stepKey="seeCustomerNameSuffix"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="seeCustomerEmail"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithoutAddressTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithoutAddressTest.xml new file mode 100644 index 0000000000000..fe4bb3ee59e6e --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithoutAddressTest.xml @@ -0,0 +1,61 @@ +<?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="AdminCreateCustomerWithoutAddressTest"> + <annotations> + <stories value="Create customer"/> + <title value="Create customer, without address"/> + <description value="Login as admin and create a customer without address"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5307"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + </before> + <after> + <actionGroup ref="DeleteCustomerByEmailActionGroup" stepKey="deleteCustomer"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Open New Customer Page --> + <amOnPage url="{{AdminNewCustomerPage.url}}" stepKey="navigateToNewCustomerPage"/> + <waitForPageLoad stepKey="waitToCustomerPageLoad"/> + <fillField userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminCustomerAccountInformationSection.firstName}}" stepKey="fillFirstName"/> + <fillField userInput="{{CustomerEntityOne.lastname}}" selector="{{AdminCustomerAccountInformationSection.lastName}}" stepKey="fillLastName"/> + <fillField userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerAccountInformationSection.email}}" stepKey="fillEmail"/> + <click selector="{{AdminCustomerMainActionsSection.saveButton}}" stepKey="saveCustomer"/> + <seeElement selector="{{AdminCustomerMessagesSection.successMessage}}" stepKey="assertSuccessMessage"/> + <reloadPage stepKey="reloadPage"/> + + <!--Filter the customer From grid--> + <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <waitForPageLoad stepKey="waitForPageToLoad"/> + + <!-- Assert Customer in grid --> + <see userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertFirstName"/> + <see userInput="{{CustomerEntityOne.lastname}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertLastName"/> + <see userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerGridSection.customerGrid}}" stepKey="assertEmail"/> + + <!--Assert Customer Form --> + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> + <waitForPageLoad stepKey="waitForCustomerEditPageToLoad1"/> + <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> + <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="seeCustomerFirstName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="seeCustomerLastName"/> + <seeInField selector="{{AdminCustomerAccountInformationSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="seeCustomerEmail"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerTest.xml new file mode 100644 index 0000000000000..de4ab9ffaa121 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateNewCustomerTest.xml @@ -0,0 +1,54 @@ +<?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="AdminCreateNewCustomerTest"> + <annotations> + <stories value="Create customer"/> + <title value="Create customer, new via backend"/> + <description value="Login as admin and create a new customer"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5312"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + </before> + <after> + <actionGroup ref="DeleteCustomerByEmailActionGroup" stepKey="deleteCustomer"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Open New Customer Page --> + <amOnPage url="{{AdminNewCustomerPage.url}}" stepKey="navigateToNewCustomerPage"/> + <waitForPageLoad stepKey="waitToCustomerPageLoad"/> + <fillField userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminCustomerAccountInformationSection.firstName}}" stepKey="fillFirstName"/> + <fillField userInput="{{CustomerEntityOne.lastname}}" selector="{{AdminCustomerAccountInformationSection.lastName}}" stepKey="fillLastName"/> + <fillField userInput="{{CustomerEntityOne.email}}" selector="{{AdminCustomerAccountInformationSection.email}}" stepKey="fillEmail"/> + <click selector="{{AdminCustomerMainActionsSection.saveButton}}" stepKey="saveCustomer"/> + <seeElement selector="{{AdminCustomerMessagesSection.successMessage}}" stepKey="assertSuccessMessage"/> + <reloadPage stepKey="reloadPage"/> + + <!--Filter the customer From grid--> + <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <waitForPageLoad stepKey="waitForPageToLoad"/> + <click selector="{{AdminCustomerGridSection.firstRowEditLink}}" stepKey="clickOnEditButton1"/> + <waitForPageLoad stepKey="waitForCustomerEditPageToLoad"/> + + <!-- Assert Customer Title --> + <click selector="{{AdminCustomerAccountInformationSection.accountInformationButton}}" stepKey="clickOnAccountInformation"/> + <waitForPageLoad stepKey="waitForCustomerInformationPageToLoad"/> + <see stepKey="seeCustomerTitle" selector="{{AdminEditCustomerInformationSection.customerTitle}}" userInput="{{CustomerEntityOne.firstname}} {{CustomerEntityOne.lastname}} "/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminUpdateCustomerTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminUpdateCustomerTest.xml new file mode 100644 index 0000000000000..f58f23dee4235 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminUpdateCustomerTest.xml @@ -0,0 +1,308 @@ +<?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="AdminUpdateCustomerInfoFromDefaultToNonDefaultTest"> + <annotations> + <features value="Customer"/> + <stories value="Update Customer Information in Admin"/> + <title value="Update Customer Info from Default to Non-Default in Admin"/> + <description value="Update Customer Info from Default to Non-Default in Admin"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-13619"/> + <group value="Customer"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <createData stepKey="customer" entity="Simple_Customer_Without_Address"/> + <magentoCLI command="indexer:reindex" stepKey="reindex"/> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + </before> + <after> + <deleteData stepKey="deleteCustomer" createDataKey="customer"/> + <!-- Reset customer grid filter --> + <amOnPage stepKey="goToCustomersGridPage" url="{{AdminCustomerPage.url}}"/> + <waitForPageLoad stepKey="waitForCustomersGrid"/> + <actionGroup stepKey="resetFilter" ref="AdminResetFilterInCustomerGrid"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <amOnPage url="{{AdminCustomerPage.url}}edit/id/$$customer.id$$/" stepKey="openCustomerEditPage"/> + <waitForPageLoad stepKey="waitForCustomerEditPage"/> + <!-- Update Customer Account Information --> + <actionGroup stepKey="editCustomerInformation" ref="AdminEditCustomerAccountInformationActionGroup"> + <argument name="firstName" value="$$customer.firstname$$updated"/> + <argument name="lastName" value="$$customer.lastname$$updated"/> + <argument name="email" value="updated$$customer.email$$"/> + </actionGroup> + <!--Update Customer Addresses --> + <actionGroup stepKey="editCustomerAddress" ref="AdminEditCustomerAddressSetDefaultShippingAndBilling"> + <argument name="customerAddress" value="CustomerAddressSimple"/> + </actionGroup> + <actionGroup stepKey="saveAndCheckSuccessMessage" ref="AdminSaveCustomerAndAssertSuccessMessage"/> + <!-- Assert Customer in Customer grid --> + <amOnPage stepKey="goToCustomersGridPage" url="{{AdminCustomerPage.url}}"/> + <waitForPageLoad stepKey="waitForCustomersGrid"/> + <actionGroup stepKey="resetFilter" ref="AdminResetFilterInCustomerGrid"/> + <actionGroup stepKey="filterByEamil" ref="AdminFilterCustomerGridByEmail"> + <argument name="email" value="updated$$customer.email$$"/> + </actionGroup> + <actionGroup stepKey="checkCustomerInGrid" ref="AdminAssertCustomerInCustomersGrid"> + <argument name="text" value="updated$$customer.email$$"/> + <argument name="row" value="1"/> + </actionGroup> + <!-- Assert Customer in Customer Form --> + <amOnPage url="{{AdminCustomerPage.url}}edit/id/$$customer.id$$/" stepKey="openCustomerEditPageAfterSave"/> + <waitForPageLoad stepKey="waitForCustomerEditPageAfterSave"/> + <!-- Assert Customer Account Information --> + <actionGroup stepKey="checkCustomerAccountInformation" ref="AdminAssertCustomerAccountInformation"> + <argument name="firstName" value="$$customer.firstname$$updated"/> + <argument name="lastName" value="$$customer.lastname$$updated"/> + <argument name="email" value="updated$$customer.email$$"/> + </actionGroup> + <!-- Assert Customer Default Billing Address --> + <actionGroup stepKey="checkDefaultBilling" ref="AdminAssertCustomerDefaultBillingAddress"> + <argument name="firstName" value="$$customer.firstname$$updated"/> + <argument name="lastName" value="$$customer.lastname$$updated"/> + <argument name="street1" value="{{CustomerAddressSimple.street[0]}}"/> + <argument name="state" value="{{CustomerAddressSimple.state}}"/> + <argument name="postcode" value="{{CustomerAddressSimple.postcode}}"/> + <argument name="country" value="{{CustomerAddressSimple.country_id}}"/> + <argument name="telephone" value="{{CustomerAddressSimple.telephone}}"/> + </actionGroup> + <!-- Assert Customer Default Shipping Address --> + <actionGroup stepKey="checkDefaultShipping" ref="AdminAssertCustomerDefaultShippingAddress"> + <argument name="firstName" value="$$customer.firstname$$updated"/> + <argument name="lastName" value="$$customer.lastname$$updated"/> + <argument name="street1" value="{{CustomerAddressSimple.street[0]}}"/> + <argument name="state" value="{{CustomerAddressSimple.state}}"/> + <argument name="postcode" value="{{CustomerAddressSimple.postcode}}"/> + <argument name="country" value="{{CustomerAddressSimple.country_id}}"/> + <argument name="telephone" value="{{CustomerAddressSimple.telephone}}"/> + </actionGroup> + </test> + + <test name="AdminUpdateCustomerAddressNoZipNoStateTest" extends="AdminUpdateCustomerInfoFromDefaultToNonDefaultTest"> + <annotations> + <features value="Customer"/> + <stories value="Update Customer Information in Admin"/> + <title value="Update Customer Address, without zip/state required, default billing/shipping checked in Admin"/> + <description value="Update Customer Address, without zip/state required, default billing/shipping checked in Admin"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-13621"/> + <group value="Customer"/> + <group value="mtf_migrated"/> + </annotations> + <after> + <remove keyForRemoval="goToCustomersGridPage"/> + <remove keyForRemoval="waitForCustomersGrid"/> + <remove keyForRemoval="resetFilter"/> + </after> + + <!-- Remove steps that are not used for this test --> + <remove keyForRemoval="editCustomerInformation"/> + <remove keyForRemoval="goToCustomersGridPage"/> + <remove keyForRemoval="waitForCustomersGrid"/> + <remove keyForRemoval="resetFilter"/> + <remove keyForRemoval="filterByEamil"/> + <remove keyForRemoval="checkCustomerInGrid"/> + <remove keyForRemoval="checkCustomerAccountInformation"/> + + <!--Update Customer Addresses With No Zip and No State --> + <actionGroup stepKey="editCustomerAddress" ref="AdminEditCustomerAddressNoZipNoState"> + <argument name="customerAddress" value="addressNoZipNoState"/> + </actionGroup> + + <!-- Assert Customer Default Billing Address --> + <actionGroup stepKey="checkDefaultBilling" ref="AdminAssertCustomerDefaultBillingAddress"> + <argument name="firstName" value="$$customer.firstname$$"/> + <argument name="lastName" value="$$customer.lastname$$"/> + <argument name="street1" value="{{addressNoZipNoState.street[0]}}"/> + <argument name="country" value="{{addressNoZipNoState.country_id}}"/> + <argument name="telephone" value="{{addressNoZipNoState.telephone}}"/> + </actionGroup> + <!-- Assert Customer Default Shipping Address --> + <actionGroup stepKey="checkDefaultShipping" ref="AdminAssertCustomerDefaultShippingAddress"> + <argument name="firstName" value="$$customer.firstname$$"/> + <argument name="lastName" value="$$customer.lastname$$"/> + <argument name="street1" value="{{addressNoZipNoState.street[0]}}"/> + <argument name="country" value="{{addressNoZipNoState.country_id}}"/> + <argument name="telephone" value="{{addressNoZipNoState.telephone}}"/> + </actionGroup> + <!-- Assert Customer Login Storefront --> + <actionGroup stepKey="login" ref="StorefrontAssertSuccessLoginToStorefront" after="checkDefaultShipping" > + <argument name="Customer" value="$$customer$$"/> + </actionGroup> + </test> + + <test name="AdminUpdateCustomerAddressNoBillingNoShippingTest" extends="AdminUpdateCustomerInfoFromDefaultToNonDefaultTest"> + <annotations> + <features value="Customer"/> + <stories value="Update Customer Information in Admin"/> + <title value="Update Customer Address, default billing/shipping unchecked in Admin"/> + <description value="Update Customer Address, default billing/shipping unchecked in Admin"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-13622"/> + <group value="Customer"/> + <group value="mtf_migrated"/> + </annotations> + <after> + <remove keyForRemoval="goToCustomersGridPage"/> + <remove keyForRemoval="waitForCustomersGrid"/> + <remove keyForRemoval="resetFilter"/> + </after> + + <!-- Remove steps that are not used for this test --> + <remove keyForRemoval="editCustomerInformation"/> + <remove keyForRemoval="goToCustomersGridPage"/> + <remove keyForRemoval="waitForCustomersGrid"/> + <remove keyForRemoval="resetFilter"/> + <remove keyForRemoval="filterByEamil"/> + <remove keyForRemoval="checkCustomerInGrid"/> + <remove keyForRemoval="checkCustomerAccountInformation"/> + <remove keyForRemoval="checkDefaultBilling"/> + <remove keyForRemoval="checkDefaultShipping"/> + + <!--Update Customer Addresses With Default Billing and Shipping Unchecked --> + <actionGroup stepKey="editCustomerAddress" ref="AdminEditCustomerAddressesFrom"> + <argument name="customerAddress" value="CustomerAddressSimple"/> + </actionGroup> + + <!-- Check Customer Address in Customer Form --> + <actionGroup stepKey="checkNoDefaultBilling" ref="AdminAssertCustomerNoDefaultBillingAddress" after="waitForCustomerEditPageAfterSave"/> + <actionGroup stepKey="checkNoDefaultShipping" ref="AdminAssertCustomerNoDefaultShippingAddress" after="checkNoDefaultBilling"/> + <actionGroup stepKey="resetFilter" ref="AdminResetFilterInCustomerAddressGrid" after="checkNoDefaultShipping"/> + <actionGroup stepKey="searchAddress" ref="AdminFilterCustomerAddressGridByPhoneNumber" after="resetFilter"> + <argument name="phone" value="{{CustomerAddressSimple.telephone}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressStreetInGrid" ref="AdminAssertAddressInCustomersAddressGrid" after="searchAddress"> + <argument name="text" value="{{CustomerAddressSimple.street[0]}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressPhoneInGrid" ref="AdminAssertAddressInCustomersAddressGrid" after="checkAddressStreetInGrid"> + <argument name="text" value="{{CustomerAddressSimple.telephone}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressStateInGrid" ref="AdminAssertAddressInCustomersAddressGrid" after="checkAddressPhoneInGrid"> + <argument name="text" value="{{CustomerAddressSimple.state}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressCityInGrid" ref="AdminAssertAddressInCustomersAddressGrid" after="checkAddressStateInGrid"> + <argument name="text" value="{{CustomerAddressSimple.city}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressCountryInGrid" ref="AdminAssertAddressInCustomersAddressGrid" after="checkAddressCityInGrid"> + <argument name="text" value="{{CustomerAddressSimple.country_id}}"/> + </actionGroup> + <actionGroup stepKey="resetFilterWhenDone" ref="AdminResetFilterInCustomerAddressGrid" after="checkAddressCountryInGrid"/> + <!-- Assert Customer Login Storefront --> + <actionGroup stepKey="login" ref="StorefrontAssertSuccessLoginToStorefront" after="resetFilterWhenDone" > + <argument name="Customer" value="$$customer$$"/> + </actionGroup> + </test> + + <test name="AdminDeleteCustomerAddressTest"> + <annotations> + <features value="Customer"/> + <stories value="Delete Customer Address in Admin"/> + <title value="Delete Customer Address in Admin"/> + <description value="Delete Customer Address in Admin"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-13623"/> + <group value="Customer"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <createData stepKey="customer" entity="Simple_US_Customer_Multiple_Addresses"/> + <magentoCLI command="indexer:reindex" stepKey="reindex"/> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + </before> + <after> + <deleteData stepKey="deleteCustomer" createDataKey="customer"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <amOnPage url="{{AdminCustomerPage.url}}edit/id/$$customer.id$$/" stepKey="openCustomerEditPage"/> + <waitForPageLoad stepKey="waitForCustomerEditPage"/> + <!-- Assert Customer Default Billing Address --> + <actionGroup stepKey="checkDefaultBilling" ref="AdminAssertCustomerDefaultBillingAddress"> + <argument name="firstName" value="$$customer.firstname$$"/> + <argument name="lastName" value="$$customer.lastname$$"/> + <argument name="street1" value="{{US_Address_NY.street[0]}}"/> + <argument name="state" value="{{US_Address_NY.state}}"/> + <argument name="postcode" value="{{US_Address_NY.postcode}}"/> + <argument name="country" value="{{US_Address_NY.country}}"/> + <argument name="telephone" value="{{US_Address_NY.telephone}}"/> + </actionGroup> + <!-- Assert Customer Default Shipping Address --> + <actionGroup stepKey="checkDefaultShipping" ref="AdminAssertCustomerDefaultShippingAddress"> + <argument name="firstName" value="$$customer.firstname$$"/> + <argument name="lastName" value="$$customer.lastname$$"/> + <argument name="street1" value="{{US_Address_NY.street[0]}}"/> + <argument name="state" value="{{US_Address_NY.state}}"/> + <argument name="postcode" value="{{US_Address_NY.postcode}}"/> + <argument name="country" value="{{US_Address_NY.country}}"/> + <argument name="telephone" value="{{US_Address_NY.telephone}}"/> + </actionGroup> + <actionGroup stepKey="resetFilter" ref="AdminResetFilterInCustomerAddressGrid"/> + <!-- Assert 2 records in Customer Address Grid --> + <actionGroup stepKey="see2Record" ref="AdminAssertNumberOfRecordsInCustomersAddressGrid"> + <argument name="number" value="2"/> + </actionGroup> + <!-- Assert Address 1 in Grid --> + <actionGroup stepKey="checkAddressStreetInGrid" ref="AdminAssertAddressInCustomersAddressGrid"> + <argument name="text" value="{{US_Address_NY.street[0]}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressPhoneInGrid" ref="AdminAssertAddressInCustomersAddressGrid"> + <argument name="text" value="{{US_Address_NY.telephone}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressStateInGrid" ref="AdminAssertAddressInCustomersAddressGrid"> + <argument name="text" value="{{US_Address_NY.state}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressCityInGrid" ref="AdminAssertAddressInCustomersAddressGrid"> + <argument name="text" value="{{US_Address_NY.city}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressCountryInGrid" ref="AdminAssertAddressInCustomersAddressGrid"> + <argument name="text" value="{{US_Address_NY.country}}"/> + </actionGroup> + <!-- Assert Address 2 in Grid --> + <actionGroup stepKey="checkAddressStreetInGrid2" ref="AdminAssertAddressInCustomersAddressGrid"> + <argument name="text" value="{{UK_Not_Default_Address.street[0]}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressPhoneInGrid2" ref="AdminAssertAddressInCustomersAddressGrid"> + <argument name="text" value="{{UK_Not_Default_Address.telephone}}"/> + </actionGroup> + <actionGroup stepKey="checkAddressCityInGrid2" ref="AdminAssertAddressInCustomersAddressGrid"> + <argument name="text" value="{{UK_Not_Default_Address.city}}"/> + </actionGroup> + <!-- Delete Customer in Customer Address Grid --> + <actionGroup stepKey="deleteAddress" ref="AdminDeleteAddressInCustomersAddressGrid"> + <argument name="row" value="0"/> + </actionGroup> + <!-- Assert 1 record in Customer Address Grid --> + <actionGroup stepKey="see1Record" ref="AdminAssertNumberOfRecordsInCustomersAddressGrid"> + <argument name="number" value="1"/> + </actionGroup> + <actionGroup stepKey="saveAndContinue" ref="AdminCustomerSaveAndContinue"/> + <actionGroup stepKey="saveAndCheckSuccessMessage" ref="AdminSaveCustomerAndAssertSuccessMessage"/> + <!-- Assert Customer Login Storefront --> + <actionGroup stepKey="login" ref="StorefrontAssertSuccessLoginToStorefront"> + <argument name="Customer" value="$$customer$$"/> + </actionGroup> + <!-- Assert Customer Address Book --> + <actionGroup stepKey="goToAddressBook" ref="StorefrontCustomerGoToSidebarMenu"> + <argument name="menu" value="Address Book"/> + </actionGroup> + <actionGroup stepKey="assertAddressNumber" ref="StorefrontCustomerAddressBookNumberOfAddresses"> + <argument name="number" value="1"/> + </actionGroup> + <actionGroup stepKey="assertNoAddress1" ref="StorefrontCustomerAddressBookNotContains"> + <argument name="text" value="{{US_Address_NY.street[0]}}"/> + </actionGroup> + <actionGroup stepKey="assertAddress2" ref="StorefrontCustomerAddressBookContains"> + <argument name="text" value="{{UK_Not_Default_Address.street[0]}}"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminVerifyCreateCustomerRequiredFieldsTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminVerifyCreateCustomerRequiredFieldsTest.xml new file mode 100644 index 0000000000000..7dab6eefde8ec --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminVerifyCreateCustomerRequiredFieldsTest.xml @@ -0,0 +1,39 @@ +<?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="AdminVerifyCreateCustomerRequiredFieldsTest"> + <annotations> + <stories value="Create customer"/> + <title value="Create customer, verify required fields on Account Information tab"/> + <description value="Login as admin and verify required fields on account information section"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5314"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Open New Customer Page --> + <amOnPage url="{{AdminNewCustomerPage.url}}" stepKey="navigateToNewCustomerPage"/> + <waitForPageLoad stepKey="waitToCustomerPageLoad"/> + <click selector="{{AdminCustomerMainActionsSection.saveButton}}" stepKey="saveCustomer"/> + <waitForPageLoad stepKey="waitForPageToLoad"/> + + <!--Assert Required Fields --> + <seeElement selector="{{AdminCustomerAccountInformationSection.firstNameRequiredMessage}}" stepKey="seeFirstNameRequiredFieldMessage"/> + <seeElement selector="{{AdminCustomerAccountInformationSection.lastNameRequiredMessage}}" stepKey="seeLastNameRequiredFieldMessage"/> + <seeElement selector="{{AdminCustomerAccountInformationSection.emailRequiredMessage}}" stepKey="seeEmailRequiredFieldMessage"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminVerifyCustomerAddressRequiredFieldsTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminVerifyCustomerAddressRequiredFieldsTest.xml new file mode 100644 index 0000000000000..bfb47dc9e1911 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminVerifyCustomerAddressRequiredFieldsTest.xml @@ -0,0 +1,49 @@ +<?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="AdminVerifyCustomerAddressRequiredFieldsTest"> + <annotations> + <stories value="Create customer"/> + <title value="Create customer, verify required fields on Addresses tab"/> + <description value="Login as admin and verify required fields on Address tab"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5315"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="Simple_Customer_Without_Address" stepKey="createCustomer"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + </before> + <after> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Open Created Customer --> + <actionGroup ref="OpenEditCustomerFromAdminActionGroup" stepKey="editCustomerForm"> + <argument name="customer" value="Simple_Customer_Without_Address"/> + </actionGroup> + <click selector="{{AdminCustomerAccountInformationSection.addressesButton}}" stepKey="openAddressesTab"/> + <waitForPageLoad stepKey="waitForPageToLoad"/> + <click selector="{{AdminEditCustomerAddressesSection.addNewAddress}}" stepKey="ClickOnAddNewAddressButton"/> + <waitForPageLoad stepKey="waitForAdressPageToLoad"/> + <click selector="{{AdminEditCustomerAddressesSection.save}}" stepKey="clickOnSaveButton"/> + <waitForPageLoad stepKey="waitForPageToBeSaved"/> + + <!--Assert Required Field Messages --> + <seeElement selector="{{AdminCustomerAddressesSection.streetRequiredMessage}}" stepKey="seeStreetRequiredMessage"/> + <seeElement selector="{{AdminCustomerAddressesSection.cityRequiredMessage}}" stepKey="seeCityRequiredMessage"/> + <scrollTo selector="{{AdminEditCustomerAddressesSection.phone}}" x="0" y="-80" stepKey="scrollToPhone"/> + <seeElement selector="{{AdminCustomerAddressesSection.countryRequiredMessage}}" stepKey="seeCountryRequiredMessage"/> + <seeElement selector="{{AdminCustomerAddressesSection.postcodeRequiredMessage}}" stepKey="seePostcodeRequiredMessage"/> + <seeElement selector="{{AdminCustomerAddressesSection.phoneNumberRequiredMessage}}" stepKey="seePhoneNumberRequiredMessage"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/StorefrontLoginWithIncorrectCredentialsTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontLoginWithIncorrectCredentialsTest.xml index 9a6c1c5ec8988..104b5d56314ba 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/StorefrontLoginWithIncorrectCredentialsTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontLoginWithIncorrectCredentialsTest.xml @@ -17,7 +17,7 @@ <severity value="CRITICAL"/> <testCaseId value="MC-10913"/> <group value="Customer"/> - <group value="mtf-migrated"/> + <group value="mtf_migrated"/> </annotations> <before> <createData stepKey="customer" entity="Simple_US_Customer"/> diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_create.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_create.xml index fd5ecbfa7f277..0c5af453f2373 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_create.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_create.xml @@ -6,6 +6,9 @@ */ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <head> + <title>Create New Customer Account + diff --git a/app/code/Magento/CustomerGraphQl/Model/Customer/CheckCustomerPassword.php b/app/code/Magento/CustomerGraphQl/Model/Customer/CheckCustomerPassword.php index f3c03e5fc18aa..3cc831e1ca40e 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Customer/CheckCustomerPassword.php +++ b/app/code/Magento/CustomerGraphQl/Model/Customer/CheckCustomerPassword.php @@ -9,7 +9,12 @@ use Magento\Customer\Model\AuthenticationInterface; use Magento\Framework\Exception\InvalidEmailOrPasswordException; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Exception\State\UserLockedException; use Magento\Framework\GraphQl\Exception\GraphQlAuthenticationException; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; /** * Check customer password @@ -36,15 +41,21 @@ public function __construct( * @param string $password * @param int $customerId * @throws GraphQlAuthenticationException + * @throws GraphQlInputException + * @throws GraphQlNoSuchEntityException */ public function execute(string $password, int $customerId) { try { $this->authentication->authenticate($customerId, $password); } catch (InvalidEmailOrPasswordException $e) { - throw new GraphQlAuthenticationException( - __('The password doesn\'t match this account. Verify the password and try again.') - ); + throw new GraphQlAuthenticationException(__($e->getMessage()), $e); + } catch (UserLockedException $e) { + throw new GraphQlAuthenticationException(__($e->getMessage()), $e); + } catch (NoSuchEntityException $e) { + throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e); + } catch (LocalizedException $e) { + throw new GraphQlInputException(__($e->getMessage()), $e); } } } diff --git a/app/code/Magento/CustomerGraphQl/Model/Customer/UpdateCustomerData.php b/app/code/Magento/CustomerGraphQl/Model/Customer/UpdateCustomerData.php index 18510b872e64a..33f16f3d94b7d 100644 --- a/app/code/Magento/CustomerGraphQl/Model/Customer/UpdateCustomerData.php +++ b/app/code/Magento/CustomerGraphQl/Model/Customer/UpdateCustomerData.php @@ -9,10 +9,13 @@ use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Framework\Exception\AlreadyExistsException; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException; +use Magento\Framework\GraphQl\Exception\GraphQlAuthenticationException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Store\Model\StoreManagerInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Framework\Api\DataObjectHelper; /** * Update customer data @@ -34,19 +37,35 @@ class UpdateCustomerData */ private $checkCustomerPassword; + /** + * @var DataObjectHelper + */ + private $dataObjectHelper; + + /** + * @var array + */ + private $restrictedKeys; + /** * @param CustomerRepositoryInterface $customerRepository * @param StoreManagerInterface $storeManager * @param CheckCustomerPassword $checkCustomerPassword + * @param DataObjectHelper $dataObjectHelper + * @param array $restrictedKeys */ public function __construct( CustomerRepositoryInterface $customerRepository, StoreManagerInterface $storeManager, - CheckCustomerPassword $checkCustomerPassword + CheckCustomerPassword $checkCustomerPassword, + DataObjectHelper $dataObjectHelper, + array $restrictedKeys = [] ) { $this->customerRepository = $customerRepository; $this->storeManager = $storeManager; $this->checkCustomerPassword = $checkCustomerPassword; + $this->dataObjectHelper = $dataObjectHelper; + $this->restrictedKeys = $restrictedKeys; } /** @@ -55,21 +74,16 @@ public function __construct( * @param int $customerId * @param array $data * @return void - * @throws GraphQlNoSuchEntityException - * @throws GraphQlInputException * @throws GraphQlAlreadyExistsException + * @throws GraphQlInputException + * @throws GraphQlAuthenticationException */ public function execute(int $customerId, array $data): void { $customer = $this->customerRepository->getById($customerId); - if (isset($data['firstname'])) { - $customer->setFirstname($data['firstname']); - } - - if (isset($data['lastname'])) { - $customer->setLastname($data['lastname']); - } + $filteredData = array_diff_key($data, array_flip($this->restrictedKeys)); + $this->dataObjectHelper->populateWithArray($customer, $filteredData, CustomerInterface::class); if (isset($data['email']) && $customer->getEmail() !== $data['email']) { if (!isset($data['password']) || empty($data['password'])) { @@ -89,6 +103,8 @@ public function execute(int $customerId, array $data): void __('A customer with the same email address already exists in an associated website.'), $e ); + } catch (LocalizedException $e) { + throw new GraphQlInputException(__($e->getMessage()), $e); } } } diff --git a/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml b/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml new file mode 100644 index 0000000000000..f1bd3563fda3d --- /dev/null +++ b/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml @@ -0,0 +1,16 @@ + + + + + + + Magento\Customer\Api\Data\CustomerInterface::EMAIL + + + + \ No newline at end of file diff --git a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls index 139ac80be8429..c5860005c6e0e 100644 --- a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls @@ -92,6 +92,7 @@ type Customer @doc(description: "Customer defines the customer name and address id: Int @doc(description: "The ID assigned to the customer") is_subscribed: Boolean @doc(description: "Indicates whether the customer is subscribed to the company's newsletter") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\IsSubscribed") addresses: [CustomerAddress] @doc(description: "An array containing the customer's shipping and billing addresses") + gender: Int @doc(description: "The customer's gender(Male - 1, Female - 2)") } type CustomerAddress @doc(description: "CustomerAddress contains detailed information about a customer's billing and shipping addresses"){ diff --git a/app/code/Magento/Downloadable/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml b/app/code/Magento/Downloadable/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml new file mode 100644 index 0000000000000..b84dbff1154cf --- /dev/null +++ b/app/code/Magento/Downloadable/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/app/code/Magento/Downloadable/Test/Mftf/Section/AdminProductDropdownOrderSection.xml b/app/code/Magento/Downloadable/Test/Mftf/Section/AdminProductDropdownOrderSection.xml new file mode 100644 index 0000000000000..39b4e303d5165 --- /dev/null +++ b/app/code/Magento/Downloadable/Test/Mftf/Section/AdminProductDropdownOrderSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Downloadable/Ui/DataProvider/Product/Form/Modifier/Links.php b/app/code/Magento/Downloadable/Ui/DataProvider/Product/Form/Modifier/Links.php index 2188a671a5aa0..c4824f913daf8 100644 --- a/app/code/Magento/Downloadable/Ui/DataProvider/Product/Form/Modifier/Links.php +++ b/app/code/Magento/Downloadable/Ui/DataProvider/Product/Form/Modifier/Links.php @@ -3,22 +3,24 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Downloadable\Ui\DataProvider\Product\Form\Modifier; -use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; use Magento\Catalog\Model\Locator\LocatorInterface; +use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; use Magento\Downloadable\Model\Product\Type; -use Magento\Downloadable\Model\Source\TypeUpload; use Magento\Downloadable\Model\Source\Shareable; -use Magento\Store\Model\StoreManagerInterface; +use Magento\Downloadable\Model\Source\TypeUpload; use Magento\Framework\Stdlib\ArrayManager; -use Magento\Ui\Component\DynamicRows; use Magento\Framework\UrlInterface; +use Magento\Store\Model\StoreManagerInterface; use Magento\Ui\Component\Container; +use Magento\Ui\Component\DynamicRows; use Magento\Ui\Component\Form; /** - * Class adds a grid with links + * Class adds a grid with links. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Links extends AbstractModifier @@ -238,6 +240,7 @@ protected function getTitleColumn() 'label' => __('Title'), 'showLabel' => false, 'dataScope' => '', + 'sortOrder' => 10, ]; $titleField['arguments']['data']['config'] = [ 'formElement' => Form\Element\Input::NAME, @@ -267,6 +270,7 @@ protected function getPriceColumn() 'label' => __('Price'), 'showLabel' => false, 'dataScope' => '', + 'sortOrder' => 20, ]; $priceField['arguments']['data']['config'] = [ 'formElement' => Form\Element\Input::NAME, @@ -304,6 +308,7 @@ protected function getFileColumn() 'label' => __('File'), 'showLabel' => false, 'dataScope' => '', + 'sortOrder' => 30, ]; $fileTypeField['arguments']['data']['config'] = [ 'formElement' => Form\Element\Select::NAME, @@ -370,6 +375,7 @@ protected function getSampleColumn() 'label' => __('Sample'), 'showLabel' => false, 'dataScope' => '', + 'sortOrder' => 40, ]; $sampleTypeField['arguments']['data']['config'] = [ 'formElement' => Form\Element\Select::NAME, @@ -432,6 +438,7 @@ protected function getShareableColumn() 'componentType' => Form\Field::NAME, 'dataType' => Form\Element\DataType\Number::NAME, 'dataScope' => 'is_shareable', + 'sortOrder' => 50, 'options' => $this->shareable->toOptionArray(), ]; @@ -452,6 +459,7 @@ protected function getMaxDownloadsColumn() 'label' => __('Max. Downloads'), 'showLabel' => false, 'dataScope' => '', + 'sortOrder' => 60, ]; $numberOfDownloadsField['arguments']['data']['config'] = [ 'formElement' => Form\Element\Input::NAME, diff --git a/app/code/Magento/Downloadable/Ui/DataProvider/Product/Form/Modifier/Samples.php b/app/code/Magento/Downloadable/Ui/DataProvider/Product/Form/Modifier/Samples.php index 197bf1338f945..81c5918eb24ae 100644 --- a/app/code/Magento/Downloadable/Ui/DataProvider/Product/Form/Modifier/Samples.php +++ b/app/code/Magento/Downloadable/Ui/DataProvider/Product/Form/Modifier/Samples.php @@ -3,21 +3,23 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Downloadable\Ui\DataProvider\Product\Form\Modifier; -use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; use Magento\Catalog\Model\Locator\LocatorInterface; +use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; use Magento\Downloadable\Model\Product\Type; use Magento\Downloadable\Model\Source\TypeUpload; -use Magento\Store\Model\StoreManagerInterface; use Magento\Framework\Stdlib\ArrayManager; -use Magento\Ui\Component\DynamicRows; use Magento\Framework\UrlInterface; +use Magento\Store\Model\StoreManagerInterface; use Magento\Ui\Component\Container; +use Magento\Ui\Component\DynamicRows; use Magento\Ui\Component\Form; /** - * Class adds a grid with samples + * Class adds a grid with samples. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Samples extends AbstractModifier @@ -209,6 +211,7 @@ protected function getTitleColumn() 'showLabel' => false, 'label' => __('Title'), 'dataScope' => '', + 'sortOrder' => 10, ]; $titleField['arguments']['data']['config'] = [ 'formElement' => Form\Element\Input::NAME, @@ -238,6 +241,7 @@ protected function getSampleColumn() 'label' => __('File'), 'showLabel' => false, 'dataScope' => '', + 'sortOrder' => 20, ]; $sampleType['arguments']['data']['config'] = [ 'formElement' => Form\Element\Select::NAME, diff --git a/app/code/Magento/Downloadable/view/frontend/layout/catalog_product_view_type_downloadable.xml b/app/code/Magento/Downloadable/view/frontend/layout/catalog_product_view_type_downloadable.xml index 45e5f0b8da72d..f851558c1a563 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/catalog_product_view_type_downloadable.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/catalog_product_view_type_downloadable.xml @@ -26,17 +26,6 @@
- - - - product.price.render.default - final_price - 1 - item_view - copy- - - - diff --git a/app/code/Magento/Elasticsearch/composer.json b/app/code/Magento/Elasticsearch/composer.json index a821506f5ef6e..c6ac38c1e4005 100644 --- a/app/code/Magento/Elasticsearch/composer.json +++ b/app/code/Magento/Elasticsearch/composer.json @@ -12,7 +12,7 @@ "magento/module-store": "*", "magento/module-catalog-inventory": "*", "magento/framework": "*", - "elasticsearch/elasticsearch": "~2.0|~5.1" + "elasticsearch/elasticsearch": "~2.0|~5.1|~6.1" }, "suggest": { "magento/module-config": "*" diff --git a/app/code/Magento/Elasticsearch6/composer.json b/app/code/Magento/Elasticsearch6/composer.json index c289d8cd3e4e4..26b6c8c678ade 100644 --- a/app/code/Magento/Elasticsearch6/composer.json +++ b/app/code/Magento/Elasticsearch6/composer.json @@ -9,7 +9,7 @@ "magento/module-search": "*", "magento/module-store": "*", "magento/module-elasticsearch": "*", - "elasticsearch/elasticsearch": "~6.1" + "elasticsearch/elasticsearch": "~2.0|~5.1|~6.1" }, "suggest": { "magento/module-config": "*" diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml b/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml new file mode 100644 index 0000000000000..5937267b4a61e --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/VerifyProductTypeOrderActionGroup.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Data/GroupedProductData.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Data/GroupedProductData.xml index cb268b51f08f9..ba3703e7b0edc 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/Data/GroupedProductData.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Data/GroupedProductData.xml @@ -18,7 +18,7 @@ EavStockItem - api-grouped-product + apiGroupedProduct grouped 4 Api Grouped Product @@ -29,7 +29,7 @@ ApiProductShortDescription - api-grouped-product + apiGroupedProduct grouped 4 Api Grouped Product diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductDropdownOrderSection.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductDropdownOrderSection.xml new file mode 100644 index 0000000000000..3efbabd34c1a4 --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductDropdownOrderSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Msrp/Helper/Data.php b/app/code/Magento/Msrp/Helper/Data.php index 393383bb2e772..2f6dd2da9bbc4 100644 --- a/app/code/Magento/Msrp/Helper/Data.php +++ b/app/code/Magento/Msrp/Helper/Data.php @@ -7,14 +7,17 @@ use Magento\Framework\App\Helper\AbstractHelper; use Magento\Framework\App\Helper\Context; +use Magento\Framework\App\ObjectManager; use Magento\Msrp\Model\Product\Attribute\Source\Type; +use Magento\Msrp\Pricing\MsrpPriceCalculatorInterface; use Magento\Store\Model\StoreManagerInterface; use Magento\Catalog\Model\Product; use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\ConfigurableProduct\Model\Product\Type\Configurable; /** * Msrp data helper + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Data extends AbstractHelper { @@ -43,6 +46,11 @@ class Data extends AbstractHelper */ protected $productRepository; + /** + * @var MsrpPriceCalculatorInterface + */ + private $msrpPriceCalculator; + /** * @param Context $context * @param StoreManagerInterface $storeManager @@ -51,6 +59,7 @@ class Data extends AbstractHelper * @param \Magento\Msrp\Model\Config $config * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency * @param ProductRepositoryInterface $productRepository + * @param MsrpPriceCalculatorInterface|null $msrpPriceCalculator */ public function __construct( Context $context, @@ -59,7 +68,8 @@ public function __construct( \Magento\Msrp\Model\Msrp $msrp, \Magento\Msrp\Model\Config $config, \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency, - ProductRepositoryInterface $productRepository + ProductRepositoryInterface $productRepository, + MsrpPriceCalculatorInterface $msrpPriceCalculator = null ) { parent::__construct($context); $this->storeManager = $storeManager; @@ -68,6 +78,8 @@ public function __construct( $this->config = $config; $this->priceCurrency = $priceCurrency; $this->productRepository = $productRepository; + $this->msrpPriceCalculator = $msrpPriceCalculator + ?: ObjectManager::getInstance()->get(MsrpPriceCalculatorInterface::class); } /** @@ -78,6 +90,7 @@ public function __construct( * @return bool * * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function canApplyMsrp($product, $visibility = null) { @@ -111,6 +124,7 @@ public function canApplyMsrp($product, $visibility = null) * * @param Product $product * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function getMsrpPriceMessage($product) { @@ -128,6 +142,7 @@ public function getMsrpPriceMessage($product) * * @param int|Product $product * @return bool + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function isShowPriceOnGesture($product) { @@ -139,6 +154,7 @@ public function isShowPriceOnGesture($product) * * @param int|Product $product * @return bool + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function isShowBeforeOrderConfirm($product) { @@ -149,31 +165,16 @@ public function isShowBeforeOrderConfirm($product) * Check if any MAP price is larger than as low as value. * * @param int|Product $product - * @return bool|float + * @return bool + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function isMinimalPriceLessMsrp($product) { if (is_numeric($product)) { $product = $this->productRepository->getById($product, false, $this->storeManager->getStore()->getId()); } - $msrp = $product->getMsrp(); + $msrp = $this->msrpPriceCalculator->getMsrpPriceValue($product); $price = $product->getPriceInfo()->getPrice(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE); - if ($msrp === null) { - if ($product->getTypeId() === \Magento\GroupedProduct\Model\Product\Type\Grouped::TYPE_CODE) { - $msrp = $product->getTypeInstance()->getChildrenMsrp($product); - } elseif ($product->getTypeId() === Configurable::TYPE_CODE) { - $prices = []; - foreach ($product->getTypeInstance()->getUsedProducts($product) as $item) { - if ($item->getMsrp() !== null) { - $prices[] = $item->getMsrp(); - } - } - - $msrp = $prices ? max($prices) : 0; - } else { - return false; - } - } if ($msrp) { $msrp = $this->priceCurrency->convertAndRound($msrp); } diff --git a/app/code/Magento/Msrp/Pricing/MsrpPriceCalculator.php b/app/code/Magento/Msrp/Pricing/MsrpPriceCalculator.php new file mode 100644 index 0000000000000..3d1e5ef0b8e6c --- /dev/null +++ b/app/code/Magento/Msrp/Pricing/MsrpPriceCalculator.php @@ -0,0 +1,64 @@ +msrpPriceCalculators = $this->getMsrpPriceCalculators($msrpPriceCalculators); + } + + /** + * @inheritdoc + */ + public function getMsrpPriceValue(ProductInterface $product): float + { + $productType = $product->getTypeId(); + if (isset($this->msrpPriceCalculators[$productType])) { + $priceCalculator = $this->msrpPriceCalculators[$productType]; + $msrp = $priceCalculator->getMsrpPriceValue($product); + } else { + $msrp = (float)$product->getMsrp(); + } + + return $msrp; + } + + /** + * Convert the configuration of MSRP price calculators. + * + * @param array $msrpPriceCalculatorsConfig + * @return array + */ + private function getMsrpPriceCalculators(array $msrpPriceCalculatorsConfig): array + { + $msrpPriceCalculators = []; + foreach ($msrpPriceCalculatorsConfig as $msrpPriceCalculator) { + if (isset($msrpPriceCalculator['productType'], $msrpPriceCalculator['priceCalculator'])) { + $msrpPriceCalculators[$msrpPriceCalculator['productType']] = + $msrpPriceCalculator['priceCalculator']; + } + } + return $msrpPriceCalculators; + } +} diff --git a/app/code/Magento/Msrp/Pricing/MsrpPriceCalculatorInterface.php b/app/code/Magento/Msrp/Pricing/MsrpPriceCalculatorInterface.php new file mode 100644 index 0000000000000..c50a381a2efa4 --- /dev/null +++ b/app/code/Magento/Msrp/Pricing/MsrpPriceCalculatorInterface.php @@ -0,0 +1,23 @@ +msrpPriceCalculator = $msrpPriceCalculator; + parent::__construct($context, $saleableItem, $price, $rendererPool, $jsonHelper, $mathRandom); + } + + /** + * Return MSRP price calculator. + * + * @return MsrpPriceCalculatorInterface + */ + public function getMsrpPriceCalculator(): MsrpPriceCalculatorInterface + { + return $this->msrpPriceCalculator; + } +} diff --git a/app/code/Magento/Msrp/Test/Unit/Helper/DataTest.php b/app/code/Magento/Msrp/Test/Unit/Helper/DataTest.php index 19f46b06ac5af..e4cd411a2e0b8 100644 --- a/app/code/Magento/Msrp/Test/Unit/Helper/DataTest.php +++ b/app/code/Magento/Msrp/Test/Unit/Helper/DataTest.php @@ -6,6 +6,8 @@ namespace Magento\Msrp\Test\Unit\Helper; +use Magento\Msrp\Pricing\MsrpPriceCalculatorInterface; + /** * Class DataTest */ @@ -26,6 +28,14 @@ class DataTest extends \PHPUnit\Framework\TestCase */ protected $productMock; + /** + * @var MsrpPriceCalculatorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $msrpPriceCalculator; + + /** + * @inheritdoc + */ protected function setUp() { $this->priceCurrencyMock = $this->createMock(\Magento\Framework\Pricing\PriceCurrencyInterface::class); @@ -33,6 +43,8 @@ protected function setUp() ->disableOriginalConstructor() ->setMethods(['getMsrp', 'getPriceInfo', '__wakeup']) ->getMock(); + $this->msrpPriceCalculator = $this->getMockBuilder(MsrpPriceCalculatorInterface::class) + ->getMockForAbstractClass(); $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -40,10 +52,14 @@ protected function setUp() \Magento\Msrp\Helper\Data::class, [ 'priceCurrency' => $this->priceCurrencyMock, + 'msrpPriceCalculator' => $this->msrpPriceCalculator, ] ); } + /** + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function testIsMinimalPriceLessMsrp() { $msrp = 120; @@ -73,12 +89,13 @@ function ($arg) { ->with(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE) ->will($this->returnValue($finalPriceMock)); - $this->productMock->expects($this->any()) - ->method('getMsrp') - ->will($this->returnValue($msrp)); + $this->msrpPriceCalculator + ->expects($this->any()) + ->method('getMsrpPriceValue') + ->willReturn($msrp); $this->productMock->expects($this->any()) ->method('getPriceInfo') - ->will($this->returnValue($priceInfoMock)); + ->willReturn($priceInfoMock); $result = $this->helper->isMinimalPriceLessMsrp($this->productMock); $this->assertTrue($result, "isMinimalPriceLessMsrp returned incorrect value"); diff --git a/app/code/Magento/Msrp/composer.json b/app/code/Magento/Msrp/composer.json index e3099aa2f14d6..a2e6da6de5387 100644 --- a/app/code/Magento/Msrp/composer.json +++ b/app/code/Magento/Msrp/composer.json @@ -10,8 +10,6 @@ "magento/module-catalog": "*", "magento/module-downloadable": "*", "magento/module-eav": "*", - "magento/module-grouped-product": "*", - "magento/module-configurable-product": "*", "magento/module-store": "*", "magento/module-tax": "*" }, diff --git a/app/code/Magento/Msrp/etc/di.xml b/app/code/Magento/Msrp/etc/di.xml index 6f197f769d412..b8392b0bb0fe4 100644 --- a/app/code/Magento/Msrp/etc/di.xml +++ b/app/code/Magento/Msrp/etc/di.xml @@ -7,6 +7,7 @@ --> + diff --git a/app/code/Magento/Msrp/view/base/layout/catalog_product_prices.xml b/app/code/Magento/Msrp/view/base/layout/catalog_product_prices.xml index 9e2dd20638646..b8a3910bf21bc 100644 --- a/app/code/Magento/Msrp/view/base/layout/catalog_product_prices.xml +++ b/app/code/Magento/Msrp/view/base/layout/catalog_product_prices.xml @@ -11,7 +11,7 @@ - Magento\Catalog\Pricing\Render\PriceBox + Magento\Msrp\Pricing\Render\PriceBox Magento_Msrp::product/price/msrp.phtml diff --git a/app/code/Magento/Msrp/view/base/templates/product/price/msrp.phtml b/app/code/Magento/Msrp/view/base/templates/product/price/msrp.phtml index a951c14cf4c70..a428df57ab113 100644 --- a/app/code/Magento/Msrp/view/base/templates/product/price/msrp.phtml +++ b/app/code/Magento/Msrp/view/base/templates/product/price/msrp.phtml @@ -9,7 +9,7 @@ /** * Template for displaying product price at product view page, gift registry and wish-list * - * @var $block \Magento\Catalog\Pricing\Render\PriceBox + * @var $block \Magento\Msrp\Pricing\Render\PriceBox */ ?> getPrice(); $product = $block->getSaleableItem(); $productId = $product->getId(); -$amount = 0; -if ($product->getMsrp()) { - $amount = $product->getMsrp(); -} elseif ($product->getTypeId() === \Magento\GroupedProduct\Model\Product\Type\Grouped::TYPE_CODE) { - $amount = $product->getTypeInstance()->getChildrenMsrp($product); -} elseif ($product->getTypeId() === \Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE) { - foreach ($product->getTypeInstance()->getUsedProducts($product) as $item) { - if ($item->getMsrp() !== null) { - $prices[] = $item->getMsrp(); - } - } - $amount = $prices ? max($prices) : 0; -} +$amount = $block->getMsrpPriceCalculator()->getMsrpPriceValue($product); $msrpPrice = $block->renderAmount( $priceType->getCustomAmount($amount), diff --git a/app/code/Magento/MsrpConfigurableProduct/Pricing/MsrpPriceCalculator.php b/app/code/Magento/MsrpConfigurableProduct/Pricing/MsrpPriceCalculator.php new file mode 100644 index 0000000000000..b6f5194ab8cbe --- /dev/null +++ b/app/code/Magento/MsrpConfigurableProduct/Pricing/MsrpPriceCalculator.php @@ -0,0 +1,46 @@ +getTypeId() !== Configurable::TYPE_CODE) { + return 0; + } + + /** @var Configurable $configurableProduct */ + $configurableProduct = $product->getTypeInstance(); + $msrp = 0; + $prices = []; + foreach ($configurableProduct->getUsedProducts($product) as $item) { + if ($item->getMsrp() !== null) { + $prices[] = $item->getMsrp(); + } + } + if ($prices) { + $msrp = (float)max($prices); + } + + return $msrp; + } +} diff --git a/app/code/Magento/MsrpConfigurableProduct/README.md b/app/code/Magento/MsrpConfigurableProduct/README.md new file mode 100644 index 0000000000000..8911b6e9e6667 --- /dev/null +++ b/app/code/Magento/MsrpConfigurableProduct/README.md @@ -0,0 +1,3 @@ +# MsrpConfigurableProduct + +**MsrpConfigurableProduct** provides type and resolver information for the Msrp module from the ConfigurableProduct module. \ No newline at end of file diff --git a/app/code/Magento/MsrpConfigurableProduct/composer.json b/app/code/Magento/MsrpConfigurableProduct/composer.json new file mode 100644 index 0000000000000..00c3cf6b03078 --- /dev/null +++ b/app/code/Magento/MsrpConfigurableProduct/composer.json @@ -0,0 +1,27 @@ +{ + "name": "magento/module-msrp-configurable-product", + "description": "N/A", + "config": { + "sort-packages": true + }, + "require": { + "php": "~7.1.3||~7.2.0", + "magento/framework": "*", + "magento/module-catalog": "*", + "magento/module-msrp": "*", + "magento/module-configurable-product": "*" + }, + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\MsrpConfigurableProduct\\": "" + } + } +} diff --git a/app/code/Magento/MsrpConfigurableProduct/etc/di.xml b/app/code/Magento/MsrpConfigurableProduct/etc/di.xml new file mode 100644 index 0000000000000..ea33c81ff7cf5 --- /dev/null +++ b/app/code/Magento/MsrpConfigurableProduct/etc/di.xml @@ -0,0 +1,19 @@ + + + + + + + + \Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE + \Magento\MsrpConfigurableProduct\Pricing\MsrpPriceCalculator + + + + + \ No newline at end of file diff --git a/app/code/Magento/MsrpConfigurableProduct/etc/module.xml b/app/code/Magento/MsrpConfigurableProduct/etc/module.xml new file mode 100644 index 0000000000000..b00e363b0b269 --- /dev/null +++ b/app/code/Magento/MsrpConfigurableProduct/etc/module.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/app/code/Magento/MsrpConfigurableProduct/registration.php b/app/code/Magento/MsrpConfigurableProduct/registration.php new file mode 100644 index 0000000000000..d4d58ec3c013b --- /dev/null +++ b/app/code/Magento/MsrpConfigurableProduct/registration.php @@ -0,0 +1,9 @@ +getTypeId() !== Grouped::TYPE_CODE) { + return 0; + } + + /** @var Grouped $groupedProduct */ + $groupedProduct = $product->getTypeInstance(); + + return $groupedProduct->getChildrenMsrp($product); + } +} diff --git a/app/code/Magento/MsrpGroupedProduct/README.md b/app/code/Magento/MsrpGroupedProduct/README.md new file mode 100644 index 0000000000000..d597ba7fc18a7 --- /dev/null +++ b/app/code/Magento/MsrpGroupedProduct/README.md @@ -0,0 +1,3 @@ +# MsrpGroupedProduct + +**MsrpGroupedProduct** provides type and resolver information for the Msrp module from the GroupedProduct module. \ No newline at end of file diff --git a/app/code/Magento/MsrpGroupedProduct/composer.json b/app/code/Magento/MsrpGroupedProduct/composer.json new file mode 100644 index 0000000000000..a626f199ad6cc --- /dev/null +++ b/app/code/Magento/MsrpGroupedProduct/composer.json @@ -0,0 +1,27 @@ +{ + "name": "magento/module-msrp-grouped-product", + "description": "N/A", + "config": { + "sort-packages": true + }, + "require": { + "php": "~7.1.3||~7.2.0", + "magento/framework": "*", + "magento/module-catalog": "*", + "magento/module-msrp": "*", + "magento/module-grouped-product": "*" + }, + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\MsrpGroupedProduct\\": "" + } + } +} diff --git a/app/code/Magento/MsrpGroupedProduct/etc/di.xml b/app/code/Magento/MsrpGroupedProduct/etc/di.xml new file mode 100644 index 0000000000000..29b25f15bc2c1 --- /dev/null +++ b/app/code/Magento/MsrpGroupedProduct/etc/di.xml @@ -0,0 +1,19 @@ + + + + + + + + \Magento\GroupedProduct\Model\Product\Type\Grouped::TYPE_CODE + \Magento\MsrpGroupedProduct\Pricing\MsrpPriceCalculator + + + + + \ No newline at end of file diff --git a/app/code/Magento/MsrpGroupedProduct/etc/module.xml b/app/code/Magento/MsrpGroupedProduct/etc/module.xml new file mode 100644 index 0000000000000..898dd904b5dfb --- /dev/null +++ b/app/code/Magento/MsrpGroupedProduct/etc/module.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/app/code/Magento/MsrpGroupedProduct/registration.php b/app/code/Magento/MsrpGroupedProduct/registration.php new file mode 100644 index 0000000000000..c5a261e66c640 --- /dev/null +++ b/app/code/Magento/MsrpGroupedProduct/registration.php @@ -0,0 +1,9 @@ +getId() && $subscriber->getCode()) { if ($subscriber->confirm($code)) { - $this->messageManager->addSuccess(__('Your subscription has been confirmed.')); + $this->messageManager->addSuccessMessage(__('Your subscription has been confirmed.')); } else { - $this->messageManager->addError(__('This is an invalid subscription confirmation code.')); + $this->messageManager->addErrorMessage(__('This is an invalid subscription confirmation code.')); } } else { - $this->messageManager->addError(__('This is an invalid subscription ID.')); + $this->messageManager->addErrorMessage(__('This is an invalid subscription ID.')); } } - - $resultRedirect = $this->resultRedirectFactory->create(); - $resultRedirect->setUrl($this->_storeManager->getStore()->getBaseUrl()); - return $resultRedirect; + /** @var \Magento\Framework\Controller\Result\Redirect $redirect */ + $redirect = $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT); + $redirectUrl = $this->_storeManager->getStore()->getBaseUrl(); + return $redirect->setUrl($redirectUrl); } } diff --git a/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php b/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php index 4f46c84894f12..7557f1610b4f4 100644 --- a/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php +++ b/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php @@ -4,6 +4,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Newsletter\Controller\Subscriber; use Magento\Customer\Api\AccountManagementInterface as CustomerAccountManagement; @@ -131,7 +132,7 @@ protected function validateEmailFormat($email) /** * New subscription action * - * @return void + * @return \Magento\Framework\Controller\Result\Redirect */ public function execute() { @@ -160,7 +161,10 @@ public function execute() $this->messageManager->addExceptionMessage($e, __('Something went wrong with the subscription.')); } } - $this->getResponse()->setRedirect($this->_redirect->getRedirectUrl()); + /** @var \Magento\Framework\Controller\Result\Redirect $redirect */ + $redirect = $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT); + $redirectUrl = $this->_redirect->getRedirectUrl(); + return $redirect->setUrl($redirectUrl); } /** diff --git a/app/code/Magento/Newsletter/Controller/Subscriber/Unsubscribe.php b/app/code/Magento/Newsletter/Controller/Subscriber/Unsubscribe.php index 88fa128162700..e37a3786e140a 100644 --- a/app/code/Magento/Newsletter/Controller/Subscriber/Unsubscribe.php +++ b/app/code/Magento/Newsletter/Controller/Subscriber/Unsubscribe.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Newsletter\Controller\Subscriber; use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; @@ -15,7 +16,7 @@ class Unsubscribe extends \Magento\Newsletter\Controller\Subscriber implements H /** * Unsubscribe newsletter. * - * @return \Magento\Backend\Model\View\Result\Redirect + * @return \Magento\Framework\Controller\Result\Redirect */ public function execute() { @@ -25,14 +26,14 @@ public function execute() if ($id && $code) { try { $this->_subscriberFactory->create()->load($id)->setCheckCode($code)->unsubscribe(); - $this->messageManager->addSuccess(__('You unsubscribed.')); + $this->messageManager->addSuccessMessage(__('You unsubscribed.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addException($e, $e->getMessage()); + $this->messageManager->addErrorMessage($e, $e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addException($e, __('Something went wrong while unsubscribing you.')); + $this->messageManager->addErrorMessage($e, __('Something went wrong while unsubscribing you.')); } } - /** @var \Magento\Backend\Model\View\Result\Redirect $redirect */ + /** @var \Magento\Framework\Controller\Result\Redirect $redirect */ $redirect = $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT); $redirectUrl = $this->_redirect->getRedirectUrl(); return $redirect->setUrl($redirectUrl); diff --git a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php index 035013e572833..309bfadab41b3 100644 --- a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php +++ b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php @@ -6,13 +6,11 @@ namespace Magento\Newsletter\Model\Plugin; use Magento\Customer\Api\CustomerRepositoryInterface as CustomerRepository; -use Magento\Customer\Api\Data\CustomerExtensionInterface; use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Newsletter\Model\SubscriberFactory; use Magento\Framework\Api\ExtensionAttributesFactory; -use Magento\Framework\App\ObjectManager; use Magento\Newsletter\Model\ResourceModel\Subscriber; -use Magento\Newsletter\Model\SubscriberFactory; -use Magento\Store\Model\StoreManagerInterface; +use Magento\Customer\Api\Data\CustomerExtensionInterface; /** * Newsletter Plugin for customer @@ -41,29 +39,21 @@ class CustomerPlugin */ private $customerSubscriptionStatus = []; - /** - * @var StoreManagerInterface - */ - private $storeManager; - /** * Initialize dependencies. * * @param SubscriberFactory $subscriberFactory * @param ExtensionAttributesFactory $extensionFactory * @param Subscriber $subscriberResource - * @param StoreManagerInterface|null $storeManager */ public function __construct( SubscriberFactory $subscriberFactory, ExtensionAttributesFactory $extensionFactory, - Subscriber $subscriberResource, - StoreManagerInterface $storeManager = null + Subscriber $subscriberResource ) { $this->subscriberFactory = $subscriberFactory; $this->extensionFactory = $extensionFactory; $this->subscriberResource = $subscriberResource; - $this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class); } /** @@ -164,8 +154,7 @@ public function afterDelete(CustomerRepository $subject, $result, CustomerInterf public function afterGetById(CustomerRepository $subject, CustomerInterface $customer) { $extensionAttributes = $customer->getExtensionAttributes(); - $storeId = $this->storeManager->getStore()->getId(); - $customer->setStoreId($storeId); + if ($extensionAttributes === null) { /** @var CustomerExtensionInterface $extensionAttributes */ $extensionAttributes = $this->extensionFactory->create(CustomerInterface::class); diff --git a/app/code/Magento/Newsletter/Test/Unit/Model/Plugin/CustomerPluginTest.php b/app/code/Magento/Newsletter/Test/Unit/Model/Plugin/CustomerPluginTest.php index 3be28cacc93e0..e809b7e37a432 100644 --- a/app/code/Magento/Newsletter/Test/Unit/Model/Plugin/CustomerPluginTest.php +++ b/app/code/Magento/Newsletter/Test/Unit/Model/Plugin/CustomerPluginTest.php @@ -10,8 +10,6 @@ use Magento\Customer\Api\Data\CustomerExtensionInterface; use Magento\Framework\Api\ExtensionAttributesFactory; use Magento\Newsletter\Model\ResourceModel\Subscriber; -use Magento\Store\Model\Store; -use Magento\Store\Model\StoreManagerInterface; class CustomerPluginTest extends \PHPUnit\Framework\TestCase { @@ -55,11 +53,6 @@ class CustomerPluginTest extends \PHPUnit\Framework\TestCase */ private $customerMock; - /** - * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $storeManagerMock; - protected function setUp() { $this->subscriberFactory = $this->getMockBuilder(\Magento\Newsletter\Model\SubscriberFactory::class) @@ -94,8 +87,6 @@ protected function setUp() ->setMethods(['getExtensionAttributes']) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->storeManagerMock = $this->createMock(StoreManagerInterface::class); - $this->subscriberFactory->expects($this->any())->method('create')->willReturn($this->subscriber); $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -105,7 +96,6 @@ protected function setUp() 'subscriberFactory' => $this->subscriberFactory, 'extensionFactory' => $this->extensionFactoryMock, 'subscriberResource' => $this->subscriberResourceMock, - 'storeManager' => $this->storeManagerMock, ] ); } @@ -216,7 +206,6 @@ public function testAfterGetByIdCreatesExtensionAttributesIfItIsNotSet( ) { $subject = $this->createMock(\Magento\Customer\Api\CustomerRepositoryInterface::class); $subscriber = [$subscriberStatusKey => $subscriberStatusValue]; - $this->prepareStoreData(); $this->extensionFactoryMock->expects($this->any()) ->method('create') @@ -244,7 +233,6 @@ public function testAfterGetByIdSetsIsSubscribedFlagIfItIsNotSet() { $subject = $this->createMock(\Magento\Customer\Api\CustomerRepositoryInterface::class); $subscriber = ['subscriber_id' => 1, 'subscriber_status' => 1]; - $this->prepareStoreData(); $this->customerMock->expects($this->any()) ->method('getExtensionAttributes') @@ -279,17 +267,4 @@ public function afterGetByIdDataProvider() [null, null, false], ]; } - - /** - * Prepare store information - * - * @return void - */ - private function prepareStoreData() - { - $storeId = 1; - $storeMock = $this->createMock(Store::class); - $storeMock->expects($this->any())->method('getId')->willReturn($storeId); - $this->storeManagerMock->expects($this->any())->method('getStore')->willReturn($storeMock); - } } diff --git a/app/code/Magento/PageCache/Test/Mftf/Test/NewProductsListWidgetTest.xml b/app/code/Magento/PageCache/Test/Mftf/Test/NewProductsListWidgetTest.xml index c5871ddc3a373..a3c9e7b39217d 100644 --- a/app/code/Magento/PageCache/Test/Mftf/Test/NewProductsListWidgetTest.xml +++ b/app/code/Magento/PageCache/Test/Mftf/Test/NewProductsListWidgetTest.xml @@ -9,7 +9,7 @@ - + @@ -18,7 +18,7 @@ - + diff --git a/app/code/Magento/Paypal/Test/Mftf/ActionGroup/OpenPayPalButtonCheckoutPageActionGroup.xml b/app/code/Magento/Paypal/Test/Mftf/ActionGroup/OpenPayPalButtonCheckoutPageActionGroup.xml index 97c7fbc471e97..32c2fab40e97a 100644 --- a/app/code/Magento/Paypal/Test/Mftf/ActionGroup/OpenPayPalButtonCheckoutPageActionGroup.xml +++ b/app/code/Magento/Paypal/Test/Mftf/ActionGroup/OpenPayPalButtonCheckoutPageActionGroup.xml @@ -8,12 +8,15 @@ - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Paypal/Test/Mftf/ActionGroup/OtherPayPalConfigurationActionGroup.xml b/app/code/Magento/Paypal/Test/Mftf/ActionGroup/OtherPayPalConfigurationActionGroup.xml new file mode 100644 index 0000000000000..08ca6c7834384 --- /dev/null +++ b/app/code/Magento/Paypal/Test/Mftf/ActionGroup/OtherPayPalConfigurationActionGroup.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Paypal/Test/Mftf/ActionGroup/PayPalExpressCheckoutConfigurationActionGroup.xml b/app/code/Magento/Paypal/Test/Mftf/ActionGroup/PayPalExpressCheckoutConfigurationActionGroup.xml index 7bf26aceb316a..bae517ffe2f3e 100644 --- a/app/code/Magento/Paypal/Test/Mftf/ActionGroup/PayPalExpressCheckoutConfigurationActionGroup.xml +++ b/app/code/Magento/Paypal/Test/Mftf/ActionGroup/PayPalExpressCheckoutConfigurationActionGroup.xml @@ -8,18 +8,22 @@ + + + + - - - - - - - - - - + + + + + + + + + + diff --git a/app/code/Magento/Paypal/Test/Mftf/Data/PaypalData.xml b/app/code/Magento/Paypal/Test/Mftf/Data/PaypalData.xml index d97e60043cc5d..ae34476e9ac0b 100644 --- a/app/code/Magento/Paypal/Test/Mftf/Data/PaypalData.xml +++ b/app/code/Magento/Paypal/Test/Mftf/Data/PaypalData.xml @@ -38,6 +38,9 @@ 0 + + someMerchantId + @@ -89,4 +92,11 @@ silver black + + myBusinessAccount@magento.com + myApiUsername.magento.com + somePassword + someApiSignature + someMerchantId + diff --git a/app/code/Magento/Paypal/Test/Mftf/Section/OtherPayPalPaymentsConfigSection.xml b/app/code/Magento/Paypal/Test/Mftf/Section/OtherPayPalPaymentsConfigSection.xml new file mode 100644 index 0000000000000..ca8438d5ee06a --- /dev/null +++ b/app/code/Magento/Paypal/Test/Mftf/Section/OtherPayPalPaymentsConfigSection.xml @@ -0,0 +1,31 @@ + + + + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
diff --git a/app/code/Magento/Paypal/Test/Mftf/Section/PayPalExpressCheckoutConfigSection.xml b/app/code/Magento/Paypal/Test/Mftf/Section/PayPalExpressCheckoutConfigSection.xml index 3ac0bb2707556..85f94cd8691a5 100644 --- a/app/code/Magento/Paypal/Test/Mftf/Section/PayPalExpressCheckoutConfigSection.xml +++ b/app/code/Magento/Paypal/Test/Mftf/Section/PayPalExpressCheckoutConfigSection.xml @@ -9,20 +9,24 @@
- - - - - - - - - + + + + + + + + + +
+
+ +
- - - + + +
diff --git a/app/code/Magento/Paypal/Test/Mftf/Section/PaymentsConfigSection.xml b/app/code/Magento/Paypal/Test/Mftf/Section/PaymentsConfigSection.xml new file mode 100644 index 0000000000000..35162cb7d619d --- /dev/null +++ b/app/code/Magento/Paypal/Test/Mftf/Section/PaymentsConfigSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Paypal/Test/Mftf/Test/AdminConfigPaymentsConflictResolutionForPayPal.xml b/app/code/Magento/Paypal/Test/Mftf/Test/AdminConfigPaymentsConflictResolutionForPayPal.xml new file mode 100644 index 0000000000000..b485fcb2a8f9a --- /dev/null +++ b/app/code/Magento/Paypal/Test/Mftf/Test/AdminConfigPaymentsConflictResolutionForPayPal.xml @@ -0,0 +1,276 @@ + + + + + + + + + + <description value="A popup should show when enabling different paypal solutions when one is already enabled for merchant country United Kingdom"/> + <severity value="Major"/> + <testCaseId value="MC-13146"/> + <group value="paypal"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="ConfigPayPalExpressCheckout" stepKey="ConfigPayPalExpress"> + <argument name="credentials" value="SamplePaypalExpressConfig"/> + </actionGroup> + </before> + <after> + <magentoCLI command="config:set paypal/general/merchant_country US" stepKey="setMerchantCountry"/> + <magentoCLI command="config:set payment/paypal_express/active 0" stepKey="disablePayPalExpress"/> + <magentoCLI command="config:set payment/wps_express/active 0" stepKey="disableWPSExpress"/> + <magentoCLI command="config:set payment/hosted_pro/active 0" stepKey="disableHostedProExpress"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!-- Change Merchant Country --> + <comment userInput="Change Merchant Country" stepKey="changeMerchantCountryComment"/> + <waitForElementVisible selector="{{PaymentsConfigSection.merchantCountry}}" stepKey="waitForMerchantCountry"/> + <selectOption selector="{{PaymentsConfigSection.merchantCountry}}" userInput="United Kingdom" stepKey="setMerchantCountry"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <!-- Enable WPS Express --> + <comment userInput="Enable WPS Express" stepKey="enableWPSExpressComment"/> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableWPSExpress"> + <argument name="payPalConfigType" value="WPSExpressConfigSection"/> + <argument name="countryCode" value="gb"/> + </actionGroup> + <!-- Check only the correct solution is enabled --> + <comment userInput="Check only the correct solution is enabled" stepKey="checkOnlyTheCorrectSolutionIsEnabledComment1"/> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkPayPalExpressIsDisabled"> + <argument name="payPalConfigType" value="PayPalExpressCheckoutConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="gb"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsEnabled"> + <argument name="payPalConfigType" value="WPSExpressConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="gb"/> + </actionGroup> + <!-- Enable Pro Hosted With Express Checkout --> + <comment userInput="Enable Pro Hosted With Express Checkout" stepKey="enableProHostedWithExpressCheckoutComment"/> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableProHostedWithExpressCheckou"> + <argument name="payPalConfigType" value="PaymentsProHostedWithExpressCheckoutConfigSection"/> + <argument name="countryCode" value="gb"/> + </actionGroup> + <!-- Check only the correct solution is enabled --> + <comment userInput="Check only the correct solution is enabled" stepKey="checkOnlyTheCorrectSolutionIsEnabledComment2"/> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsDisabled"> + <argument name="payPalConfigType" value="WPSExpressConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="gb"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkProHostedIsEnabled"> + <argument name="payPalConfigType" value="PaymentsProHostedWithExpressCheckoutConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="gb"/> + </actionGroup> + </test> + <test name="AdminConfigPaymentsConflictResolutionForPayPalInJapan" extends="AdminConfigPaymentsConflictResolutionForPayPalInUnitedKingdom"> + <annotations> + <features value="PayPal"/> + <stories value="Payment methods"/> + <title value="Conflict resolution for PayPal in Japan"/> + <description value="A popup should show when enabling different paypal solutions when one is already enabled for merchant country Japan"/> + <severity value="Major"/> + <testCaseId value="MC-13146"/> + <group value="paypal"/> + </annotations> + <selectOption selector="{{PaymentsConfigSection.merchantCountry}}" userInput="Japan" stepKey="setMerchantCountry"/> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableWPSExpress"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="countryCode" value="jp"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkPayPalExpressIsDisabled"> + <argument name="payPalConfigType" value="PayPalExpressCheckoutOtherCountryConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="jp"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsEnabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="jp"/> + </actionGroup> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableProHostedWithExpressCheckou"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="countryCode" value="jp"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsDisabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="jp"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkProHostedIsEnabled"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="jp"/> + </actionGroup> + </test> + <test name="AdminConfigPaymentsConflictResolutionForPayPalInFrance" extends="AdminConfigPaymentsConflictResolutionForPayPalInUnitedKingdom"> + <annotations> + <features value="PayPal"/> + <stories value="Payment methods"/> + <title value="Conflict resolution for PayPal in France"/> + <description value="A popup should show when enabling different paypal solutions when one is already enabled for merchant country France"/> + <severity value="Major"/> + <testCaseId value="MC-13146"/> + <group value="paypal"/> + </annotations> + <selectOption selector="{{PaymentsConfigSection.merchantCountry}}" userInput="France" stepKey="setMerchantCountry"/> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableWPSExpress"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="countryCode" value="fr"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkPayPalExpressIsDisabled"> + <argument name="payPalConfigType" value="PayPalExpressCheckoutOtherCountryConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="fr"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsEnabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="fr"/> + </actionGroup> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableProHostedWithExpressCheckou"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="countryCode" value="fr"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsDisabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="fr"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkProHostedIsEnabled"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="fr"/> + </actionGroup> + </test> + <test name="AdminConfigPaymentsConflictResolutionForPayPalInHongKong" extends="AdminConfigPaymentsConflictResolutionForPayPalInUnitedKingdom"> + <annotations> + <features value="PayPal"/> + <stories value="Payment methods"/> + <title value="Conflict resolution for PayPal in Hong Kong"/> + <description value="A popup should show when enabling different paypal solutions when one is already enabled for merchant country Hong Kong"/> + <severity value="Major"/> + <testCaseId value="MC-13146"/> + <group value="paypal"/> + </annotations> + <selectOption selector="{{PaymentsConfigSection.merchantCountry}}" userInput="Hong Kong SAR China" stepKey="setMerchantCountry"/> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableWPSExpress"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="countryCode" value="hk"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkPayPalExpressIsDisabled"> + <argument name="payPalConfigType" value="PayPalExpressCheckoutOtherCountryConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="hk"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsEnabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="hk"/> + </actionGroup> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableProHostedWithExpressCheckou"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="countryCode" value="hk"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsDisabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="hk"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkProHostedIsEnabled"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="hk"/> + </actionGroup> + </test> + <test name="AdminConfigPaymentsConflictResolutionForPayPalInItaly" extends="AdminConfigPaymentsConflictResolutionForPayPalInUnitedKingdom"> + <annotations> + <features value="PayPal"/> + <stories value="Payment methods"/> + <title value="Conflict resolution for PayPal in Italy"/> + <description value="A popup should show when enabling different paypal solutions when one is already enabled for merchant country Italy"/> + <severity value="Major"/> + <testCaseId value="MC-13146"/> + <group value="paypal"/> + </annotations> + <selectOption selector="{{PaymentsConfigSection.merchantCountry}}" userInput="Italy" stepKey="setMerchantCountry"/> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableWPSExpress"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="countryCode" value="it"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkPayPalExpressIsDisabled"> + <argument name="payPalConfigType" value="PayPalExpressCheckoutOtherCountryConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="it"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsEnabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="it"/> + </actionGroup> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableProHostedWithExpressCheckou"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="countryCode" value="it"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsDisabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="it"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkProHostedIsEnabled"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="it"/> + </actionGroup> + </test> + <test name="AdminConfigPaymentsConflictResolutionForPayPalInSpain" extends="AdminConfigPaymentsConflictResolutionForPayPalInUnitedKingdom"> + <annotations> + <features value="PayPal"/> + <stories value="Payment methods"/> + <title value="Conflict resolution for PayPal in Spain"/> + <description value="A popup should show when enabling different paypal solutions when one is already enabled for merchant country Spain"/> + <severity value="Major"/> + <testCaseId value="MC-13146"/> + <group value="paypal"/> + </annotations> + <selectOption selector="{{PaymentsConfigSection.merchantCountry}}" userInput="Spain" stepKey="setMerchantCountry"/> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableWPSExpress"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="countryCode" value="es"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkPayPalExpressIsDisabled"> + <argument name="payPalConfigType" value="PayPalExpressCheckoutOtherCountryConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="es"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsEnabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="es"/> + </actionGroup> + <actionGroup ref="EnablePayPalConfiguration" stepKey="EnableProHostedWithExpressCheckou"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="countryCode" value="es"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkWPSExpressIsDisabled"> + <argument name="payPalConfigType" value="WPSOtherConfigSection"/> + <argument name="enabledOption" value="No"/> + <argument name="countryCode" value="es"/> + </actionGroup> + <actionGroup ref="CheckEnableOptionPayPalConfiguration" stepKey="checkProHostedIsEnabled"> + <argument name="payPalConfigType" value="WebsitePaymentsPlusConfigSection"/> + <argument name="enabledOption" value="Yes"/> + <argument name="countryCode" value="es"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Paypal/etc/adminhtml/rules/payment_gb.xml b/app/code/Magento/Paypal/etc/adminhtml/rules/payment_gb.xml index 565962518881b..d8b765b9b4d22 100644 --- a/app/code/Magento/Paypal/etc/adminhtml/rules/payment_gb.xml +++ b/app/code/Magento/Paypal/etc/adminhtml/rules/payment_gb.xml @@ -15,7 +15,7 @@ <predicate name="confirm" message="There is already another PayPal solution enabled. Enable this solution instead?" event="deactivate-rule" - > + > <argument name="wps_express">wps_express</argument> </predicate> </event> @@ -39,16 +39,16 @@ <predicate name="confirm" message="There is already another PayPal solution enabled. Enable this solution instead?" event="deactivate-rule" - > + > <argument name="payments_pro_hosted_solution_with_express_checkout">payments_pro_hosted_solution_with_express_checkout</argument> - <argument name="express_checkout_us">express_checkout_us</argument> + <argument name="express_checkout_gb">express_checkout_gb</argument> </predicate> </event> </events> <relation target="payments_pro_hosted_solution_with_express_checkout"> <rule type="disable" event="activate-rule"/> </relation> - <relation target="express_checkout_us"> + <relation target="express_checkout_gb"> <rule type="disable" event="activate-rule"/> </relation> <relation target=":self"> @@ -56,19 +56,19 @@ <rule type="simpleDisable" event="deactivate-rule"/> <rule type="conflict" event=":load"> <argument name="payments_pro_hosted_solution_with_express_checkout">payments_pro_hosted_solution_with_express_checkout</argument> - <argument name="express_checkout_us">express_checkout_us</argument> + <argument name="express_checkout_gb">express_checkout_gb</argument> </rule> </relation> </payment> <!-- Express Checkout --> - <payment id="express_checkout_us"> + <payment id="express_checkout_gb"> <events selector="[data-enable='payment']"> <event value="0" name="deactivate-rule"/> <event value="1" name="activate-rule"> <predicate name="confirm" message="There is already another PayPal solution enabled. Enable this solution instead?" event="deactivate-rule" - > + > <argument name="wps_express">wps_express</argument> </predicate> </event> @@ -98,4 +98,4 @@ <rule type="removeCreditOptionConditional" event=":load"/> </relation> </payment> -</rules> +</rules> \ No newline at end of file diff --git a/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php b/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php index abecec395865d..392a815ed963c 100644 --- a/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php +++ b/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php @@ -256,9 +256,8 @@ protected function _assignProducts(): self foreach ($this as $item) { /** @var ProductInterface $product */ $product = $productCollection->getItemById($item->getProductId()); - $isValidProduct = $this->isValidProduct($product); $qtyOptions = []; - if ($isValidProduct) { + if ($product && $this->isValidProduct($product)) { $product->setCustomOptions([]); $optionProductIds = $this->getOptionProductIds($item, $product, $productCollection); foreach ($optionProductIds as $optionProductId) { diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/ApplyCouponToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ApplyCouponToCart.php index 0af35354758c9..5429d5333b25b 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/ApplyCouponToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ApplyCouponToCart.php @@ -50,12 +50,12 @@ public function __construct( */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) { - if (!isset($args['input']['cart_id'])) { + if (!isset($args['input']['cart_id']) || empty($args['input']['cart_id'])) { throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); } $maskedCartId = $args['input']['cart_id']; - if (!isset($args['input']['coupon_code'])) { + if (!isset($args['input']['coupon_code']) || empty($args['input']['coupon_code'])) { throw new GraphQlInputException(__('Required parameter "coupon_code" is missing')); } $couponCode = $args['input']['coupon_code']; diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart.php index 2df31841366a1..db74b1fa4174b 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart.php @@ -37,7 +37,7 @@ public function __construct( */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) { - if (!isset($args['cart_id'])) { + if (!isset($args['cart_id']) || empty($args['cart_id'])) { throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); } $maskedCartId = $args['cart_id']; diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php index 68925c6e8944d..5a708ceaedc28 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php @@ -50,7 +50,7 @@ public function __construct( */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) { - if (!isset($args['input']['cart_id'])) { + if (!isset($args['input']['cart_id']) || empty($args['input']['cart_id'])) { throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); } $maskedCartId = $args['input']['cart_id']; diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveItemFromCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveItemFromCart.php index c8f0ef06c7594..63e66f121f555 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveItemFromCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveItemFromCart.php @@ -14,7 +14,7 @@ use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Quote\Api\GuestCartItemRepositoryInterface; +use Magento\Quote\Api\CartItemRepositoryInterface; use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; /** @@ -23,25 +23,25 @@ class RemoveItemFromCart implements ResolverInterface { /** - * @var GuestCartItemRepositoryInterface + * @var GetCartForUser */ - private $guestCartItemRepository; + private $getCartForUser; /** - * @var GetCartForUser + * @var CartItemRepositoryInterface */ - private $getCartForUser; + private $cartItemRepository; /** - * @param GuestCartItemRepositoryInterface $guestCartItemRepository * @param GetCartForUser $getCartForUser + * @param CartItemRepositoryInterface $cartItemRepository */ public function __construct( - GuestCartItemRepositoryInterface $guestCartItemRepository, - GetCartForUser $getCartForUser + GetCartForUser $getCartForUser, + CartItemRepositoryInterface $cartItemRepository ) { - $this->guestCartItemRepository = $guestCartItemRepository; $this->getCartForUser = $getCartForUser; + $this->cartItemRepository = $cartItemRepository; } /** @@ -49,20 +49,20 @@ public function __construct( */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) { - if (!isset($args['input']['cart_id'])) { - throw new GraphQlInputException(__('Required parameter "cart_id" is missing')); + if (!isset($args['input']['cart_id']) || empty($args['input']['cart_id'])) { + throw new GraphQlInputException(__('Required parameter "cart_id" is missing.')); } $maskedCartId = $args['input']['cart_id']; - if (!isset($args['input']['cart_item_id'])) { - throw new GraphQlInputException(__('Required parameter "cart_item_id" is missing')); + if (!isset($args['input']['cart_item_id']) || empty($args['input']['cart_item_id'])) { + throw new GraphQlInputException(__('Required parameter "cart_item_id" is missing.')); } $itemId = $args['input']['cart_item_id']; $cart = $this->getCartForUser->execute($maskedCartId, $context->getUserId()); try { - $this->guestCartItemRepository->deleteById($maskedCartId, $itemId); + $this->cartItemRepository->deleteById((int)$cart->getId(), $itemId); } catch (NoSuchEntityException $e) { throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e); } catch (LocalizedException $e) { diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/UpdateCartItems.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/UpdateCartItems.php new file mode 100644 index 0000000000000..78a07506556c0 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/UpdateCartItems.php @@ -0,0 +1,118 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Quote\Api\CartItemRepositoryInterface; +use Magento\Quote\Model\Quote; +use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; + +/** + * @inheritdoc + */ +class UpdateCartItems implements ResolverInterface +{ + /** + * @var GetCartForUser + */ + private $getCartForUser; + + /** + * @var CartItemRepositoryInterface + */ + private $cartItemRepository; + + /** + * @param GetCartForUser $getCartForUser + * @param CartItemRepositoryInterface $cartItemRepository + */ + public function __construct( + GetCartForUser $getCartForUser, + CartItemRepositoryInterface $cartItemRepository + ) { + $this->getCartForUser = $getCartForUser; + $this->cartItemRepository = $cartItemRepository; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (!isset($args['input']['cart_id']) || empty($args['input']['cart_id'])) { + throw new GraphQlInputException(__('Required parameter "cart_id" is missing.')); + } + $maskedCartId = $args['input']['cart_id']; + + if (!isset($args['input']['cart_items']) || empty($args['input']['cart_items']) + || !is_array($args['input']['cart_items']) + ) { + throw new GraphQlInputException(__('Required parameter "cart_items" is missing.')); + } + $cartItems = $args['input']['cart_items']; + + $cart = $this->getCartForUser->execute($maskedCartId, $context->getUserId()); + + try { + $this->processCartItems($cart, $cartItems); + } catch (NoSuchEntityException $e) { + throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e); + } catch (LocalizedException $e) { + throw new GraphQlInputException(__($e->getMessage()), $e); + } + + return [ + 'cart' => [ + 'model' => $cart, + ], + ]; + } + + /** + * Process cart items + * + * @param Quote $cart + * @param array $items + * @throws GraphQlInputException + * @throws LocalizedException + */ + private function processCartItems(Quote $cart, array $items): void + { + foreach ($items as $item) { + if (!isset($item['cart_item_id']) || empty($item['cart_item_id'])) { + throw new GraphQlInputException(__('Required parameter "cart_item_id" for "cart_items" is missing.')); + } + $itemId = $item['cart_item_id']; + + if (!isset($item['quantity'])) { + throw new GraphQlInputException(__('Required parameter "quantity" for "cart_items" is missing.')); + } + $qty = (float)$item['quantity']; + + $cartItem = $cart->getItemById($itemId); + if ($cartItem === false) { + throw new GraphQlNoSuchEntityException( + __('Could not find cart item with id: %1.', $item['cart_item_id']) + ); + } + + if ($qty <= 0.0) { + $this->cartItemRepository->deleteById((int)$cart->getId(), $itemId); + } else { + $cartItem->setQty($qty); + $this->cartItemRepository->save($cartItem); + } + } + } +} diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 5f65a990bac21..79cea3855f6f3 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -11,6 +11,7 @@ type Mutation { addVirtualProductsToCart(input: AddVirtualProductsToCartInput): AddVirtualProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart") removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\RemoveCouponFromCart") + updateCartItems(input: UpdateCartItemsInput): UpdateCartItemsOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\UpdateCartItems") removeItemFromCart(input: RemoveItemFromCartInput): RemoveItemFromCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\RemoveItemFromCart") setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetShippingAddressesOnCart") setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetBillingAddressOnCart") @@ -53,6 +54,16 @@ input ApplyCouponToCartInput { coupon_code: String! } +input UpdateCartItemsInput { + cart_id: String! + cart_items: [CartItemQuantityInput!]! +} + +input CartItemQuantityInput { + cart_item_id: Int! + quantity: Float! +} + input RemoveItemFromCartInput { cart_id: String! cart_item_id: Int! @@ -230,6 +241,10 @@ type AddVirtualProductsToCartOutput { cart: Cart! } +type UpdateCartItemsOutput { + cart: Cart! +} + type RemoveItemFromCartOutput { cart: Cart! } diff --git a/app/code/Magento/Sales/Model/Service/InvoiceService.php b/app/code/Magento/Sales/Model/Service/InvoiceService.php index ba6ae7eb14ba7..02242e92c8bf5 100644 --- a/app/code/Magento/Sales/Model/Service/InvoiceService.php +++ b/app/code/Magento/Sales/Model/Service/InvoiceService.php @@ -190,6 +190,11 @@ private function prepareItemsQty(Order $order, array $qtys = []) if ($orderItem->getProductType() == Type::TYPE_BUNDLE && !$orderItem->isShipSeparately()) { $qtys[$orderItem->getId()] = $orderItem->getQtyOrdered() - $orderItem->getQtyInvoiced(); } else { + $parentItem = $orderItem->getParentItem(); + $parentItemId = $parentItem ? $parentItem->getId() : null; + if ($parentItemId && isset($qtys[$parentItemId])) { + $qtys[$orderItem->getId()] = $qtys[$parentItemId]; + } continue; } } diff --git a/app/code/Magento/Sales/view/frontend/email/shipment_new.html b/app/code/Magento/Sales/view/frontend/email/shipment_new.html index 8af49f322c682..84f5acb29ea3b 100644 --- a/app/code/Magento/Sales/view/frontend/email/shipment_new.html +++ b/app/code/Magento/Sales/view/frontend/email/shipment_new.html @@ -53,7 +53,7 @@ <h1>{{trans "Your Shipment #%shipment_id for Order #%order_id" shipment_id=$ship </tr> </table> {{/depend}} - {{block class='Magento\\Framework\\View\\Element\\Template' area='frontend' template='Magento_Sales::email/shipment/track.phtml' shipment=$shipment order=$order}} + {{layout handle="sales_email_order_shipment_track" shipment=$shipment order=$order}} <table class="order-details"> <tr> <td class="address-details"> diff --git a/app/code/Magento/Sales/view/frontend/email/shipment_new_guest.html b/app/code/Magento/Sales/view/frontend/email/shipment_new_guest.html index df1677f56a500..bb181126724da 100644 --- a/app/code/Magento/Sales/view/frontend/email/shipment_new_guest.html +++ b/app/code/Magento/Sales/view/frontend/email/shipment_new_guest.html @@ -51,7 +51,7 @@ <h1>{{trans "Your Shipment #%shipment_id for Order #%order_id" shipment_id=$ship </tr> </table> {{/depend}} - {{block class='Magento\\Framework\\View\\Element\\Template' area='frontend' template='Magento_Sales::email/shipment/track.phtml' shipment=$shipment order=$order}} + {{layout handle="sales_email_order_shipment_track" shipment=$shipment order=$order}} <table class="order-details"> <tr> <td class="address-details"> diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_track.xml b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_track.xml new file mode 100644 index 0000000000000..91414663951d3 --- /dev/null +++ b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_track.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <update handle="sales_email_order_shipment_renderers"/> + <body> + <block class="Magento\Framework\View\Element\Template" name="sales.order.email.shipment.track" template="Magento_Sales::email/shipment/track.phtml"/> + </body> +</page> \ No newline at end of file diff --git a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php index 5e6f3847c8e31..3e7b6ea281501 100644 --- a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php +++ b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php @@ -9,6 +9,9 @@ use Magento\Framework\DB\Select; use Magento\Framework\Serialize\Serializer\Json; use Magento\Quote\Model\Quote\Address; +use Magento\SalesRule\Api\Data\CouponInterface; +use Magento\SalesRule\Model\Coupon; +use Magento\SalesRule\Model\Rule; /** * Sales Rules resource collection model. @@ -107,12 +110,15 @@ protected function mapAssociatedEntities($entityType, $objectField) $associatedEntities = $this->getConnection()->fetchAll($select); - array_map(function ($associatedEntity) use ($entityInfo, $ruleIdField, $objectField) { - $item = $this->getItemByColumnValue($ruleIdField, $associatedEntity[$ruleIdField]); - $itemAssociatedValue = $item->getData($objectField) === null ? [] : $item->getData($objectField); - $itemAssociatedValue[] = $associatedEntity[$entityInfo['entity_id_field']]; - $item->setData($objectField, $itemAssociatedValue); - }, $associatedEntities); + array_map( + function ($associatedEntity) use ($entityInfo, $ruleIdField, $objectField) { + $item = $this->getItemByColumnValue($ruleIdField, $associatedEntity[$ruleIdField]); + $itemAssociatedValue = $item->getData($objectField) ?? []; + $itemAssociatedValue[] = $associatedEntity[$entityInfo['entity_id_field']]; + $item->setData($objectField, $itemAssociatedValue); + }, + $associatedEntities + ); } /** @@ -141,6 +147,7 @@ protected function _afterLoad() * @param string $couponCode * @param string|null $now * @param Address $address allow extensions to further filter out rules based on quote address + * @throws \Zend_Db_Select_Exception * @use $this->addWebsiteGroupDateFilter() * @SuppressWarnings(PHPMD.UnusedFormalParameter) * @return $this @@ -153,32 +160,24 @@ public function setValidationFilter( Address $address = null ) { if (!$this->getFlag('validation_filter')) { - /* We need to overwrite joinLeft if coupon is applied */ - $this->getSelect()->reset(); - parent::_initSelect(); + $this->prepareSelect($websiteId, $customerGroupId, $now); - $this->addWebsiteGroupDateFilter($websiteId, $customerGroupId, $now); - $select = $this->getSelect(); + $noCouponRules = $this->getNoCouponCodeSelect(); - $connection = $this->getConnection(); - if (strlen($couponCode)) { - $noCouponWhereCondition = $connection->quoteInto( - 'main_table.coupon_type = ?', - \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON - ); - $relatedRulesIds = $this->getCouponRelatedRuleIds($couponCode); - - $select->where( - $noCouponWhereCondition . ' OR main_table.rule_id IN (?)', - $relatedRulesIds, - Select::TYPE_CONDITION - ); + if ($couponCode) { + $couponRules = $this->getCouponCodeSelect($couponCode); + + $allAllowedRules = $this->getConnection()->select(); + $allAllowedRules->union([$noCouponRules, $couponRules], Select::SQL_UNION_ALL); + + $wrapper = $this->getConnection()->select(); + $wrapper->from($allAllowedRules); + + $this->_select = $wrapper; } else { - $this->addFieldToFilter( - 'main_table.coupon_type', - \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON - ); + $this->_select = $noCouponRules; } + $this->setOrder('sort_order', self::SORT_ORDER_ASC); $this->setFlag('validation_filter', true); } @@ -187,72 +186,98 @@ public function setValidationFilter( } /** - * Get rules ids related to coupon code + * Recreate the default select object for specific needs of salesrule evaluation with coupon codes. * - * @param string $couponCode - * @return array + * @param int $websiteId + * @param int $customerGroupId + * @param string $now */ - private function getCouponRelatedRuleIds(string $couponCode): array + private function prepareSelect($websiteId, $customerGroupId, $now) { - $connection = $this->getConnection(); - $select = $connection->select()->from( - ['main_table' => $this->getTable('salesrule')], - 'rule_id' + $this->getSelect()->reset(); + parent::_initSelect(); + + $this->addWebsiteGroupDateFilter($websiteId, $customerGroupId, $now); + } + + /** + * Return select object to determine all active rules not needing a coupon code. + * + * @return Select + */ + private function getNoCouponCodeSelect() + { + $noCouponSelect = clone $this->getSelect(); + + $noCouponSelect->where( + 'main_table.coupon_type = ?', + Rule::COUPON_TYPE_NO_COUPON ); - $select->joinLeft( - ['rule_coupons' => $this->getTable('salesrule_coupon')], - $connection->quoteInto( - 'main_table.rule_id = rule_coupons.rule_id AND main_table.coupon_type != ?', - \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON, - null - ) + + $noCouponSelect->columns([Coupon::KEY_CODE => new \Zend_Db_Expr('NULL')]); + + return $noCouponSelect; + } + + /** + * Determine all active rules that are valid for the given coupon code. + * + * @param string $couponCode + * @return Select + */ + private function getCouponCodeSelect($couponCode) + { + $couponSelect = clone $this->getSelect(); + + $this->joinCouponTable($couponCode, $couponSelect); + + $notExpired = $this->getConnection()->quoteInto( + '(rule_coupons.expiration_date IS NULL OR rule_coupons.expiration_date >= ?)', + $this->_date->date()->format('Y-m-d') ); - $autoGeneratedCouponCondition = [ - $connection->quoteInto( - "main_table.coupon_type = ?", - \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO - ), - $connection->quoteInto( - "rule_coupons.type = ?", - \Magento\SalesRule\Api\Data\CouponInterface::TYPE_GENERATED - ), - ]; - - $orWhereConditions = [ - "(" . implode($autoGeneratedCouponCondition, " AND ") . ")", - $connection->quoteInto( - '(main_table.coupon_type = ? AND main_table.use_auto_generation = 1 AND rule_coupons.type = 1)', - \Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC - ), - $connection->quoteInto( - '(main_table.coupon_type = ? AND main_table.use_auto_generation = 0 AND rule_coupons.type = 0)', - \Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC - ), - ]; - - $andWhereConditions = [ - $connection->quoteInto( - 'rule_coupons.code = ?', - $couponCode - ), - $connection->quoteInto( - '(rule_coupons.expiration_date IS NULL OR rule_coupons.expiration_date >= ?)', - $this->_date->date()->format('Y-m-d') - ), - ]; - - $orWhereCondition = implode(' OR ', $orWhereConditions); - $andWhereCondition = implode(' AND ', $andWhereConditions); - - $select->where( - '(' . $orWhereCondition . ') AND ' . $andWhereCondition, + $isAutogenerated = + $this->getConnection()->quoteInto('main_table.coupon_type = ?', Rule::COUPON_TYPE_AUTO) + . ' AND ' . + $this->getConnection()->quoteInto('rule_coupons.type = ?', CouponInterface::TYPE_GENERATED); + + $isValidSpecific = + $this->getConnection()->quoteInto('(main_table.coupon_type = ?)', Rule::COUPON_TYPE_SPECIFIC) + . ' AND (' . + '(main_table.use_auto_generation = 1 AND rule_coupons.type = 1)' + . ' OR ' . + '(main_table.use_auto_generation = 0 AND rule_coupons.type = 0)' + . ')'; + + $couponSelect->where( + "$notExpired AND ($isAutogenerated OR $isValidSpecific)", null, Select::TYPE_CONDITION ); - $select->group('main_table.rule_id'); - return $connection->fetchCol($select); + return $couponSelect; + } + + /** + * Join coupong table to select. + * + * @param string $couponCode + * @param Select $couponSelect + */ + private function joinCouponTable($couponCode, Select $couponSelect) + { + $couponJoinCondition = + 'main_table.rule_id = rule_coupons.rule_id' + . ' AND ' . + $this->getConnection()->quoteInto('main_table.coupon_type <> ?', Rule::COUPON_TYPE_NO_COUPON) + . ' AND ' . + $this->getConnection()->quoteInto('rule_coupons.code = ?', $couponCode); + + $couponSelect->joinInner( + ['rule_coupons' => $this->getTable('salesrule_coupon')], + $couponJoinCondition, + [Coupon::KEY_CODE] + ); } /** diff --git a/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml b/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml index 2b08e9b4b85ec..3c2909b59c0de 100644 --- a/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml +++ b/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml @@ -11,5 +11,6 @@ <section name="StorefrontQuickSearchSection"> <element name="searchPhrase" type="input" selector="#search"/> <element name="searchButton" type="button" selector="button.action.search" timeout="30"/> + <element name="searchMiniForm" type="input" selector="#search_mini_form"/> </section> </sections> diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateNewStoreGroupActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateNewStoreGroupActionGroup.xml index 91fe4fccddb91..7f1a63d3db6f2 100644 --- a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateNewStoreGroupActionGroup.xml +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateNewStoreGroupActionGroup.xml @@ -25,4 +25,21 @@ <waitForElementVisible selector="{{AdminStoresGridSection.storeGrpFilterTextField}}" stepKey="waitForStoreGridReload"/> <see userInput="You saved the store." stepKey="seeSavedMessage" /> </actionGroup> + <actionGroup name="CreateCustomStore"> + <arguments> + <argument name="website" type="string"/> + <argument name="store" type="string"/> + <argument name="rootCategory" type="string"/> + </arguments> + <amOnPage url="{{AdminSystemStorePage.url}}" stepKey="amOnAdminSystemStorePage"/> + <waitForPageLoad stepKey="waitForSystemStorePage"/> + <click selector="{{AdminStoresMainActionsSection.createStoreButton}}" stepKey="selectCreateStore"/> + <selectOption userInput="{{website}}" selector="{{AdminNewStoreGroupSection.storeGrpWebsiteDropdown}}" stepKey="selectMainWebsite"/> + <fillField userInput="{{store}}" selector="{{AdminNewStoreGroupSection.storeGrpNameTextField}}" stepKey="fillStoreName"/> + <fillField userInput="{{store}}" selector="{{AdminNewStoreGroupSection.storeGrpCodeTextField}}" stepKey="fillStoreCode"/> + <selectOption userInput="{{rootCategory}}" selector="{{AdminNewStoreGroupSection.storeRootCategoryDropdown}}" stepKey="selectStoreStatus"/> + <click selector="{{AdminStoreGroupActionsSection.saveButton}}" stepKey="clickSaveStoreGroup" /> + <waitForElementVisible selector="{{AdminStoresGridSection.storeGrpFilterTextField}}" stepKey="waitForStoreGridReload"/> + <see userInput="You saved the store." stepKey="seeSavedMessage"/> + </actionGroup> </actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/DeleteCustomStoreActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/DeleteCustomStoreActionGroup.xml index 8e32b819aa954..8a1d830661aad 100644 --- a/app/code/Magento/Store/Test/Mftf/ActionGroup/DeleteCustomStoreActionGroup.xml +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/DeleteCustomStoreActionGroup.xml @@ -23,4 +23,33 @@ <selectOption userInput="No" selector="{{AdminStoresDeleteStoreGroupSection.createDbBackup}}" stepKey="setCreateDbBackupToNo"/> <click selector="{{AdminStoresDeleteStoreGroupSection.deleteStoreGroupButton}}" stepKey="clickDeleteStoreGroupButtonOnDeleteStorePage"/> </actionGroup> -</actionGroups> + <actionGroup name="DeleteCustomStoreBackupEnabledYesActionGroup"> + <arguments> + <argument name="storeGroupName" type="string"/> + </arguments> + <amOnPage url="{{AdminSystemStorePage.url}}" stepKey="amOnAdminSystemStorePage"/> + <click selector="{{AdminStoresGridSection.resetButton}}" stepKey="resetSearchFilter"/> + <fillField userInput="{{storeGroupName}}" selector="{{AdminStoresGridSection.storeGrpFilterTextField}}" stepKey="fillSearchStoreGroupField"/> + <click selector="{{AdminStoresGridSection.searchButton}}" stepKey="clickSearchButton"/> + <see userInput="{{storeGroupName}}" selector="{{AdminStoresGridSection.storeGrpNameInFirstRow}}" stepKey="verifyThatCorrectStoreGroupFound"/> + <click selector="{{AdminStoresGridSection.storeGrpNameInFirstRow}}" stepKey="clickEditExistingStoreRow"/> + <waitForPageLoad stepKey="waitForStoreToLoad"/> + <click selector="{{AdminStoresMainActionsSection.deleteButton}}" stepKey="clickDeleteStoreGroupButtonOnEditStorePage"/> + <selectOption userInput="Yes" selector="{{AdminStoresDeleteStoreGroupSection.createDbBackup}}" stepKey="setCreateDbBackupToNo"/> + <click selector="{{AdminStoresDeleteStoreGroupSection.deleteStoreGroupButton}}" stepKey="clickDeleteStoreGroupButtonOnDeleteStorePage"/> + <see selector="{{AdminStoresGridSection.successMessage}}" userInput="The database was backed up." stepKey="seeAssertDatabaseBackedUpMessage"/> + <see selector="{{AdminStoresGridSection.successMessage}}" userInput="You deleted the store." stepKey="seeAssertSuccessDeleteStoreGroupMessage"/> + </actionGroup> + <actionGroup name="AssertStoreNotInGrid"> + <arguments> + <argument name="storeGroupName" type="string"/> + </arguments> + <amOnPage url="{{AdminSystemStorePage.url}}" stepKey="amOnAdminSystemStorePage"/> + <waitForPageLoad stepKey="waitForAdminSystemStorePageLoad"/> + <click selector="{{AdminStoresGridSection.resetButton}}" stepKey="resetSearchFilter"/> + <fillField userInput="{{storeGroupName}}" selector="{{AdminStoresGridSection.storeGrpFilterTextField}}" stepKey="fillSearchStoreGroupField"/> + <click selector="{{AdminStoresGridSection.searchButton}}" stepKey="clickSearchButton"/> + <waitForPageLoad stepKey="waitForStoreToLoad"/> + <see selector="{{AdminStoresGridSection.emptyText}}" userInput="We couldn't find any records." stepKey="seeAssertStoreGroupNotInGridMessage"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Store/Test/Mftf/Section/AdminStoresGridSection.xml b/app/code/Magento/Store/Test/Mftf/Section/AdminStoresGridSection.xml index b02e9adaed45e..592af42f2de30 100644 --- a/app/code/Magento/Store/Test/Mftf/Section/AdminStoresGridSection.xml +++ b/app/code/Magento/Store/Test/Mftf/Section/AdminStoresGridSection.xml @@ -21,5 +21,7 @@ <element name="storeGrpNameInFirstRow" type="text" selector=".col-group_title>a"/> <element name="storeNameInFirstRow" type="text" selector=".col-store_title>a"/> <element name="firstRow" type="textarea" selector="(//*[@id='storeGrid_table']/tbody/tr)[1]"/> + <element name="successMessage" type="text" selector="//div[@class='message message-success success']/div"/> + <element name="emptyText" type="text" selector="//tr[@class='data-grid-tr-no-data even']/td[@class='empty-text']"/> </section> </sections> diff --git a/app/code/Magento/Store/Test/Mftf/Section/StorefrontHeaderSection.xml b/app/code/Magento/Store/Test/Mftf/Section/StorefrontHeaderSection.xml index 8004b750a4d1f..416808e58e6b3 100644 --- a/app/code/Magento/Store/Test/Mftf/Section/StorefrontHeaderSection.xml +++ b/app/code/Magento/Store/Test/Mftf/Section/StorefrontHeaderSection.xml @@ -13,5 +13,6 @@ <element name="storeViewOption" type="button" selector="li.view-{{var1}}>a" parameterized="true"/> <element name="storeView" type="button" selector="//div[@class='actions dropdown options switcher-options active']//ul//li//a[contains(text(),'{{var}}')]" parameterized="true"/> <element name="storeViewList" type="button" selector="//li[contains(.,'{{storeViewName}}')]//a" parameterized="true"/> + <element name="storeViewName" type="text" selector="//*[@id='switcher-language-trigger']//span"/> </section> </sections> diff --git a/app/code/Magento/Store/Test/Mftf/Test/AdminDeleteStoreGroupTest.xml b/app/code/Magento/Store/Test/Mftf/Test/AdminDeleteStoreGroupTest.xml new file mode 100644 index 0000000000000..652537f7864cd --- /dev/null +++ b/app/code/Magento/Store/Test/Mftf/Test/AdminDeleteStoreGroupTest.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- Test XML Example --> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminDeleteStoreGroupTest"> + <annotations> + <stories value="Delete Store Group"/> + <title value="Delete store group and save backup"/> + <description value="Test log in to Stores and Delete Store Group Test"/> + <testCaseId value="MC-14297"/> + <severity value="CRITICAL"/> + <group value="store"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <magentoCLI command="config:set system/backup/functionality_enabled 1" stepKey="setEnableBackupToYes"/> + <actionGroup ref = "LoginAsAdmin" stepKey="loginAsAdmin"/> + <!--Create custom store group--> + <actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createNewCustomStoreGroup"> + <argument name="website" value="{{_defaultWebsite.name}}"/> + <argument name="storeGroupName" value="{{customStore.name}}"/> + <argument name="storeGroupCode" value="{{customStore.code}}"/> + </actionGroup> + </before> + <after> + <magentoCLI command="config:set system/backup/functionality_enabled 0" stepKey="setEnableBackupToNo"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Delete custom store group and verify AssertStoreGroupSuccessDeleteAndBackupMessages--> + <actionGroup ref="DeleteCustomStoreBackupEnabledYesActionGroup" stepKey="deleteCustomStoreGroup"> + <argument name="storeGroupName" value="{{customStore.name}}"/> + </actionGroup> + + <!--Verify deleted Store group is not present in grid and verify AssertStoreGroupNotInGrid message--> + <actionGroup ref="AssertStoreNotInGrid" stepKey="verifyDeletedStoreGroupNotInGrid"> + <argument name="storeGroupName" value="{{customStore.name}}"/> + </actionGroup> + + <!--Go to backup index page and verify AssertBackupInGrid--> + <amOnPage url="{{BackupIndexPage.url}}" stepKey="goToBackupIndexPage"/> + <waitForPageLoad stepKey="waitForBackupIndexPageLoad"/> + <see selector="{{AdminGridTableSection.backupNameColumn}}" userInput="{{WebSetupWizardBackup.name}}" stepKey="seeBackupInGrid"/> + <!--Delete database backup--> + <actionGroup ref="deleteBackup" stepKey="deleteDatabaseBackup"> + <argument name="backup" value="WebSetupWizardBackup"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js index a18e03ad52a9e..2080652210a53 100644 --- a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js +++ b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js @@ -924,7 +924,8 @@ define([ $productPrice = $product.find(this.options.selectorProductPrice), options = _.object(_.keys($widget.optionsMap), {}), result, - tierPriceHtml; + tierPriceHtml, + isShow; $widget.element.find('.' + $widget.options.classes.attributeClass + '[option-selected]').each(function () { var attributeId = $(this).attr('attribute-id'); @@ -941,11 +942,9 @@ define([ } ); - if (typeof result != 'undefined' && result.oldPrice.amount !== result.finalPrice.amount) { - $(this.options.slyOldPriceSelector).show(); - } else { - $(this.options.slyOldPriceSelector).hide(); - } + isShow = typeof result != 'undefined' && result.oldPrice.amount !== result.finalPrice.amount; + + $product.find(this.options.slyOldPriceSelector)[isShow ? 'show' : 'hide'](); if (typeof result != 'undefined' && result.tierPrices.length) { if (this.options.tierPriceTemplate) { diff --git a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/classes/Formatter.js b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/classes/Formatter.js index f74282afd32a6..b7266779d3a35 100644 --- a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/classes/Formatter.js +++ b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/classes/Formatter.js @@ -1970,7 +1970,7 @@ node.appendChild(dom.doc.createTextNode(invisibleChar)); node = node.firstChild; - // Insert caret container after the formated node + // Insert caret container after the formatted node dom.insertAfter(caretContainer, formatNode); // Move selection to text node diff --git a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_jquery_src.js b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_jquery_src.js index 2d9d859caa6fa..60dd358414be1 100644 --- a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_jquery_src.js +++ b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_jquery_src.js @@ -15796,7 +15796,7 @@ tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', { node.appendChild(dom.doc.createTextNode(invisibleChar)); node = node.firstChild; - // Insert caret container after the formated node + // Insert caret container after the formatted node dom.insertAfter(caretContainer, formatNode); // Move selection to text node diff --git a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_prototype_src.js b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_prototype_src.js index aaa207da3e4a9..ed0b7cb0e50a2 100644 --- a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_prototype_src.js +++ b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_prototype_src.js @@ -16646,7 +16646,7 @@ tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', { node.appendChild(dom.doc.createTextNode(invisibleChar)); node = node.firstChild; - // Insert caret container after the formated node + // Insert caret container after the formatted node dom.insertAfter(caretContainer, formatNode); // Move selection to text node diff --git a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_src.js b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_src.js index 8448152ed5d2f..1c53062dd9690 100644 --- a/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_src.js +++ b/app/code/Magento/Tinymce3/view/base/web/tiny_mce/tiny_mce_src.js @@ -16620,7 +16620,7 @@ tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', { node.appendChild(dom.doc.createTextNode(invisibleChar)); node = node.firstChild; - // Insert caret container after the formated node + // Insert caret container after the formatted node dom.insertAfter(caretContainer, formatNode); // Move selection to text node diff --git a/app/code/Magento/Ui/Test/Mftf/Section/AdminMessagesSection.xml b/app/code/Magento/Ui/Test/Mftf/Section/AdminMessagesSection.xml index 75d445f1ee04e..3d4efa13ce3a0 100644 --- a/app/code/Magento/Ui/Test/Mftf/Section/AdminMessagesSection.xml +++ b/app/code/Magento/Ui/Test/Mftf/Section/AdminMessagesSection.xml @@ -12,5 +12,6 @@ <element name="successMessage" type="text" selector=".message-success"/> <element name="errorMessage" type="text" selector=".message.message-error.error"/> <element name="warningMessage" type="text" selector=".message-warning"/> + <element name="noticeMessage" type="text" selector=".message-notice"/> </section> </sections> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminUrlRewriteActionGroup.xml b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminUrlRewriteActionGroup.xml index 71475acd8b066..e9651a3f26e94 100644 --- a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminUrlRewriteActionGroup.xml +++ b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminUrlRewriteActionGroup.xml @@ -75,4 +75,37 @@ <click selector="{{AdminUrlRewriteEditSection.saveButton}}" stepKey="clickOnSaveButton"/> <seeElement selector="{{AdminUrlRewriteIndexSection.successMessage}}" stepKey="seeSuccessSaveMessage"/> </actionGroup> + <actionGroup name="AdminUpdateUrlRewrite"> + <arguments> + <argument name="storeValue" type="string"/> + <argument name="requestPath" type="string"/> + <argument name="redirectTypeValue" type="string"/> + <argument name="description" type="string"/> + </arguments> + <click selector="{{AdminUrlRewriteEditSection.store}}" stepKey="clickOnStore"/> + <click selector="{{AdminUrlRewriteEditSection.storeValue('storeValue')}}" stepKey="clickOnStoreValue"/> + <fillField selector="{{AdminUrlRewriteEditSection.requestPath}}" userInput="{{requestPath}}" stepKey="fillRequestPath"/> + <click selector="{{AdminUrlRewriteEditSection.redirectType}}" stepKey="selectRedirectType"/> + <click selector="{{AdminUrlRewriteEditSection.redirectTypeValue('redirectTypeValue')}}" stepKey="selectRedirectTypeValue"/> + <fillField selector="{{AdminUrlRewriteEditSection.description}}" userInput="{{description}}" stepKey="fillDescription"/> + <click selector="{{AdminUrlRewriteEditSection.saveButton}}" stepKey="clickOnSaveButton"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.successMessage}}" stepKey="seeSuccessSaveMessage"/> + </actionGroup> + <actionGroup name="AdminUpdateCustomUrlRewrite"> + <arguments> + <argument name="storeValue" type="string"/> + <argument name="requestPath" type="string"/> + <argument name="targetPath" type="string"/> + <argument name="redirectTypeValue" type="string"/> + <argument name="description" type="string"/> + </arguments> + <click selector="{{AdminUrlRewriteEditSection.store}}" stepKey="clickOnStore"/> + <click selector="{{AdminUrlRewriteEditSection.storeValue('storeValue')}}" stepKey="clickOnStoreValue"/> + <fillField selector="{{AdminUrlRewriteEditSection.requestPath}}" userInput="{{requestPath}}" stepKey="fillRequestPath"/> + <fillField selector="{{AdminUrlRewriteEditSection.targetPath}}" userInput="{{targetPath}}" stepKey="fillTargetPath"/> + <selectOption selector="{{AdminUrlRewriteEditSection.redirectType}}" userInput="{{redirectTypeValue}}" stepKey="selectRedirectTypeValue"/> + <fillField selector="{{AdminUrlRewriteEditSection.description}}" userInput="{{description}}" stepKey="fillDescription"/> + <click selector="{{AdminUrlRewriteEditSection.saveButton}}" stepKey="clickOnSaveButton"/> + <seeElement selector="{{AdminUrlRewriteIndexSection.successMessage}}" stepKey="seeSuccessSaveMessage"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminUrlRewriteGridActionGroup.xml b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminUrlRewriteGridActionGroup.xml index f053d18e79c3e..1a9248ef36789 100644 --- a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminUrlRewriteGridActionGroup.xml +++ b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminUrlRewriteGridActionGroup.xml @@ -25,7 +25,7 @@ <see selector="{{AdminUrlRewriteIndexSection.targetPathColumn('1')}}" userInput="{{targetPath}}" stepKey="seeTheTargetPath" /> <see selector="{{AdminUrlRewriteIndexSection.redirectTypeColumn('1')}}" userInput="{{redirectType}}" stepKey="seeTheRedirectTypeForOldUrl" /> </actionGroup> - <actionGroup name="AdminSearchProductBySku"> + <actionGroup name="AdminSearchUrlRewriteProductBySku"> <arguments> <argument name="productSku" type="string"/> </arguments> @@ -72,4 +72,26 @@ <waitForPageLoad stepKey="waitForPageToLoad3"/> <see selector="{{AdminUrlRewriteIndexSection.successMessage}}" userInput="You deleted the URL rewrite." stepKey="seeSuccessMessage"/> </actionGroup> -</actionGroups> \ No newline at end of file + <actionGroup name="AssertPageByUrlRewriteIsNotFound"> + <arguments> + <argument name="requestPath" type="string"/> + </arguments> + <amOnPage url="{{requestPath}}" stepKey="amOnPage"/> + <waitForPageLoad stepKey="waitForStorefrontPageLoad"/> + <see userInput="Whoops, our bad..." stepKey="seeWhoops"/> + </actionGroup> + <actionGroup name="AdminSearchAndSelectUrlRewriteInGrid"> + <arguments> + <argument name="requestPath" type="string"/> + </arguments> + <amOnPage url="{{AdminUrlRewriteIndexPage.url}}" stepKey="openUrlRewriteEditPage"/> + <waitForPageLoad stepKey="waitForUrlRewriteEditPageToLoad"/> + <click selector="{{AdminUrlRewriteIndexSection.resetButton}}" stepKey="clickOnResetButton"/> + <waitForPageLoad stepKey="waitForPageToLoad"/> + <fillField selector="{{AdminUrlRewriteIndexSection.requestPathFilter}}" userInput="{{requestPath}}" stepKey="fillRedirectPathFilter"/> + <click selector="{{AdminUrlRewriteIndexSection.searchButton}}" stepKey="clickOnSearchButton"/> + <waitForPageLoad stepKey="waitForPageToLoad1"/> + <click selector="{{AdminUrlRewriteIndexSection.editButton('1')}}" stepKey="clickOnEditButton"/> + <waitForPageLoad stepKey="waitForEditPageToLoad"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Data/UrlRewriteData.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Data/UrlRewriteData.xml new file mode 100644 index 0000000000000..77cf80ca95ac5 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Data/UrlRewriteData.xml @@ -0,0 +1,46 @@ +<?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="defaultUrlRewrite" type="urlRewrite"> + <data key="request_path" unique="prefix">test-test-test.html</data> + <data key="target_path">http://www.example.com/</data> + <data key="redirect_type">302</data> + <data key="redirect_type_label">Temporary (302)</data> + <data key="store_id">1</data> + <data key="store">Default Store View</data> + <data key="description">End To End Test</data> + </entity> + <entity name="updateUrlRewrite" type="urlRewrite"> + <data key="request_path" unique="prefix">test-aspx-test.aspx</data> + <data key="target_path">http://www.example.com/</data> + <data key="redirect_type">302</data> + <data key="redirect_type_label">Temporary (302)</data> + <data key="store_id">1</data> + <data key="store">Default Store View</data> + </entity> + <entity name="customPermanentUrlRewrite" type="urlRewrite"> + <data key="request_path" unique="prefix">wishlist</data> + <data key="target_path">https://marketplace.magento.com/</data> + <data key="redirect_type">301</data> + <data key="redirect_type_label">Permanent (301)</data> + <data key="store_id">1</data> + <data key="store">Default Store View</data> + <data key="description">test_description_relative path</data> + </entity> + <entity name="customTemporaryUrlRewrite" type="urlRewrite"> + <data key="request_path" unique="prefix">wishlist</data> + <data key="target_path">https://marketplace.magento.com/</data> + <data key="redirect_type">302</data> + <data key="redirect_type_label">Temporary (302)</data> + <data key="store_id">1</data> + <data key="store">Default Store View</data> + <data key="description">test_description_relative path</data> + </entity> +</entities> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/MetaData/url_rewrite-meta.xml b/app/code/Magento/UrlRewrite/Test/Mftf/MetaData/url_rewrite-meta.xml new file mode 100644 index 0000000000000..0738b17d6e0f0 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/MetaData/url_rewrite-meta.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateUrlRewrite" dataType="urlRewrite" type="create" auth="adminFormKey" url="/admin/url_rewrite/save/" method="POST" successRegex="/messages-message-success/"> + <field key="store_id">integer</field> + <field key="redirect_type">integer</field> + <field key="request_path">string</field> + <field key="target_path">string</field> + <field key="description">string</field> + </operation> +</operations> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Metadata/url_rewrite-meta.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Metadata/url_rewrite-meta.xml new file mode 100644 index 0000000000000..0738b17d6e0f0 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Metadata/url_rewrite-meta.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateUrlRewrite" dataType="urlRewrite" type="create" auth="adminFormKey" url="/admin/url_rewrite/save/" method="POST" successRegex="/messages-message-success/"> + <field key="store_id">integer</field> + <field key="redirect_type">integer</field> + <field key="request_path">string</field> + <field key="target_path">string</field> + <field key="description">string</field> + </operation> +</operations> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml index 90ab19c2ed76a..7b789845fe249 100644 --- a/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteIndexSection.xml @@ -21,5 +21,6 @@ <element name="emptyRecords" type="text" selector="//td[@class='empty-text']"/> <element name="successMessage" type="text" selector="#messages"/> <element name="editButton" type="text" selector="//tr[@data-role='row'][{{rowNumber}}]/td/a[contains(.,'Edit')]" parameterized="true"/> + <element name="storeView" type="text" selector="//tr[@data-role='row'][{{var1}}]/td[@data-column='store_id']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteProductSection.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteProductSection.xml new file mode 100644 index 0000000000000..3650ec56d1391 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Section/AdminUrlRewriteProductSection.xml @@ -0,0 +1,18 @@ +<?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="AdminUrlRewriteProductSection"> + <element name="skuFilter" type="input" selector="//input[@name='sku']"/> + <element name="resetFilter" type="button" selector="//button[@data-action='grid-filter-reset']" timeout="30"/> + <element name="searchFilter" type="button" selector="//button[@data-action='grid-filter-apply']" timeout="30"/> + <element name="productRow" type="text" selector="//tbody/tr/td[contains(@class,'col-sku')]"/> + <element name="skipCategoryButton" type="button" selector="//button[@class='action-default scalable save']" timeout="30"/> + </section> +</sections> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminAutoUpdateURLRewriteWhenCategoryIsDeletedTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminAutoUpdateURLRewriteWhenCategoryIsDeletedTest.xml new file mode 100644 index 0000000000000..52d313b21f3e1 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminAutoUpdateURLRewriteWhenCategoryIsDeletedTest.xml @@ -0,0 +1,73 @@ +<?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="AdminAutoUpdateURLRewriteWhenCategoryIsDeletedTest"> + <annotations> + <stories value="Create Product UrlRewrite"/> + <title value="Create product URL rewrite, autoupdate if subcategory deleted"/> + <description value="Login as admin,verify UrlRewrite auto update when subcategory is deleted "/> + <testCaseId value="MC-5342"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Filter and Select the created Product --> + <actionGroup ref="AdminSearchUrlRewriteProductBySku" stepKey="searchProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + + <!-- Update the Store, RequestPath, RedirectType and Description --> + <actionGroup ref="AdminAddUrlRewriteForProduct" stepKey="addUrlRewriteForProduct"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{_defaultProduct.urlKey}}.html"/> + <argument name="redirectTypeValue" value="Temporary (302)"/> + <argument name="description" value="End To End Test"/> + </actionGroup> + + <!-- Delete Category --> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!--Filter Product in product page and get the Product ID --> + <actionGroup ref="filterAndSelectProduct" stepKey="filterProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="productId" regex="#\/([0-9]*)?\/$#"/> + + <!-- Assert Redirect path, Target Path and Redirect type in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath"> + <argument name="redirectPath" value="$$createSimpleProduct.name$$.html" /> + <argument name="redirectType" value="No" /> + <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + </actionGroup> + + <!-- Assert Redirect path, Target Path and Redirect type in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath1"> + <argument name="redirectPath" value="{{_defaultProduct.urlKey}}.html" /> + <argument name="redirectType" value="Temporary (302)"/> + <argument name="targetPath" value="$$createSimpleProduct.name$$.html"/> + </actionGroup> + + <!--Assert Category Url Redirect is not present --> + <actionGroup ref="AdminSearchDeletedUrlRewrite" stepKey="searchDeletedCategory"> + <argument name="requestPath" value="$$createCategory.name$$.html"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCheckUrlRewritesInCatalogCategoriesAfterChangingUrlKeyForStoreViewAndMovingCategoryTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCheckUrlRewritesInCatalogCategoriesAfterChangingUrlKeyForStoreViewAndMovingCategoryTest.xml new file mode 100644 index 0000000000000..ee3682c8ad4d7 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCheckUrlRewritesInCatalogCategoriesAfterChangingUrlKeyForStoreViewAndMovingCategoryTest.xml @@ -0,0 +1,81 @@ +<?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="AdminCheckUrlRewritesInCatalogCategoriesAfterChangingUrlKeyForStoreViewAndMovingCategoryTest"> + <annotations> + <features value="Url Rewrite"/> + <stories value="Update url rewrites"/> + <title value="Check url rewrites in catalog categories after changing url key"/> + <description value="Check url rewrites in catalog categories after changing url key for store view and moving category"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-5352"/> + <group value="url_rewrite"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <!-- Create two sub-categories in default category with simple products --> + <createData entity="_defaultCategory" stepKey="createFirstCategory"/> + <createData entity="_defaultProduct" stepKey="createFirstSimpleProduct"> + <requiredEntity createDataKey="createFirstCategory"/> + </createData> + <createData entity="_defaultCategory" stepKey="createSecondCategory"/> + <createData entity="_defaultProduct" stepKey="createSecondSimpleProduct"> + <requiredEntity createDataKey="createSecondCategory"/> + </createData> + + <!-- Log in to backend --> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!--Create additional Store View in Main Website Store --> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createStoreView"/> + </before> + <after> + <deleteData createDataKey="createFirstCategory" stepKey="deleteFirstCategory"/> + <deleteData createDataKey="createSecondCategory" stepKey="deleteSecondCategory"/> + <deleteData createDataKey="createFirstSimpleProduct" stepKey="deleteFirstSimpleProduct"/> + <deleteData createDataKey="createSecondSimpleProduct" stepKey="deleteSecondSimpleProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- On the categories editing page change store view to created additional view --> + <actionGroup ref="switchCategoryStoreView" stepKey="switchStoreView"> + <argument name="Store" value="customStore.name"/> + <argument name="CatName" value="$$createFirstCategory.name$$"/> + </actionGroup> + + <!-- Change url key for category for first category; save --> + <actionGroup ref="ChangeSeoUrlKeyForSubCategory" stepKey="changeUrlKey"> + <argument name="value" value="{{SimpleRootSubCategory.url_key}}"/> + </actionGroup> + + <!-- Change store view to "All store views" for first category --> + <actionGroup ref="switchCategoryToAllStoreView" stepKey="switchToAllStoreViewProduct"> + <argument name="CatName" value="$$createFirstCategory.name$$"/> + </actionGroup> + + <!-- Move first category inside second category --> + <actionGroup ref="MoveCategoryActionGroup" stepKey="moveFirstCategoryToSecondCategory"> + <argument name="childCategory" value="$$createFirstCategory.name$$"/> + <argument name="parentCategory" value="$$createSecondCategory.name$$"/> + </actionGroup> + + <!-- Switch default store view on store view created below for first category --> + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="amOnStorefrontPage"/> + <waitForPageLoad stepKey="waitForStorefrontPageLoad"/> + <actionGroup ref="StorefrontSwitchStoreViewActionGroup" stepKey="storefrontSwitchStoreView"> + <argument name="storeView" value="customStore"/> + </actionGroup> + + <!-- Assert category url with custom store view --> + <amOnPage url="{{StorefrontHomePage.url}}$$createSecondCategory.name$$/{{SimpleRootSubCategory.url_key}}.html" stepKey="amOnCategoryPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + <dontSee userInput="$$createSecondSimpleProduct.name$$" selector="{{StorefrontCategoryMainSection.productsList}}" stepKey="dontSeeProductInCategory"/> + <see selector="{{StorefrontCategoryMainSection.emptyProductMessage}}" userInput="We can't find products matching the selection." stepKey="seeEmptyProductMessage"/> + </test> +</tests> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductURLRewriteAndAddNoRedirectTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductURLRewriteAndAddNoRedirectTest.xml new file mode 100644 index 0000000000000..f8d297c92a176 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductURLRewriteAndAddNoRedirectTest.xml @@ -0,0 +1,62 @@ +<?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="AdminCreateProductUrLRewriteAndAddNoRedirectTest"> + <annotations> + <stories value="Create Product UrlRewrite"/> + <title value="Create product URL rewrite, with no redirect"/> + <description value="Login as admin, create product UrlRewrite and add No redirect "/> + <testCaseId value="MC-5339"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <createData entity="defaultSimpleProduct" stepKey="createSimpleProduct"/> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Filter and Select the created Product --> + <actionGroup ref="AdminSearchUrlRewriteProductBySku" stepKey="searchProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + + <!-- Update the Store, RequestPath, RedirectType and Description --> + <actionGroup ref="AdminAddUrlRewriteForProduct" stepKey="addUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{_defaultProduct.urlKey}}.html"/> + <argument name="redirectTypeValue" value="No"/> + <argument name="description" value="End To End Test"/> + </actionGroup> + + <!--Filter Product in product page and get the Product ID --> + <actionGroup ref="filterAndSelectProduct" stepKey="filterProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="productId" regex="#\/([0-9]*)?\/$#"/> + + <!--Assert Product Redirect --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath"> + <argument name="redirectPath" value="{{_defaultProduct.urlKey}}.html" /> + <argument name="redirectType" value="No" /> + <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + </actionGroup> + + <!-- Assert Redirect path, Target Path and Redirect type in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath1"> + <argument name="redirectPath" value="$$createSimpleProduct.name$$.html" /> + <argument name="redirectType" value="No" /> + <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductURLRewriteWithCategoryAndAddTemporaryRedirectTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductURLRewriteWithCategoryAndAddTemporaryRedirectTest.xml new file mode 100644 index 0000000000000..ae18ab33ba6ce --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductURLRewriteWithCategoryAndAddTemporaryRedirectTest.xml @@ -0,0 +1,79 @@ +<?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="AdminCreateProductURLRewriteWithCategoryAndAddTemporaryRedirectTest"> + <annotations> + <stories value="Create Product UrlRewrite"/> + <title value="Create product URL rewrite, add temporary redirect for product"/> + <description value="Login as admin, create product with category and UrlRewrite and add temporary redirect "/> + <testCaseId value="MC-5338"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Filter and Select the created Product --> + <actionGroup ref="AdminSearchUrlRewriteProductBySku" stepKey="searchProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + + <!-- Update the Store, RequestPath, RedirectType and Description --> + <actionGroup ref="AdminAddUrlRewriteForProduct" stepKey="addUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{FirstLevelSubCat.name_lwr}}/{{_defaultProduct.urlKey}}.html"/> + <argument name="redirectTypeValue" value="Temporary (302)"/> + <argument name="description" value="End To End Test"/> + </actionGroup> + + <!--Assert Product Redirect --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath"> + <argument name="redirectPath" value="{{FirstLevelSubCat.name_lwr}}/{{_defaultProduct.urlKey}}.html" /> + <argument name="redirectType" value="Temporary (302)" /> + <argument name="targetPath" value="$$createSimpleProduct.name$$.html"/> + </actionGroup> + + <!--Filter Product in product page and get the Product ID --> + <actionGroup ref="filterAndSelectProduct" stepKey="filterProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="productId" regex="#\/([0-9]*)?\/$#"/> + + <!-- Assert Redirect path, Target Path and Redirect type in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath1"> + <argument name="redirectPath" value="$$createSimpleProduct.name$$.html" /> + <argument name="redirectType" value="No" /> + <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + </actionGroup> + + <!-- Open Category Page and Get Category ID --> + <actionGroup ref="OpenCategoryFromCategoryTree" stepKey="getCategoryId"> + <argument name="category" value="$$createCategory.name$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="categoryId" regex="#\/([0-9]*)?\/$#"/> + + <!-- Assert Redirect path, Target Path and Redirect type in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath2"> + <argument name="redirectPath" value="$$createCategory.name$$.html" /> + <argument name="redirectType" value="No" /> + <argument name="targetPath" value="catalog/category/view/id/{$categoryId}"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductUrLRewriteAndAddPermanentRedirectTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductUrLRewriteAndAddPermanentRedirectTest.xml new file mode 100644 index 0000000000000..66c586d4fe891 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductUrLRewriteAndAddPermanentRedirectTest.xml @@ -0,0 +1,62 @@ +<?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="AdminCreateProductUrLRewriteAndAddPermanentRedirectTest"> + <annotations> + <stories value="Create Product UrlRewrite"/> + <title value="Create product URL rewrite, with permanent redirect"/> + <description value="Login as admin, create product UrlRewrite and add Permanent redirect"/> + <testCaseId value="MC-5341"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <createData entity="defaultSimpleProduct" stepKey="createSimpleProduct"/> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Filter and Select the created Product --> + <actionGroup ref="AdminSearchUrlRewriteProductBySku" stepKey="searchProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + + <!-- Update the Store, RequestPath, RedirectType and Description --> + <actionGroup ref="AdminAddUrlRewriteForProduct" stepKey="addUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{_defaultProduct.urlKey}}.html"/> + <argument name="redirectTypeValue" value="Permanent (301)"/> + <argument name="description" value="End To End Test"/> + </actionGroup> + + <!--Filter Product in product page and get the Product ID --> + <actionGroup ref="filterAndSelectProduct" stepKey="filterProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="productId" regex="#\/([0-9]*)?\/$#"/> + + + <!--Assert Product Redirect --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath"> + <argument name="redirectPath" value="{{_defaultProduct.urlKey}}.html" /> + <argument name="redirectType" value="Permanent (301)" /> + <argument name="targetPath" value="$$createSimpleProduct.name$$.html"/> + </actionGroup> + + <!-- Assert Redirect Path, Target Path and Redirect type in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath1"> + <argument name="redirectPath" value="$$createSimpleProduct.name$$.html" /> + <argument name="redirectType" value="No" /> + <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductUrLRewriteAndAddTemporaryRedirectTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductUrLRewriteAndAddTemporaryRedirectTest.xml new file mode 100644 index 0000000000000..2d797a12bedf5 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductUrLRewriteAndAddTemporaryRedirectTest.xml @@ -0,0 +1,62 @@ +<?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="AdminCreateProductUrLRewriteAndAddTemporaryRedirectTest"> + <annotations> + <stories value="Create Product UrlRewrite"/> + <title value="Create product URL rewrite, with temporary redirect"/> + <description value="Login as admin, create product UrlRewrite and add Temporary redirect"/> + <testCaseId value="MC-5340"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <createData entity="defaultSimpleProduct" stepKey="createSimpleProduct"/> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Filter and Select the created Product --> + <actionGroup ref="AdminSearchUrlRewriteProductBySku" stepKey="searchProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + + <!-- Update the Store, RequestPath, RedirectType and Description --> + <actionGroup ref="AdminAddUrlRewriteForProduct" stepKey="addUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{_defaultProduct.urlKey}}.html"/> + <argument name="redirectTypeValue" value="Temporary (302)"/> + <argument name="description" value="End To End Test"/> + </actionGroup> + + <!--Filter Product in product page and get the Product ID --> + <actionGroup ref="filterAndSelectProduct" stepKey="filterProduct"> + <argument name="productSku" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="productId" regex="#\/([0-9]*)?\/$#"/> + + <!--Assert Product Redirect --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath"> + <argument name="redirectPath" value="{{_defaultProduct.urlKey}}.html" /> + <argument name="redirectType" value="Temporary (302)" /> + <argument name="targetPath" value="$$createSimpleProduct.name$$.html"/> + </actionGroup> + + <!-- Assert Redirect Path, Target Path and Redirect type in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByRequestPath1"> + <argument name="redirectPath" value="$$createSimpleProduct.name$$.html" /> + <argument name="redirectType" value="No" /> + <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml new file mode 100644 index 0000000000000..83c1e5c0a5e0a --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml @@ -0,0 +1,113 @@ +<?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="AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest"> + <annotations> + <stories value="Create product with several websites"/> + <title value="Create product with several websites and check URL Rewrites"/> + <description value="Test log in to Create product and Create product with several websites and check URL Rewrites"/> + <testCaseId value="MC-5359"/> + <severity value="CRITICAL"/> + <group value="urlRewrite"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="NewRootCategory" stepKey="rootCategory"/> + <createData entity="SimpleRootSubCategory" stepKey="category"> + <requiredEntity createDataKey="rootCategory"/> + </createData> + <createData entity="defaultSimpleProduct" stepKey="createProduct"/> + <actionGroup ref = "LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <actionGroup ref="DeleteCustomStoreActionGroup" stepKey="deleteStore1"> + <argument name="storeGroupName" value="customStore.name"/> + </actionGroup> + <actionGroup ref="DeleteCustomStoreActionGroup" stepKey="deleteStore2"> + <argument name="storeGroupName" value="customStoreGroup.name"/> + </actionGroup> + <deleteData stepKey="deleteRootCategory" createDataKey="rootCategory"/> + <deleteData stepKey="deleteProduct" createDataKey="createProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create first store --> + <actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createNewStore"> + <argument name="website" value="{{_defaultWebsite.name}}"/> + <argument name="storeGroupName" value="{{customStore.name}}"/> + <argument name="storeGroupCode" value="{{customStore.code}}"/> + </actionGroup> + <!-- Create first store view --> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createNewStoreView"> + <argument name="StoreGroup" value="customStore"/> + <argument name="customStore" value="storeViewData"/> + </actionGroup> + + <!-- Create second store --> + <actionGroup ref="CreateCustomStore" stepKey="createCustomStore"> + <argument name="website" value="{{_defaultWebsite.name}}"/> + <argument name="store" value="{{customStoreGroup.name}}"/> + <argument name="rootCategory" value="$$rootCategory.name$$"/> + </actionGroup> + <!-- Create second store view --> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createCustomStoreView"> + <argument name="StoreGroup" value="customStoreGroup"/> + <argument name="customStore" value="customStoreEN"/> + </actionGroup> + + <!-- Create simple product with categories created in create data --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="openProductCatalogPage"/> + <waitForPageLoad stepKey="waitForProductCatalogPage"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProduct"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowOfCreatedSimpleProduct"/> + <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDown"/> + <fillField selector="{{AdminProductFormSection.searchCategory}}" userInput="$$rootCategory.name$$" stepKey="fillSearchForInitialCategory"/> + <click selector="{{AdminProductFormSection.selectCategory($$rootCategory.name$$)}}" stepKey="unselectInitialCategory"/> + <fillField selector="{{AdminProductFormSection.searchCategory}}" userInput="$$category.name$$" stepKey="fillSearchCategory"/> + <click selector="{{AdminProductFormSection.selectCategory($$category.name$$)}}" stepKey="clickOnCategory"/> + <click selector="{{AdminProductFormSection.done}}" stepKey="clickOnDoneAdvancedCategorySelect"/> + <scrollToTopOfPage stepKey="scrollToTopOfAdminProductFormSection"/> + <click selector="{{AdminProductFormSection.save}}" stepKey="clickSaveButton"/> + <waitForPageLoad stepKey="waitForSimpleProductSaved"/> + <!-- Verify customer see success message --> + <see selector="{{AdminProductFormSection.successMessage}}" userInput="You saved the product." stepKey="seeAssertSimpleProductSaveSuccessMessage"/> + + <!-- Grab category Id --> + <actionGroup ref="OpenCategoryFromCategoryTree" stepKey="grabCategoryId"> + <argument name="category" value="$$category.name$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="categoryId" regex="#\/([0-9]*)?\/$#"/> + <!-- Open Url Rewrite page and verify new Redirect Path, RedirectType and Target Path for the grabbed category Id --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchPath"> + <argument name="redirectPath" value="$$category.name$$.html"/> + <argument name="redirectType" value="No"/> + <argument name="targetPath" value="catalog/category/view/id/{$categoryId}"/> + </actionGroup> + <see selector="{{AdminUrlRewriteIndexSection.storeView('1')}}" userInput="{{customStoreGroup.name}}" stepKey="seeStoreValueForCategoryId"/> + <see selector="{{AdminUrlRewriteIndexSection.storeView('1')}}" userInput="{{customStoreEN.name}}" stepKey="seeStoreViewValueForCategoryId"/> + + <!-- Grab product Id --> + <actionGroup ref="filterAndSelectProduct" stepKey="grabProductId"> + <argument name="productSku" value="$$createProduct.sku$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="productId" regex="#\/([0-9]*)?\/$#"/> + <!-- Open Url Rewrite page and verify new Redirect Path, RedirectType and Target Path for the grabbed product Id --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchPath1"> + <argument name="redirectPath" value="$$createProduct.name$$.html"/> + <argument name="redirectType" value="No"/> + <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + </actionGroup> + <see selector="{{AdminUrlRewriteIndexSection.storeView('1')}}" userInput="{{customStore.name}}" stepKey="seeStoreValueForProductId"/> + <see selector="{{AdminUrlRewriteIndexSection.storeView('1')}}" userInput="{{storeViewData.name}}" stepKey="seeStoreViewValueForProductId"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminDeleteCustomUrlRewriteTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminDeleteCustomUrlRewriteTest.xml new file mode 100644 index 0000000000000..cf45931029778 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminDeleteCustomUrlRewriteTest.xml @@ -0,0 +1,44 @@ +<?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="AdminDeleteCustomUrlRewriteTest"> + <annotations> + <stories value="Delete custom URL rewrite"/> + <title value="Delete custom URL rewrite"/> + <description value="Test log in to URL rewrite and Delete custom URL rewrite"/> + <testCaseId value="MC-5350"/> + <severity value="CRITICAL"/> + <group value="urlRewrite"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="defaultUrlRewrite" stepKey="urlRewrite" /> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Delete created custom url rewrite and verify AssertUrlRewriteDeletedMessage--> + <actionGroup ref="AdminDeleteUrlRewrite" stepKey="deleteUrlRewrite"> + <argument name="requestPath" value="$$urlRewrite.request_path$$"/> + </actionGroup> + + <!--Search and verify AssertUrlRewriteNotInGrid--> + <actionGroup ref="AdminSearchDeletedUrlRewrite" stepKey="searchDeletedUrlRewriteInGrid"> + <argument name="requestPath" value="$$urlRewrite.request_path$$"/> + </actionGroup> + + <!--Verify AssertPageByUrlRewriteIsNotFound--> + <actionGroup ref="AssertPageByUrlRewriteIsNotFound" stepKey="amOnPage"> + <argument name="requestPath" value="$$urlRewrite.request_path$$"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddAspxRequestPathTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddAspxRequestPathTest.xml new file mode 100644 index 0000000000000..072753505223d --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddAspxRequestPathTest.xml @@ -0,0 +1,61 @@ +<?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="AdminUpdateCategoryUrlRewriteAndAddAspxRequestPathTest"> + <annotations> + <stories value="Update URL rewrite"/> + <title value="Update Category URL Rewrites, aspx request path"/> + <description value="Login as Admin, update category UrlRewrite, add aspx request path and Temporary redirect type "/> + <testCaseId value="MC-5358"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="SimpleSubCategory" stepKey="category"/> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + </before> + <after> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Search and Select Edit option for created category in grid --> + <actionGroup ref="AdminSearchAndSelectUrlRewriteInGrid" stepKey="editUrlRewrite"> + <argument name="requestPath" value="$$category.custom_attributes[url_key]$$.html"/> + </actionGroup> + + <!-- Open UrlRewrite Edit page and update the fields --> + <actionGroup ref="AdminUpdateUrlRewrite" stepKey="updateCategoryUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{defaultUrlRewrite.request_path}}"/> + <argument name="redirectTypeValue" value="Temporary (302)"/> + <argument name="description" value="Update Category Url Rewrite"/> + </actionGroup> + + <!-- Open Category Page and Get Category ID --> + <actionGroup ref="OpenCategoryFromCategoryTree" stepKey="getCategoryId"> + <argument name="category" value="$$category.name$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="categoryId" regex="#\/([0-9]*)?\/$#"/> + + <!--Assert category Url Rewrite in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByNewRequestPath"> + <argument name="redirectPath" value="{{defaultUrlRewrite.request_path}}" /> + <argument name="redirectType" value="Temporary (302)" /> + <argument name="targetPath" value="catalog/category/view/id/{$categoryId}"/> + </actionGroup> + + <!-- Assert category redirect in Store Front --> + <actionGroup ref="AssertStorefrontUrlRewriteRedirect" stepKey="verifyCategoryInStoreFront"> + <argument name="category" value="$$category.name$$"/> + <argument name="newRequestPath" value="{{defaultUrlRewrite.request_path}}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddNoRedirectTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddNoRedirectTest.xml new file mode 100644 index 0000000000000..80b9dbe41bf59 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddNoRedirectTest.xml @@ -0,0 +1,61 @@ +<?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="AdminUpdateCategoryUrlRewriteAndAddNoRedirectTest"> + <annotations> + <stories value="Update URL rewrite"/> + <title value="Update Category URL Rewrites, no redirect type"/> + <description value="Login as Admin and update category Url Rewrite and add redirect type No"/> + <testCaseId value="MC-5355"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="SimpleSubCategory" stepKey="category"/> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + </before> + <after> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Search and Select Edit option for created category in grid --> + <actionGroup ref="AdminSearchAndSelectUrlRewriteInGrid" stepKey="editUrlRewrite"> + <argument name="requestPath" value="$$category.custom_attributes[url_key]$$.html"/> + </actionGroup> + + <!-- Open UrlRewrite Edit page and update the fields --> + <actionGroup ref="AdminUpdateUrlRewrite" stepKey="updateCategoryUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{defaultUrlRewrite.request_path}}"/> + <argument name="redirectTypeValue" value="No"/> + <argument name="description" value="Update Category Url Rewrite"/> + </actionGroup> + + <!-- Open Category Page and Get Category ID --> + <actionGroup ref="OpenCategoryFromCategoryTree" stepKey="getCategoryId"> + <argument name="category" value="$$category.name$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="categoryId" regex="#\/([0-9]*)?\/$#"/> + + <!-- Assert category Url Rewrite in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByNewRequestPath"> + <argument name="redirectPath" value="{{defaultUrlRewrite.request_path}}" /> + <argument name="redirectType" value="No" /> + <argument name="targetPath" value="catalog/category/view/id/{$categoryId}"/> + </actionGroup> + + <!-- Assert Category redirect in Store Front --> + <actionGroup ref="AssertStorefrontUrlRewriteRedirect" stepKey="verifyCategoryInStoreFront"> + <argument name="category" value="$$category.name$$"/> + <argument name="newRequestPath" value="{{defaultUrlRewrite.request_path}}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddPermanentRedirectTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddPermanentRedirectTest.xml new file mode 100644 index 0000000000000..be9fd1d83c8f1 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddPermanentRedirectTest.xml @@ -0,0 +1,61 @@ +<?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="AdminUpdateCategoryUrlRewriteAndAddPermanentRedirectTest"> + <annotations> + <stories value="Update URL rewrite"/> + <title value="Update Category URL Rewrites, permanent"/> + <description value="Login as Admin and update category UrlRewrite and add Permanent redirect type"/> + <testCaseId value="MC-5357"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="SimpleSubCategory" stepKey="category"/> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + </before> + <after> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Search and Select Edit option for created category in grid --> + <actionGroup ref="AdminSearchAndSelectUrlRewriteInGrid" stepKey="editUrlRewrite"> + <argument name="requestPath" value="$$category.custom_attributes[url_key]$$.html"/> + </actionGroup> + + <!-- Open UrlRewrite Edit page and update the fields --> + <actionGroup ref="AdminUpdateUrlRewrite" stepKey="updateCategoryUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{defaultUrlRewrite.request_path}}"/> + <argument name="redirectTypeValue" value="Permanent (301)"/> + <argument name="description" value="Update Category Url Rewrite"/> + </actionGroup> + + <!-- Open Category Page and Get Category ID --> + <actionGroup ref="OpenCategoryFromCategoryTree" stepKey="getCategoryId"> + <argument name="category" value="$$category.name$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="categoryId" regex="#\/([0-9]*)?\/$#"/> + + <!--Assert category Url Rewrite in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByNewRequestPath"> + <argument name="redirectPath" value="{{defaultUrlRewrite.request_path}}" /> + <argument name="redirectType" value="Permanent (301)" /> + <argument name="targetPath" value="catalog/category/view/id/{$categoryId}"/> + </actionGroup> + + <!-- Assert category redirect in Store Front --> + <actionGroup ref="AssertStorefrontUrlRewriteRedirect" stepKey="verifyCategoryInStoreFront"> + <argument name="category" value="$$category.name$$"/> + <argument name="newRequestPath" value="{{defaultUrlRewrite.request_path}}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddTemporaryRedirectTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddTemporaryRedirectTest.xml new file mode 100644 index 0000000000000..7453b7b5a43f3 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddTemporaryRedirectTest.xml @@ -0,0 +1,61 @@ +<?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="AdminUpdateCategoryUrlRewriteAndAddTemporaryRedirectTest"> + <annotations> + <stories value="Update URL rewrite"/> + <title value="Update Category URL Rewrites, no redirect type"/> + <description value="Login as Admin and update category UrlRewrite and add Temporary redirect type"/> + <testCaseId value="MC-5356"/> + <severity value="CRITICAL"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="SimpleSubCategory" stepKey="category"/> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + </before> + <after> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Search and Select Edit option for created category in grid --> + <actionGroup ref="AdminSearchAndSelectUrlRewriteInGrid" stepKey="editUrlRewrite"> + <argument name="requestPath" value="$$category.custom_attributes[url_key]$$.html"/> + </actionGroup> + + <!-- Open UrlRewrite Edit page and update the fields --> + <actionGroup ref="AdminUpdateUrlRewrite" stepKey="updateCategoryUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{updateUrlRewrite.request_path}}"/> + <argument name="redirectTypeValue" value="Temporary (302)"/> + <argument name="description" value="Update Category Url Rewrite"/> + </actionGroup> + + <!-- Open Category Page and Get Category ID --> + <actionGroup ref="OpenCategoryFromCategoryTree" stepKey="getCategoryId"> + <argument name="category" value="$$category.name$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="categoryId" regex="#\/([0-9]*)?\/$#"/> + + <!--Assert category Url Rewrite in grid --> + <actionGroup ref="AdminSearchByRequestPath" stepKey="searchByNewRequestPath"> + <argument name="redirectPath" value="{{updateUrlRewrite.request_path}}" /> + <argument name="redirectType" value="Temporary (302)" /> + <argument name="targetPath" value="catalog/category/view/id/{$categoryId}"/> + </actionGroup> + + <!-- Assert category redirect in Store Front --> + <actionGroup ref="AssertStorefrontUrlRewriteRedirect" stepKey="verifyCategoryInStoreFront"> + <argument name="category" value="$$category.name$$"/> + <argument name="newRequestPath" value="{{updateUrlRewrite.request_path}}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesPermanentTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesPermanentTest.xml new file mode 100644 index 0000000000000..8339eb63abef1 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesPermanentTest.xml @@ -0,0 +1,58 @@ +<?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="AdminUpdateCustomURLRewritesPermanentTest"> + <annotations> + <stories value="Update Custom URL Rewrites"/> + <title value="Update Custom URL Rewrites, permanent"/> + <description value="Test log in to URL Rewrites and Update Custom URL Rewrites, permanent"/> + <testCaseId value="MC-5353"/> + <severity value="CRITICAL"/> + <group value="urlRewrite"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="defaultUrlRewrite" stepKey="urlRewrite"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + </before> + <after> + <actionGroup ref="AdminDeleteUrlRewrite" stepKey="deleteCustomUrlRewrite"> + <argument name="requestPath" value="{{customPermanentUrlRewrite.request_path}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Search default custom url rewrite in grid--> + <actionGroup ref="AdminSearchAndSelectUrlRewriteInGrid" stepKey="searchUrlRewrite"> + <argument name="requestPath" value="$$urlRewrite.request_path$$"/> + </actionGroup> + + <!--Update default custom url rewrite as per requirement and verify AssertUrlRewriteSaveMessage--> + <actionGroup ref="AdminUpdateCustomUrlRewrite" stepKey="updateUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{customPermanentUrlRewrite.request_path}}"/> + <argument name="targetPath" value="{{customPermanentUrlRewrite.target_path}}"/> + <argument name="redirectTypeValue" value="{{customPermanentUrlRewrite.redirect_type_label}}"/> + <argument name="description" value="{{customPermanentUrlRewrite.description}}"/> + </actionGroup> + + <!--Search and verify updated AssertUrlRewriteInGrid--> + <actionGroup ref="AdminSearchByRequestPath" stepKey="verifyUpdatedUrlRewriteInGrid"> + <argument name="redirectPath" value="{{customPermanentUrlRewrite.request_path}}"/> + <argument name="redirectType" value="{{customPermanentUrlRewrite.redirect_type_label}}"/> + <argument name="targetPath" value="{{customPermanentUrlRewrite.target_path}}"/> + </actionGroup> + + <!--AssertUrlRewriteSuccessOutsideRedirect--> + <amOnPage url="{{StorefrontHomePage.url}}{{customPermanentUrlRewrite.request_path}}" stepKey="amOnStorefrontPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <seeInCurrentUrl url="{{customPermanentUrlRewrite.target_path}}" stepKey="seeAssertUrlRewrite"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesTemporaryTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesTemporaryTest.xml new file mode 100644 index 0000000000000..07d578cbbeca4 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCustomURLRewritesTemporaryTest.xml @@ -0,0 +1,68 @@ +<?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="AdminUpdateCustomURLRewritesTemporaryTest"> + <annotations> + <stories value="Update Custom URL Rewrites"/> + <title value="Update Custom URL Rewrites, temporary"/> + <description value="Test log in to URL Rewrites and Update Custom URL Rewrites, temporary"/> + <testCaseId value="MC-5354"/> + <severity value="CRITICAL"/> + <group value="urlRewrite"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <createData entity="defaultUrlRewrite" stepKey="urlRewrite"/> + <createData entity="defaultSimpleProduct" stepKey="createProduct"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminPanel"/> + </before> + <after> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <actionGroup ref="AdminDeleteUrlRewrite" stepKey="deleteCustomUrlRewrite"> + <argument name="requestPath" value="{{customTemporaryUrlRewrite.request_path}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Filter Product in product page and get the Product ID --> + <actionGroup ref="filterAndSelectProduct" stepKey="filterProduct"> + <argument name="productSku" value="$$createProduct.sku$$"/> + </actionGroup> + <grabFromCurrentUrl stepKey="productId" regex="#\/([0-9]*)?\/$#"/> + + <!--Search default custom url rewrite in grid--> + <actionGroup ref="AdminSearchAndSelectUrlRewriteInGrid" stepKey="searchUrlRewrite"> + <argument name="requestPath" value="$$urlRewrite.request_path$$"/> + </actionGroup> + + <!--Update default custom url rewrite as per requirement and verify AssertUrlRewriteSaveMessage--> + <actionGroup ref="AdminUpdateCustomUrlRewrite" stepKey="updateUrlRewrite"> + <argument name="storeValue" value="Default Store View"/> + <argument name="requestPath" value="{{customTemporaryUrlRewrite.request_path}}"/> + <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + <argument name="redirectTypeValue" value="{{customTemporaryUrlRewrite.redirect_type_label}}"/> + <argument name="description" value="{{customTemporaryUrlRewrite.description}}"/> + </actionGroup> + + <!--Search and verify AssertUrlRewriteInGrid--> + <actionGroup ref="AdminSearchByRequestPath" stepKey="verifyUpdatedUrlRewriteInGrid"> + <argument name="redirectPath" value="{{customTemporaryUrlRewrite.request_path}}"/> + <argument name="redirectType" value="{{customTemporaryUrlRewrite.redirect_type_label}}"/> + <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + </actionGroup> + + <!-- AssertUrlRewriteCustomSearchRedirect--> + <actionGroup ref="AssertStorefrontProductRedirect" stepKey="verifyProductInStoreFrontPage"> + <argument name="productName" value="$$createProduct.name$$"/> + <argument name="productSku" value="$$createProduct.sku$$"/> + <argument name="productRequestPath" value="$$createProduct.name$$.html"/> + </actionGroup> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php index 1c25ffd1e9ff7..c842d660a6176 100644 --- a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php +++ b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php @@ -76,6 +76,7 @@ public function resolve( $result = [ 'id' => $urlRewrite->getEntityId(), 'canonical_url' => $urlRewrite->getTargetPath(), + 'relative_url' => $urlRewrite->getTargetPath(), 'type' => $this->sanitizeType($urlRewrite->getEntityType()) ]; } diff --git a/app/code/Magento/UrlRewriteGraphQl/etc/schema.graphqls b/app/code/Magento/UrlRewriteGraphQl/etc/schema.graphqls index dae695c69a33c..5aea482a0fe02 100644 --- a/app/code/Magento/UrlRewriteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/UrlRewriteGraphQl/etc/schema.graphqls @@ -1,16 +1,17 @@ # Copyright © Magento, Inc. All rights reserved. # See COPYING.txt for license details. -type EntityUrl @doc(description: "EntityUrl is an output object containing the `id`, `canonical_url`, and `type` attributes") { - id: Int @doc(description: "The ID assigned to the object associated with the specified url. This could be a product ID, category ID, or page ID.") - canonical_url: String @doc(description: "The internal relative URL. If the specified url is a redirect, the query returns the redirected URL, not the original.") - type: UrlRewriteEntityTypeEnum @doc(description: "One of PRODUCT, CATEGORY, or CMS_PAGE.") -} - type Query { urlResolver(url: String!): EntityUrl @resolver(class: "Magento\\UrlRewriteGraphQl\\Model\\Resolver\\EntityUrl") @doc(description: "The urlResolver query returns the relative URL for a specified product, category or CMS page") } +type EntityUrl @doc(description: "EntityUrl is an output object containing the `id`, `relative_url`, and `type` attributes") { + id: Int @doc(description: "The ID assigned to the object associated with the specified url. This could be a product ID, category ID, or page ID.") + canonical_url: String @deprecated(reason: "The canonical_url field is deprecated, use relative_url instead.") + relative_url: String @doc(description: "The internal relative URL. If the specified url is a redirect, the query returns the redirected URL, not the original.") + type: UrlRewriteEntityTypeEnum @doc(description: "One of PRODUCT, CATEGORY, or CMS_PAGE.") +} + enum UrlRewriteEntityTypeEnum { } diff --git a/app/code/Magento/Wishlist/Block/AbstractBlock.php b/app/code/Magento/Wishlist/Block/AbstractBlock.php index bb8138fb87a3e..981a0da1d241f 100644 --- a/app/code/Magento/Wishlist/Block/AbstractBlock.php +++ b/app/code/Magento/Wishlist/Block/AbstractBlock.php @@ -228,7 +228,7 @@ public function hasDescription($item) } /** - * Retrieve formated Date + * Retrieve formatted Date * * @param string $date * @deprecated diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_store-scope.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_store-scope.less index c0c94eaaf3507..05e6350c88d8e 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_store-scope.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_store-scope.less @@ -38,7 +38,7 @@ .admin__legend { .admin__field-tooltip { margin-left: -@indent__base; - margin-top: -.2rem; + margin-top: .5rem; } } } diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new.html b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new.html index 8c4084fcaf496..e467aa843e2f4 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new.html @@ -51,7 +51,7 @@ <h1>{{trans "Your Shipment #%shipment_id for Order #%order_id" shipment_id=$ship </tr> </table> {{/depend}} - {{block class='Magento\\Framework\\View\\Element\\Template' area='frontend' template='Magento_Sales::email/shipment/track.phtml' shipment=$shipment order=$order}} + {{layout handle="sales_email_order_shipment_track" shipment=$shipment order=$order}} <table class="order-details"> <tr> <td class="address-details"> diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new_guest.html index 68f1886986c5b..385110f8f037e 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new_guest.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new_guest.html @@ -49,7 +49,7 @@ <h1>{{trans "Your Shipment #%shipment_id for Order #%order_id" shipment_id=$ship </tr> </table> {{/depend}} - {{block class='Magento\\Framework\\View\\Element\\Template' area='frontend' template='Magento_Sales::email/shipment/track.phtml' shipment=$shipment order=$order}} + {{layout handle="sales_email_order_shipment_track" shipment=$shipment order=$order}} <table class="order-details"> <tr> <td class="address-details"> diff --git a/composer.json b/composer.json index 9ef896c7e72cc..50b22238e0d01 100644 --- a/composer.json +++ b/composer.json @@ -181,6 +181,8 @@ "magento/module-media-storage": "*", "magento/module-message-queue": "*", "magento/module-msrp": "*", + "magento/module-msrp-configurable-product": "*", + "magento/module-msrp-grouped-product": "*", "magento/module-multishipping": "*", "magento/module-mysql-mq": "*", "magento/module-new-relic-reporting": "*", diff --git a/composer.lock b/composer.lock index 72d3e93a7b35e..a7131f4a16eec 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3cdccc93cc990b4212377b1d01a8c4ef", + "content-hash": "60007664938710edf52eadddd7551867", "packages": [ { "name": "braintree/braintree_php", @@ -7842,6 +7842,7 @@ "mock", "xunit" ], + "abandoned": true, "time": "2018-08-09T05:50:03+00:00" }, { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ChangeCustomerPasswordTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ChangeCustomerPasswordTest.php index f4e96e49a58e6..66b171740ccab 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ChangeCustomerPasswordTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/ChangeCustomerPasswordTest.php @@ -94,7 +94,7 @@ public function testChangeWeakPassword() /** * @magentoApiDataFixture Magento/Customer/_files/customer.php * @expectedException \Exception - * @expectedExceptionMessage The password doesn't match this account. Verify the password and try again. + * @expectedExceptionMessage Invalid login or password. */ public function testChangePasswordIfPasswordIsInvalid() { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php index c11c1385f7412..ee8fabc43c901 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php @@ -47,33 +47,58 @@ public function testUpdateCustomer() $currentEmail = 'customer@example.com'; $currentPassword = 'password'; + $newPrefix = 'Dr'; $newFirstname = 'Richard'; + $newMiddlename = 'Riley'; $newLastname = 'Rowe'; + $newSuffix = 'III'; + $newDob = '3/11/1972'; + $newTaxVat = 'GQL1234567'; + $newGender = 2; $newEmail = 'customer_updated@example.com'; $query = <<<QUERY mutation { updateCustomer( input: { + prefix: "{$newPrefix}" firstname: "{$newFirstname}" + middlename: "{$newMiddlename}" lastname: "{$newLastname}" + suffix: "{$newSuffix}" + dob: "{$newDob}" + taxvat: "{$newTaxVat}" email: "{$newEmail}" password: "{$currentPassword}" + gender: {$newGender} } ) { customer { + prefix firstname + middlename lastname + suffix + dob + taxvat email + gender } } } QUERY; $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword)); + $this->assertEquals($newPrefix, $response['updateCustomer']['customer']['prefix']); $this->assertEquals($newFirstname, $response['updateCustomer']['customer']['firstname']); + $this->assertEquals($newMiddlename, $response['updateCustomer']['customer']['middlename']); $this->assertEquals($newLastname, $response['updateCustomer']['customer']['lastname']); + $this->assertEquals($newSuffix, $response['updateCustomer']['customer']['suffix']); + $newDobDate = new \DateTime($newDob); + $this->assertEquals($newDobDate->format('Y-m-d'), $response['updateCustomer']['customer']['dob']); + $this->assertEquals($newTaxVat, $response['updateCustomer']['customer']['taxvat']); $this->assertEquals($newEmail, $response['updateCustomer']['customer']['email']); + $this->assertEquals($newGender, $response['updateCustomer']['customer']['gender']); } /** @@ -185,7 +210,7 @@ public function testUpdateEmailIfPasswordIsMissed() /** * @magentoApiDataFixture Magento/Customer/_files/customer.php * @expectedException \Exception - * @expectedExceptionMessage The password doesn't match this account. Verify the password and try again. + * @expectedExceptionMessage Invalid login or password. */ public function testUpdateEmailIfPasswordIsInvalid() { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveItemFromCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveItemFromCartTest.php index a351a2188a664..70ec646c10008 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveItemFromCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveItemFromCartTest.php @@ -81,14 +81,13 @@ public function testRemoveItemFromCart() public function testRemoveItemFromNonExistentCart() { $query = $this->prepareMutationQuery('non_existent_masked_id', 1); - $this->graphQlQuery($query, [], '', $this->getHeaderMap()); } /** * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php */ - public function testRemoveNotExistentItem() + public function testRemoveNonExistentItem() { $quote = $this->quoteFactory->create(); $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id'); @@ -183,6 +182,50 @@ public function testRemoveItemFromAnotherCustomerCart() $this->graphQlQuery($query, [], '', $this->getHeaderMap()); } + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @param string $input + * @param string $message + * @dataProvider dataProviderUpdateWithMissedRequiredParameters + */ + public function testUpdateWithMissedItemRequiredParameters(string $input, string $message) + { + $query = <<<QUERY +mutation { + removeItemFromCart( + input: { + {$input} + } + ) { + cart { + items { + qty + } + } + } +} +QUERY; + $this->expectExceptionMessage($message); + $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + } + + /** + * @return array + */ + public function dataProviderUpdateWithMissedRequiredParameters(): array + { + return [ + 'missed_cart_id' => [ + 'cart_item_id: 1', + 'Required parameter "cart_id" is missing.' + ], + 'missed_cart_item_id' => [ + 'cart_id: "test"', + 'Required parameter "cart_item_id" is missing.' + ], + ]; + } + /** * @param string $maskedQuoteId * @param int $itemId diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/UpdateCartItemsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/UpdateCartItemsTest.php new file mode 100644 index 0000000000000..632ee839834e0 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/UpdateCartItemsTest.php @@ -0,0 +1,334 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Quote\Customer; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Integration\Api\CustomerTokenServiceInterface; +use Magento\Quote\Model\QuoteFactory; +use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface; +use Magento\Quote\Model\ResourceModel\Quote as QuoteResource; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\GraphQlAbstract; + +/** + * Test for updating shopping cart items + */ +class UpdateCartItemsTest extends GraphQlAbstract +{ + /** + * @var CustomerTokenServiceInterface + */ + private $customerTokenService; + + /** + * @var QuoteResource + */ + private $quoteResource; + + /** + * @var QuoteFactory + */ + private $quoteFactory; + + /** + * @var QuoteIdToMaskedQuoteIdInterface + */ + private $quoteIdToMaskedId; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + protected function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->quoteResource = $objectManager->get(QuoteResource::class); + $this->quoteFactory = $objectManager->get(QuoteFactory::class); + $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class); + $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); + $this->productRepository = $objectManager->get(ProductRepositoryInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testUpdateCartItemQty() + { + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id'); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId()); + $itemId = (int)$quote->getItemByProduct($this->productRepository->get('simple'))->getId(); + $qty = 2; + + $query = $this->getQuery($maskedQuoteId, $itemId, $qty); + $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + + $this->assertArrayHasKey('updateCartItems', $response); + $this->assertArrayHasKey('cart', $response['updateCartItems']); + + $responseCart = $response['updateCartItems']['cart']; + $item = current($responseCart['items']); + + $this->assertEquals($itemId, $item['id']); + $this->assertEquals($qty, $item['qty']); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testRemoveCartItemIfQuantityIsZero() + { + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id'); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId()); + $itemId = (int)$quote->getItemByProduct($this->productRepository->get('simple'))->getId(); + $qty = 0; + + $query = $this->getQuery($maskedQuoteId, $itemId, $qty); + $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + + $this->assertArrayHasKey('updateCartItems', $response); + $this->assertArrayHasKey('cart', $response['updateCartItems']); + + $responseCart = $response['updateCartItems']['cart']; + $this->assertCount(0, $responseCart['items']); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @expectedException \Exception + * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id" + */ + public function testUpdateItemInNonExistentCart() + { + $query = $this->getQuery('non_existent_masked_id', 1, 2); + $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testUpdateNonExistentItem() + { + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id'); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId()); + $notExistentItemId = 999; + + $this->expectExceptionMessage("Could not find cart item with id: {$notExistentItemId}."); + + $query = $this->getQuery($maskedQuoteId, $notExistentItemId, 2); + $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php + */ + public function testUpdateItemIfItemIsNotBelongToCart() + { + $firstQuote = $this->quoteFactory->create(); + $this->quoteResource->load($firstQuote, 'test_order_1', 'reserved_order_id'); + $firstQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$firstQuote->getId()); + + $secondQuote = $this->quoteFactory->create(); + $this->quoteResource->load( + $secondQuote, + 'test_order_with_virtual_product_without_address', + 'reserved_order_id' + ); + $secondQuote->setCustomerId(1); + $this->quoteResource->save($secondQuote); + $secondQuoteItemId = (int)$secondQuote + ->getItemByProduct($this->productRepository->get('virtual-product')) + ->getId(); + + $this->expectExceptionMessage("Could not find cart item with id: {$secondQuoteItemId}."); + + $query = $this->getQuery($firstQuoteMaskedId, $secondQuoteItemId, 2); + $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php + */ + public function testUpdateItemInGuestCart() + { + $guestQuote = $this->quoteFactory->create(); + $this->quoteResource->load( + $guestQuote, + 'test_order_with_virtual_product_without_address', + 'reserved_order_id' + ); + $guestQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$guestQuote->getId()); + $guestQuoteItemId = (int)$guestQuote + ->getItemByProduct($this->productRepository->get('virtual-product')) + ->getId(); + + $this->expectExceptionMessage( + "The current user cannot perform operations on cart \"$guestQuoteMaskedId\"" + ); + + $query = $this->getQuery($guestQuoteMaskedId, $guestQuoteItemId, 2); + $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/three_customers.php + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php + */ + public function testUpdateItemInAnotherCustomerCart() + { + $anotherCustomerQuote = $this->quoteFactory->create(); + $this->quoteResource->load( + $anotherCustomerQuote, + 'test_order_with_virtual_product_without_address', + 'reserved_order_id' + ); + $anotherCustomerQuote->setCustomerId(2); + $this->quoteResource->save($anotherCustomerQuote); + + $anotherCustomerQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$anotherCustomerQuote->getId()); + $anotherCustomerQuoteItemId = (int)$anotherCustomerQuote + ->getItemByProduct($this->productRepository->get('virtual-product')) + ->getId(); + + $this->expectExceptionMessage( + "The current user cannot perform operations on cart \"$anotherCustomerQuoteMaskedId\"" + ); + + $query = $this->getQuery($anotherCustomerQuoteMaskedId, $anotherCustomerQuoteItemId, 2); + $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @expectedException \Exception + * @expectedExceptionMessage Required parameter "cart_id" is missing. + */ + public function testUpdateWithMissedCartItemId() + { + $query = <<<QUERY +mutation { + updateCartItems(input: { + cart_items: [ + { + cart_item_id: 1 + quantity: 2 + } + ] + }) { + cart { + items { + id + qty + } + } + } +} +QUERY; + $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + } + + /** + * @param string $input + * @param string $message + * @dataProvider dataProviderUpdateWithMissedRequiredParameters + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testUpdateWithMissedItemRequiredParameters(string $input, string $message) + { + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id'); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId()); + + $query = <<<QUERY +mutation { + updateCartItems(input: { + cart_id: "{$maskedQuoteId}" + {$input} + }) { + cart { + items { + id + qty + } + } + } +} +QUERY; + $this->expectExceptionMessage($message); + $this->graphQlQuery($query, [], '', $this->getHeaderMap()); + } + + /** + * @return array + */ + public function dataProviderUpdateWithMissedRequiredParameters(): array + { + return [ + 'missed_cart_items' => [ + '', + 'Required parameter "cart_items" is missing.' + ], + 'missed_cart_item_id' => [ + 'cart_items: [{ quantity: 2 }]', + 'Required parameter "cart_item_id" for "cart_items" is missing.' + ], + 'missed_cart_item_qty' => [ + 'cart_items: [{ cart_item_id: 1 }]', + 'Required parameter "quantity" for "cart_items" is missing.' + ], + ]; + } + + /** + * @param string $maskedQuoteId + * @param int $itemId + * @param float $qty + * @return string + */ + private function getQuery(string $maskedQuoteId, int $itemId, float $qty): string + { + return <<<QUERY +mutation { + updateCartItems(input: { + cart_id: "{$maskedQuoteId}" + cart_items:[ + { + cart_item_id: {$itemId} + quantity: {$qty} + } + ] + }) { + cart { + items { + id + qty + } + } + } +} +QUERY; + } + + /** + * @param string $username + * @param string $password + * @return array + */ + private function getHeaderMap(string $username = 'customer@example.com', string $password = 'password'): array + { + $customerToken = $this->customerTokenService->createCustomerAccessToken($username, $password); + $headerMap = ['Authorization' => 'Bearer ' . $customerToken]; + return $headerMap; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/RemoveItemFromCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/RemoveItemFromCartTest.php index a6b8f05fc0834..a306b29e51197 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/RemoveItemFromCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/RemoveItemFromCartTest.php @@ -73,14 +73,13 @@ public function testRemoveItemFromCart() public function testRemoveItemFromNonExistentCart() { $query = $this->prepareMutationQuery('non_existent_masked_id', 1); - $this->graphQlQuery($query); } /** * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php */ - public function testRemoveNotExistentItem() + public function testRemoveNonExistentItem() { $quote = $this->quoteFactory->create(); $this->quoteResource->load($quote, 'test_order_with_simple_product_without_address', 'reserved_order_id'); @@ -139,6 +138,49 @@ public function testRemoveItemFromCustomerCart() $this->graphQlQuery($query); } + /** + * @param string $input + * @param string $message + * @dataProvider dataProviderUpdateWithMissedRequiredParameters + */ + public function testUpdateWithMissedItemRequiredParameters(string $input, string $message) + { + $query = <<<QUERY +mutation { + removeItemFromCart( + input: { + {$input} + } + ) { + cart { + items { + qty + } + } + } +} +QUERY; + $this->expectExceptionMessage($message); + $this->graphQlQuery($query); + } + + /** + * @return array + */ + public function dataProviderUpdateWithMissedRequiredParameters(): array + { + return [ + 'missed_cart_id' => [ + 'cart_item_id: 1', + 'Required parameter "cart_id" is missing.' + ], + 'missed_cart_item_id' => [ + 'cart_id: "test"', + 'Required parameter "cart_item_id" is missing.' + ], + ]; + } + /** * @param string $maskedQuoteId * @param int $itemId diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/UpdateCartItemsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/UpdateCartItemsTest.php new file mode 100644 index 0000000000000..fca7a4287620b --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/UpdateCartItemsTest.php @@ -0,0 +1,273 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Quote\Guest; + +use Magento\Quote\Model\QuoteFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface; +use Magento\Quote\Model\ResourceModel\Quote as QuoteResource; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\GraphQlAbstract; + +/** + * Test for updating/removing shopping cart items + */ +class UpdateCartItemsTest extends GraphQlAbstract +{ + /** + * @var QuoteResource + */ + private $quoteResource; + + /** + * @var QuoteFactory + */ + private $quoteFactory; + + /** + * @var QuoteIdToMaskedQuoteIdInterface + */ + private $quoteIdToMaskedId; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + protected function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->quoteResource = $objectManager->get(QuoteResource::class); + $this->quoteFactory = $objectManager->get(QuoteFactory::class); + $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class); + $this->productRepository = $objectManager->get(ProductRepositoryInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + */ + public function testUpdateCartItemQty() + { + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, 'test_order_with_simple_product_without_address', 'reserved_order_id'); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId()); + $itemId = (int)$quote->getItemByProduct($this->productRepository->get('simple'))->getId(); + $qty = 2; + + $query = $this->getQuery($maskedQuoteId, $itemId, $qty); + $response = $this->graphQlQuery($query); + + $this->assertArrayHasKey('updateCartItems', $response); + $this->assertArrayHasKey('cart', $response['updateCartItems']); + + $responseCart = $response['updateCartItems']['cart']; + $item = current($responseCart['items']); + + $this->assertEquals($itemId, $item['id']); + $this->assertEquals($qty, $item['qty']); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + */ + public function testRemoveCartItemIfQuantityIsZero() + { + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, 'test_order_with_simple_product_without_address', 'reserved_order_id'); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId()); + $itemId = (int)$quote->getItemByProduct($this->productRepository->get('simple'))->getId(); + $qty = 0; + + $query = $this->getQuery($maskedQuoteId, $itemId, $qty); + $response = $this->graphQlQuery($query); + + $this->assertArrayHasKey('updateCartItems', $response); + $this->assertArrayHasKey('cart', $response['updateCartItems']); + + $responseCart = $response['updateCartItems']['cart']; + $this->assertCount(0, $responseCart['items']); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id" + */ + public function testUpdateItemInNonExistentCart() + { + $query = $this->getQuery('non_existent_masked_id', 1, 2); + $this->graphQlQuery($query); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + */ + public function testUpdateNonExistentItem() + { + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, 'test_order_with_simple_product_without_address', 'reserved_order_id'); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId()); + $notExistentItemId = 999; + + $this->expectExceptionMessage("Could not find cart item with id: {$notExistentItemId}."); + + $query = $this->getQuery($maskedQuoteId, $notExistentItemId, 2); + $this->graphQlQuery($query); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php + */ + public function testUpdateItemIfItemIsNotBelongToCart() + { + $firstQuote = $this->quoteFactory->create(); + $this->quoteResource->load($firstQuote, 'test_order_with_simple_product_without_address', 'reserved_order_id'); + $firstQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$firstQuote->getId()); + + $secondQuote = $this->quoteFactory->create(); + $this->quoteResource->load( + $secondQuote, + 'test_order_with_virtual_product_without_address', + 'reserved_order_id' + ); + $secondQuoteItemId = (int)$secondQuote + ->getItemByProduct($this->productRepository->get('virtual-product')) + ->getId(); + + $this->expectExceptionMessage("Could not find cart item with id: {$secondQuoteItemId}."); + + $query = $this->getQuery($firstQuoteMaskedId, $secondQuoteItemId, 2); + $this->graphQlQuery($query); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testUpdateItemFromCustomerCart() + { + $customerQuote = $this->quoteFactory->create(); + $this->quoteResource->load($customerQuote, 'test_order_1', 'reserved_order_id'); + $customerQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$customerQuote->getId()); + $customerQuoteItemId = (int)$customerQuote->getItemByProduct($this->productRepository->get('simple'))->getId(); + + $this->expectExceptionMessage("The current user cannot perform operations on cart \"$customerQuoteMaskedId\""); + + $query = $this->getQuery($customerQuoteMaskedId, $customerQuoteItemId, 2); + $this->graphQlQuery($query); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Required parameter "cart_id" is missing. + */ + public function testUpdateWithMissedCartItemId() + { + $query = <<<QUERY +mutation { + updateCartItems(input: { + cart_items: [ + { + cart_item_id: 1 + quantity: 2 + } + ] + }) { + cart { + items { + id + qty + } + } + } +} +QUERY; + $this->graphQlQuery($query); + } + + /** + * @param string $input + * @param string $message + * @dataProvider dataProviderUpdateWithMissedRequiredParameters + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + */ + public function testUpdateWithMissedItemRequiredParameters(string $input, string $message) + { + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, 'test_order_with_simple_product_without_address', 'reserved_order_id'); + $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId()); + + $query = <<<QUERY +mutation { + updateCartItems(input: { + cart_id: "{$maskedQuoteId}" + {$input} + }) { + cart { + items { + id + qty + } + } + } +} +QUERY; + $this->expectExceptionMessage($message); + $this->graphQlQuery($query); + } + + /** + * @return array + */ + public function dataProviderUpdateWithMissedRequiredParameters(): array + { + return [ + 'missed_cart_items' => [ + '', + 'Required parameter "cart_items" is missing.' + ], + 'missed_cart_item_id' => [ + 'cart_items: [{ quantity: 2 }]', + 'Required parameter "cart_item_id" for "cart_items" is missing.' + ], + 'missed_cart_item_qty' => [ + 'cart_items: [{ cart_item_id: 1 }]', + 'Required parameter "quantity" for "cart_items" is missing.' + ], + ]; + } + + /** + * @param string $maskedQuoteId + * @param int $itemId + * @param float $qty + * @return string + */ + private function getQuery(string $maskedQuoteId, int $itemId, float $qty): string + { + return <<<QUERY +mutation { + updateCartItems(input: { + cart_id: "{$maskedQuoteId}" + cart_items: [ + { + cart_item_id: {$itemId} + quantity: {$qty} + } + ] + }) { + cart { + items { + id + qty + } + } + } +} +QUERY; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php index c70b1631e85cd..370121a1dad78 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php @@ -31,7 +31,7 @@ protected function setUp() } /** - * Tests if target_path(canonical_url) is resolved for Product entity + * Tests if target_path(relative_url) is resolved for Product entity * * @magentoApiDataFixture Magento/CatalogUrlRewrite/_files/product_with_category.php */ @@ -60,7 +60,7 @@ public function testProductUrlResolver() urlResolver(url:"{$urlPath}") { id - canonical_url + relative_url type } } @@ -68,12 +68,12 @@ public function testProductUrlResolver() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['canonical_url']); + $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } /** - * Tests the use case where canonical_url is provided as resolver input in the Query + * Tests the use case where relative_url is provided as resolver input in the Query * * @magentoApiDataFixture Magento/CatalogUrlRewrite/_files/product_with_category.php */ @@ -104,7 +104,7 @@ public function testProductUrlWithCanonicalUrlInput() urlResolver(url:"{$canonicalPath}") { id - canonical_url + relative_url type } } @@ -112,7 +112,7 @@ public function testProductUrlWithCanonicalUrlInput() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['canonical_url']); + $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } @@ -147,7 +147,7 @@ public function testCategoryUrlResolver() urlResolver(url:"{$urlPath2}") { id - canonical_url + relative_url type } } @@ -155,7 +155,7 @@ public function testCategoryUrlResolver() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($categoryId, $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['canonical_url']); + $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } @@ -183,14 +183,14 @@ public function testCMSPageUrlResolver() urlResolver(url:"{$requestPath}") { id - canonical_url + relative_url type } } QUERY; $response = $this->graphQlQuery($query); $this->assertEquals($cmsPageId, $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['canonical_url']); + $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper(str_replace('-', '_', $expectedEntityType)), $response['urlResolver']['type']); } @@ -226,7 +226,7 @@ public function testProductUrlRewriteResolver() urlResolver(url:"{$urlPath}") { id - canonical_url + relative_url type } } @@ -234,7 +234,7 @@ public function testProductUrlRewriteResolver() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['canonical_url']); + $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } @@ -266,7 +266,7 @@ public function testInvalidUrlResolverInput() urlResolver(url:"{$urlPath}") { id - canonical_url + relative_url type } } @@ -307,7 +307,7 @@ public function testCategoryUrlWithLeadingSlash() urlResolver(url:"/{$urlPath}") { id - canonical_url + relative_url type } } @@ -315,7 +315,7 @@ public function testCategoryUrlWithLeadingSlash() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($categoryId, $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['canonical_url']); + $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } @@ -344,7 +344,7 @@ public function testResolveSlash() urlResolver(url:"/") { id - canonical_url + relative_url type } } @@ -352,7 +352,7 @@ public function testResolveSlash() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($homePageId, $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['canonical_url']); + $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); $this->assertEquals('CMS_PAGE', $response['urlResolver']['type']); } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml index a975d19ef8879..89c9d9168921f 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Analytics\Test\TestCase\AdvancedReportingButtonTest" summary="Navigate through Advanced Reporting button on dashboard to Sign Up page" ticketId="MAGETWO-63715"> <variation name="AdvancedReportingButtonTest"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="advancedReportingLink" xsi:type="string">https://advancedreporting.rjmetrics.com/report</data> <constraint name="Magento\Analytics\Test\Constraint\AssertAdvancedReportingPage" /> </variation> diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/ValidateOrderOfProductTypeTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/ValidateOrderOfProductTypeTest.xml index 7077f367795ed..cb32742a0ce6b 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/ValidateOrderOfProductTypeTest.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/ValidateOrderOfProductTypeTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Catalog\Test\TestCase\Product\ValidateOrderOfProductTypeTest"> <variation name="ValidateOrderOfProductTypeTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="menu/4" xsi:type="string">Bundle Product</data> </variation> </testCase> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ValidateOrderOfProductTypeTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ValidateOrderOfProductTypeTest.xml index 0d1a34ab52f97..ec776128fdfe3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ValidateOrderOfProductTypeTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ValidateOrderOfProductTypeTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Catalog\Test\TestCase\Product\ValidateOrderOfProductTypeTest" summary="Validate product types order on product grid page" ticketId="MAGETWO-37146"> <variation name="ValidateOrderOfProductTypeTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="menu/0" xsi:type="string">Simple Product</data> <data name="menu/3" xsi:type="string">Virtual Product</data> <constraint name="Magento\Catalog\Test\Constraint\AssertProductTypeOrderOnCreate" /> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteUsedInConfigurableProductAttributeTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteUsedInConfigurableProductAttributeTest.xml index df396c22312b1..e46174de8818f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteUsedInConfigurableProductAttributeTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteUsedInConfigurableProductAttributeTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Catalog\Test\TestCase\ProductAttribute\DeleteUsedInConfigurableProductAttributeTest" summary="Delete Used in Configurable Product Attribute" ticketId="MAGETWO-26652"> <variation name="DeleteUsedInConfigurableProductAttributeTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/dataset" xsi:type="string">one_variation</data> <constraint name="Magento\Catalog\Test\Constraint\AssertUsedSuperAttributeImpossibleDeleteMessages" /> <constraint name="Magento\Catalog\Test\Constraint\AssertProductAttributeInGrid" /> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml index e1b6fcf47e562..f831173ba0ae0 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\ConfigurableProduct\Test\TestCase\CreateConfigurableProductEntityTest" summary="Create Configurable Product" ticketId="MAGETWO-26041"> <variation name="CreateConfigurableProductEntityTestVariation1" summary="Create product with category and two new options"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/url_key" xsi:type="string">configurable-product-%isolation%</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_new_options</data> <data name="product/data/checkout_data/dataset" xsi:type="string">configurable_two_options</data> @@ -32,6 +33,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertChildProductIsNotDisplayedSeparately"/> </variation> <variation name="CreateConfigurableProductEntityTestVariation2" summary="Create product with two options"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/url_key" xsi:type="string">configurable-product-%isolation%</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_options</data> <data name="product/data/checkout_data/dataset" xsi:type="string">configurable_two_options</data> @@ -97,6 +99,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertConfigurableProductInCart" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation5" summary="Create Configurable Product and Assign it to Category" ticketId="MAGETWO-12620"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/url_key" xsi:type="string">configurable-product-%isolation%</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_options_with_fixed_price</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> @@ -113,7 +116,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertConfigurableProductPage" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation6" summary="Create Configurable Product with Creating New Category and New Attribute (Required Fields Only)" ticketId="MAGETWO-13361"> - <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> + <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, mftf_migrated:yes</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_searchable_options</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> <data name="product/data/sku" xsi:type="string">configurable_sku_%isolation%</data> @@ -129,6 +132,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertConfigurableProductPage" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation7" summary="Verify that variation's SKU based on parent SKU"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_new_options_with_empty_sku</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> <data name="product/data/sku" xsi:type="string">configurable_sku_%isolation%</data> @@ -137,6 +141,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertChildProductsGeneratedSku" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation8" summary="Assert notice that existing sku automatically changed when saving product with same sku"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_new_options_with_parent_sku</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> <data name="product/data/sku" xsi:type="string">existing_sku</data> @@ -145,6 +150,7 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertProductAutoincrementedSkuNoticeMessage" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation9" summary="Create configurable product and assign it to custom website"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/url_key" xsi:type="string">configurable-product-%isolation%</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_options_with_assigned_product_special_price</data> <data name="product/data/checkout_data/dataset" xsi:type="string">configurable_two_new_options_with_special_price</data> @@ -156,6 +162,7 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertProductOnCustomWebsite" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation10" summary="Create configurable product with tier price for one item"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/url_key" xsi:type="string">configurable-product-%isolation%</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_options_with_assigned_product_tier_price</data> <data name="product/data/checkout_data/dataset" xsi:type="string">configurable_two_new_options_with_special_price</data> @@ -170,7 +177,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertProductTierPriceOnProductPage" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation11" summary="Create Configurable Product with out of stock child" ticketId="MAGETWO-65660"> - <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> + <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, mftf_migrated:yes</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">with_out_of_stock_item</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> <data name="product/data/sku" xsi:type="string">configurable_sku_%isolation%</data> @@ -189,7 +196,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertConfigurableProductOutOfStockPage" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation12" summary="Create Configurable Product with disabled child" ticketId="MAGETWO-65661"> - <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> + <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, mftf_migrated:yes</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">with_disabled_item</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> <data name="product/data/sku" xsi:type="string">configurable_sku_%isolation%</data> @@ -207,7 +214,7 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertProductNotVisibleInCategory" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation13" summary="Create Configurable Product with one disabled child and with one out of stock child" ticketId="MAGETWO-65662"> - <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> + <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, mftf_migrated:yes</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">with_one_disabled_item_and_one_out_of_stock_item</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> <data name="product/data/sku" xsi:type="string">configurable_sku_%isolation%</data> @@ -225,6 +232,7 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertProductVisibleInCategory" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation14" summary="Create configurable product with images" ticketId="MAGETWO-41354"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">color_and_size_with_images</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> <data name="product/data/sku" xsi:type="string">configurable_sku_%isolation%</data> @@ -238,6 +246,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertConfigurableProductImages" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation15" summary="Create Configurable Product with 1 out of stock and several in stock options with displaying out of stock ones" ticketId="MAGETWO-89274"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/url_key" xsi:type="string">configurable-product-%isolation%</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">three_new_options_with_out_of_stock_product</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> @@ -254,6 +263,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertOutOfStockOptionIsAbsentOnProductPage" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation16" summary="Create Configurable Product with 1 out of stock and several in stock options" ticketId="MAGETWO-69508"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/url_key" xsi:type="string">configurable-product-%isolation%</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">three_new_options_with_out_of_stock_product</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml index a62bcf92ebf39..5af854cae5434 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Catalog\Test\TestCase\Product\ValidateOrderOfProductTypeTest"> <variation name="ValidateOrderOfProductTypeTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="menu/1" xsi:type="string">Configurable Product</data> </variation> </testCase> diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml index 5bb96dc13c739..ff87a1df60fe8 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Customer\Test\TestCase\CreateCustomerBackendEntityTest" summary="Create Customer from Backend" ticketId="MAGETWO-23424"> <variation name="CreateCustomerBackendEntityTestVariation1" summary="General customer without address"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="customerAction" xsi:type="string">save</data> <data name="customer/data/website_id" xsi:type="string">Main Website</data> <data name="customer/data/group_id/dataset" xsi:type="string">General</data> @@ -35,7 +36,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerForm" /> </variation> <variation name="CreateCustomerBackendEntityTestVariation3" summary="General customer from USA"> - <data name="tag" xsi:type="string">test_type:extended_acceptance_test</data> + <data name="tag" xsi:type="string">test_type:extended_acceptance_test, mftf_migrated:yes</data> <data name="customerAction" xsi:type="string">save</data> <data name="customer/data/website_id" xsi:type="string">Main Website</data> <data name="customer/data/group_id/dataset" xsi:type="string">General</data> @@ -55,6 +56,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerForm" /> </variation> <variation name="CreateCustomerBackendEntityTestVariation4" summary="Retailer customer without address"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="customerAction" xsi:type="string">save</data> <data name="customer/data/website_id" xsi:type="string">Main Website</data> <data name="customer/data/group_id/dataset" xsi:type="string">Retailer</data> @@ -64,6 +66,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerInvalidEmail" /> </variation> <variation name="CreateCustomerBackendEntityTestVariation5" summary="General customer from Poland"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="customerAction" xsi:type="string">save</data> <data name="customer/data/website_id" xsi:type="string">Main Website</data> <data name="customer/data/group_id/dataset" xsi:type="string">General</data> @@ -83,6 +86,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerForm" /> </variation> <variation name="CreateCustomerBackendEntityTestVariation6" summary="Create New Customer on Backend" ticketId="MAGETWO-12516"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="customerAction" xsi:type="string">saveAndContinue</data> <data name="customer/data/website_id" xsi:type="string">Main Website</data> <data name="customer/data/group_id/dataset" xsi:type="string">General</data> @@ -105,6 +109,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerForm" /> </variation> <variation name="CreateCustomerBackendEntityTestVariation8" summary="Verify required fields on Account Information tab."> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="customerAction" xsi:type="string">save</data> <data name="customer/data/website_id" xsi:type="string">Main Website</data> <data name="customer/data/group_id/dataset" xsi:type="string">General</data> @@ -116,6 +121,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerBackendRequiredFields" /> </variation> <variation name="CreateCustomerBackendEntityTestVariation9" summary="Verify required fields on the Add address modal."> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="customer/data/website_id" xsi:type="string">Main Website</data> <data name="customer/data/group_id/dataset" xsi:type="string">General</data> <data name="customer/data/firstname" xsi:type="string">John%isolation%</data> diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml index 24f68f686fdc1..095746cfdef57 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml @@ -25,6 +25,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerInGrid" /> </variation> <variation name="UpdateCustomerBackendEntityTestVariation2"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="initialCustomer/dataset" xsi:type="string">default</data> <data name="customer/data/email" xsi:type="string">-</data> <data name="address/data/prefix" xsi:type="string">Prefix%isolation%_</data> @@ -75,6 +76,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerInGrid" /> </variation> <variation name="UpdateCustomerBackendEntityTestVariation4" summary="Address w/o zip/state required, default billing/shipping checked"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="initialCustomer/dataset" xsi:type="string">default</data> <data name="customer/data/email" xsi:type="string">-</data> <data name="address/data/default_billing" xsi:type="string">Yes</data> @@ -95,6 +97,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerLogin" /> </variation> <variation name="UpdateCustomerBackendEntityTestVariation5" summary="Default billing/shipping unchecked"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="initialCustomer/dataset" xsi:type="string">johndoe_unique_TX</data> <data name="customer/data/email" xsi:type="string">-</data> <data name="address/data/default_billing" xsi:type="string">No</data> @@ -114,6 +117,7 @@ <constraint name="Magento\Customer\Test\Constraint\AssertCustomerForm" /> </variation> <variation name="UpdateCustomerBackendEntityTestVariation6" summary="Delete customer address"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="initialCustomer/dataset" xsi:type="string">johndoe_with_multiple_addresses</data> <data name="customer/data/email" xsi:type="string">-</data> <data name="addressIndexToDelete" xsi:type="number">1</data> diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/ValidateOrderOfProductTypeTest.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/ValidateOrderOfProductTypeTest.xml index ccb74e1f79dc9..e807ec9134277 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/ValidateOrderOfProductTypeTest.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/ValidateOrderOfProductTypeTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Catalog\Test\TestCase\Product\ValidateOrderOfProductTypeTest"> <variation name="ValidateOrderOfProductTypeTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="menu/5" xsi:type="string">Downloadable Product</data> </variation> </testCase> diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml index 5a5cfdd9adc4c..ac57cdeb92053 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Catalog\Test\TestCase\Product\ValidateOrderOfProductTypeTest"> <variation name="ValidateOrderOfProductTypeTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="menu/2" xsi:type="string">Grouped Product</data> </variation> </testCase> diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.xml b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.xml index 66ae1d8179af5..865530862853a 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.xml @@ -8,7 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Store\Test\TestCase\DeleteStoreGroupEntityTest" summary="Delete Store Group" ticketId="MAGETWO-27596"> <variation name="DeleteStoreGroupEntityTestVariation1"> - <data name="tag" xsi:type="string">severity:S3</data> + <data name="tag" xsi:type="string">severity:S3, mftf_migrated:yes</data> <data name="storeGroup/dataset" xsi:type="string">custom</data> <data name="createBackup" xsi:type="string">Yes</data> <constraint name="Magento\Store\Test\Constraint\AssertStoreGroupSuccessDeleteAndBackupMessages" /> diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.xml index 730eb285d6d0c..1f888c3a2a8b9 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\UrlRewrite\Test\TestCase\CategoryUrlRewriteTest" summary="Check url rewrites in catalog categories after changing url key for store view and moving category." ticketId="MAGETWO-45385"> <variation name="CategoryUrlRewriteTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="storeView/dataset" xsi:type="string">custom</data> <data name="childCategory/dataset" xsi:type="string">default</data> <data name="childCategory/data/category_products/dataset" xsi:type="string">catalogProductSimple::default</data> diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.xml index 1917ec928bfaf..0cf2fd9c0d4e1 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.xml @@ -8,7 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\UrlRewrite\Test\TestCase\CreateProductUrlRewriteEntityTest" summary="Create Product URL Rewrites" ticketId="MAGETWO-25150"> <variation name="CreateProductUrlRewriteEntityTestVariation1" summary="Add Temporary Redirect for Product" ticketId="MAGETWO-12409"> - <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> + <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, mftf_migrated:yes</data> <data name="urlRewrite/data/entity_type" xsi:type="string">For Product</data> <data name="product/dataset" xsi:type="string">product_with_category</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> @@ -19,6 +19,7 @@ <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteProductRedirect" /> </variation> <variation name="CreateProductUrlRewriteEntityTestVariation2" summary="Create Product URL Rewrites with no redirect"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="urlRewrite/data/entity_type" xsi:type="string">For Product</data> <data name="product/dataset" xsi:type="string">default</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> @@ -28,6 +29,7 @@ <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteSaveMessage" /> </variation> <variation name="CreateProductUrlRewriteEntityTestVariation3" summary="Create Product URL Rewrites with Temporary redirect"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="urlRewrite/data/entity_type" xsi:type="string">For Product</data> <data name="product/dataset" xsi:type="string">default</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> @@ -38,6 +40,7 @@ <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteProductRedirect" /> </variation> <variation name="CreateProductUrlRewriteEntityTestVariation4" summary="Create Product URL Rewrites with Permanent redirect"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="urlRewrite/data/entity_type" xsi:type="string">For Product</data> <data name="product/dataset" xsi:type="string">default</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> @@ -48,6 +51,7 @@ <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteProductRedirect" /> </variation> <variation name="CreateProductUrlRewriteEntityTestVariation5" summary="Autoupdate URL Rewrites if Subcategories deleted" ticketId="MAGETWO-27325"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="urlRewrite/data/entity_type" xsi:type="string">For Product</data> <data name="product/dataset" xsi:type="string">product_with_category</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml index 98e3f9e38382d..8e737f193cf94 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\UrlRewrite\Test\TestCase\CreateProductWithSeveralWebsitesUrlRewriteTest" summary="Test product url rewrites when it is created in several websites"> <variation name="CreateSimpleProductEntityWithSeveralWebsites" summary="Create product with several websites and check URL Rewites" ticketId="MAGETWO-27238"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="product/data/url_key" xsi:type="string">simple-product-%isolation%</data> <data name="product/data/name" xsi:type="string">Simple Product %isolation%</data> <data name="product/data/sku" xsi:type="string">simple_sku_%isolation%</data> diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCustomUrlRewriteEntityTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCustomUrlRewriteEntityTest.xml index 90f5edec2f46b..8e0e8ebde99fb 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCustomUrlRewriteEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCustomUrlRewriteEntityTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\UrlRewrite\Test\TestCase\DeleteCustomUrlRewriteEntityTest" summary="Delete Custom URL Rewrites" ticketId="MAGETWO-26337"> <variation name="DeleteCustomUrlRewriteEntityTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="urlRewrite/dataset" xsi:type="string">default</data> <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteDeletedMessage" /> <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteNotInGrid" /> diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.xml index 4a88ad01b5a75..b2be1a205212e 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\UrlRewrite\Test\TestCase\UpdateCategoryUrlRewriteEntityTest" summary="Update Category URL Rewrites" ticketId="MAGETWO-24838"> <variation name="UpdateCategoryUrlRewriteEntityTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> <data name="category/dataset" xsi:type="string">default_subcategory</data> <data name="categoryRewrite/dataset" xsi:type="string">default</data> @@ -20,6 +21,7 @@ <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteCategoryRedirect" /> </variation> <variation name="UpdateCategoryUrlRewriteEntityTestVariation2"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> <data name="category/dataset" xsi:type="string">default_subcategory</data> <data name="categoryRewrite/dataset" xsi:type="string">default</data> @@ -32,6 +34,7 @@ <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteCategoryRedirect" /> </variation> <variation name="UpdateCategoryUrlRewriteEntityTestVariation3"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> <data name="category/dataset" xsi:type="string">default_subcategory</data> <data name="categoryRewrite/dataset" xsi:type="string">default</data> @@ -44,6 +47,7 @@ <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteCategoryRedirect" /> </variation> <variation name="UpdateCategoryUrlRewriteEntityTestVariation4"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> <data name="category/dataset" xsi:type="string">default_subcategory</data> <data name="categoryRewrite/dataset" xsi:type="string">default</data> diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCustomUrlRewriteEntityTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCustomUrlRewriteEntityTest.xml index 3671cd767ece9..2405216c12203 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCustomUrlRewriteEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCustomUrlRewriteEntityTest.xml @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\UrlRewrite\Test\TestCase\UpdateCustomUrlRewriteEntityTest" summary="Update Custom URL Rewrites" ticketId="MAGETWO-25784"> <variation name="UpdateCustomUrlRewriteEntityTestVariation1"> + <data name="tag" xsi:type="string">mftf_migrated:yes</data> <data name="initialRewrite/dataset" xsi:type="string">default</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> <data name="urlRewrite/data/request_path" xsi:type="string">wishlist/%isolation%</data> @@ -19,7 +20,7 @@ <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteSuccessOutsideRedirect" /> </variation> <variation name="UpdateCustomUrlRewriteEntityTestVariation2"> - <data name="tag" xsi:type="string">test_type:extended_acceptance_test</data> + <data name="tag" xsi:type="string">test_type:extended_acceptance_test, mftf_migrated:yes</data> <data name="initialRewrite/dataset" xsi:type="string">custom_rewrite_wishlist</data> <data name="urlRewrite/data/store_id" xsi:type="string">Main Website/Main Website Store/Default Store View</data> <data name="urlRewrite/data/request_path" xsi:type="string">wishlist/%isolation%</data> diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceWithDimensionTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceWithDimensionTest.php index 280e83a863325..fe39de2729eac 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceWithDimensionTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceWithDimensionTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + declare(strict_types=1); namespace Magento\Catalog\Model\Product\Type; @@ -108,7 +109,7 @@ public function testGetFinalPrice() } /** - * Get formated price + * Get formatted price */ public function testGetFormatedPrice() { diff --git a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php index 73f1dd9e7b711..e59672f1b5e1a 100644 --- a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php +++ b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php @@ -7,6 +7,8 @@ namespace Magento\Config\Console\Command; use Magento\Config\Model\Config\Backend\Admin\Custom; +use Magento\Config\Model\Config\Structure\Converter; +use Magento\Config\Model\Config\Structure\Data as StructureData; use Magento\Directory\Model\Currency; use Magento\Framework\App\Config\ConfigPathResolver; use Magento\Framework\App\Config\ScopeConfigInterface; @@ -91,6 +93,8 @@ protected function setUp() { Bootstrap::getInstance()->reinitialize(); $this->objectManager = Bootstrap::getObjectManager(); + $this->extendSystemStructure(); + $this->scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); $this->reader = $this->objectManager->get(FileReader::class); $this->filesystem = $this->objectManager->get(Filesystem::class); @@ -123,6 +127,21 @@ protected function tearDown() $this->appConfig->reinit(); } + /** + * Add test system structure to main system structure + * + * @return void + */ + private function extendSystemStructure() + { + $document = new \DOMDocument(); + $document->load(__DIR__ . '/../../_files/system.xml'); + $converter = $this->objectManager->get(Converter::class); + $systemConfig = $converter->convert($document); + $structureData = $this->objectManager->get(StructureData::class); + $structureData->merge($systemConfig); + } + /** * @return array */ @@ -191,6 +210,8 @@ public function runLockDataProvider() ['general/region/display_all', '1'], ['general/region/state_required', 'BR,FR', ScopeInterface::SCOPE_WEBSITE, 'base'], ['admin/security/use_form_key', '0'], + ['general/group/subgroup/field', 'default_value'], + ['general/group/subgroup/field', 'website_value', ScopeInterface::SCOPE_WEBSITE, 'base'], ]; } diff --git a/dev/tests/integration/testsuite/Magento/Config/_files/system.xml b/dev/tests/integration/testsuite/Magento/Config/_files/system.xml new file mode 100644 index 0000000000000..f0063a3c0bf7f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/_files/system.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd"> + <system> + <section id="general"> + <group id="group"> + <group id="subgroup"> + <field id="field" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Label</label> + </field> + </group> + </group> + </section> + </system> +</config> diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Service/InvoiceServiceTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Service/InvoiceServiceTest.php new file mode 100644 index 0000000000000..e35c480e44c66 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Service/InvoiceServiceTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Sales\Model\Service; + +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Model\Order; +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Tests \Magento\Sales\Model\Service\InvoiceService + */ +class InvoiceServiceTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var InvoiceService + */ + private $invoiceService; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->invoiceService = Bootstrap::getObjectManager()->create(InvoiceService::class); + } + + /** + * @param int $invoiceQty + * @magentoDataFixture Magento/Sales/_files/order_configurable_product.php + * @return void + * @dataProvider prepareInvoiceConfigurableProductDataProvider + */ + public function testPrepareInvoiceConfigurableProduct(int $invoiceQty): void + { + /** @var OrderInterface $order */ + $order = Bootstrap::getObjectManager()->create(Order::class)->load('100000001', 'increment_id'); + $orderItems = $order->getItems(); + foreach ($orderItems as $orderItem) { + if ($orderItem->getParentItemId()) { + $parentItemId = $orderItem->getParentItemId(); + } + } + $invoice = $this->invoiceService->prepareInvoice($order, [$parentItemId => $invoiceQty]); + $invoiceItems = $invoice->getItems(); + foreach ($invoiceItems as $invoiceItem) { + $this->assertEquals($invoiceQty, $invoiceItem->getQty()); + } + } + + public function prepareInvoiceConfigurableProductDataProvider() + { + return [ + 'full invoice' => [2], + 'partial invoice' => [1] + ]; + } + + /** + * @param int $invoiceQty + * @magentoDataFixture Magento/Sales/_files/order.php + * @return void + * @dataProvider prepareInvoiceSimpleProductDataProvider + */ + public function testPrepareInvoiceSimpleProduct(int $invoiceQty): void + { + /** @var OrderInterface $order */ + $order = Bootstrap::getObjectManager()->create(Order::class)->load('100000001', 'increment_id'); + $orderItems = $order->getItems(); + $invoiceQtys = []; + foreach ($orderItems as $orderItem) { + $invoiceQtys[$orderItem->getItemId()] = $invoiceQty; + } + $invoice = $this->invoiceService->prepareInvoice($order, $invoiceQtys); + $invoiceItems = $invoice->getItems(); + foreach ($invoiceItems as $invoiceItem) { + $this->assertEquals($invoiceQty, $invoiceItem->getQty()); + } + } + + public function prepareInvoiceSimpleProductDataProvider() + { + return [ + 'full invoice' => [2], + 'partial invoice' => [1] + ]; + } +} diff --git a/lib/internal/Magento/Framework/Data/Collection.php b/lib/internal/Magento/Framework/Data/Collection.php index dbafc9734e091..9c789e81913c4 100644 --- a/lib/internal/Magento/Framework/Data/Collection.php +++ b/lib/internal/Magento/Framework/Data/Collection.php @@ -7,7 +7,6 @@ use Magento\Framework\Data\Collection\EntityFactoryInterface; use Magento\Framework\Option\ArrayInterface; -use Magento\Framework\Exception\InputException; /** * Data collection @@ -235,20 +234,12 @@ protected function _setIsLoaded($flag = true) * Get current collection page * * @param int $displacement - * @throws \Magento\Framework\Exception\InputException * @return int */ public function getCurPage($displacement = 0) { if ($this->_curPage + $displacement < 1) { return 1; - } elseif ($this->_curPage > $this->getLastPageNumber() && $displacement === 0) { - throw new InputException( - __( - 'currentPage value %1 specified is greater than the %2 page(s) available.', - [$this->_curPage, $this->getLastPageNumber()] - ) - ); } elseif ($this->_curPage + $displacement > $this->getLastPageNumber()) { return $this->getLastPageNumber(); } else { diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/CollectionTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/CollectionTest.php index 80c256d8553ef..daadeae2ac0e2 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/CollectionTest.php +++ b/lib/internal/Magento/Framework/Data/Test/Unit/CollectionTest.php @@ -144,19 +144,6 @@ public function testGetCurPage() $this->assertEquals(1, $this->_model->getCurPage()); } - /** - * Test for getCurPage with exception. - * - * @expectedException \Magento\Framework\Exception\StateException - * @return void - */ - public function testGetCurPageWithException() - { - $this->_model->setCurPage(10); - $this->expectException(\Magento\Framework\Exception\InputException::class); - $this->_model->getCurPage(); - } - /** * Test for method possibleFlowWithItem. * diff --git a/lib/internal/Magento/Framework/Filesystem/DirectoryList.php b/lib/internal/Magento/Framework/Filesystem/DirectoryList.php index 20874f60791c1..b3ab51b948109 100644 --- a/lib/internal/Magento/Framework/Filesystem/DirectoryList.php +++ b/lib/internal/Magento/Framework/Filesystem/DirectoryList.php @@ -8,6 +8,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Framework\Filesystem; /** @@ -96,7 +97,8 @@ public function __construct($root, array $config = []) static::validate($config); $this->root = $this->normalizePath($root); $this->directories = static::getDefaultConfig(); - $this->directories[self::SYS_TMP] = [self::PATH => realpath(sys_get_temp_dir())]; + $sysTmpPath = get_cfg_var('upload_tmp_dir') ?: sys_get_temp_dir(); + $this->directories[self::SYS_TMP] = [self::PATH => realpath($sysTmpPath)]; // inject custom values from constructor foreach ($this->directories as $code => $dir) { diff --git a/setup/src/Magento/Setup/Controller/Session.php b/setup/src/Magento/Setup/Controller/Session.php index e310dd485ace5..c9caa5a8de792 100644 --- a/setup/src/Magento/Setup/Controller/Session.php +++ b/setup/src/Magento/Setup/Controller/Session.php @@ -5,6 +5,9 @@ */ namespace Magento\Setup\Controller; +/** + * Sets up session for setup/index.php/session/prolong or redirects to error page + */ class Session extends \Zend\Mvc\Controller\AbstractActionController { /** @@ -52,23 +55,28 @@ public function prolongAction() try { if ($this->serviceManager->get(\Magento\Framework\App\DeploymentConfig::class)->isAvailable()) { $objectManager = $this->objectManagerProvider->get(); - /** @var \Magento\Framework\App\State $adminAppState */ - $adminAppState = $objectManager->get(\Magento\Framework\App\State::class); - $adminAppState->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML); - $sessionConfig = $objectManager->get(\Magento\Backend\Model\Session\AdminConfig::class); - /** @var \Magento\Backend\Model\Url $backendUrl */ - $backendUrl = $objectManager->get(\Magento\Backend\Model\Url::class); - $urlPath = parse_url($backendUrl->getBaseUrl(), PHP_URL_PATH); - $cookiePath = $urlPath . 'setup'; - $sessionConfig->setCookiePath($cookiePath); /* @var \Magento\Backend\Model\Auth\Session $session */ - $session = $objectManager->create( - \Magento\Backend\Model\Auth\Session::class, - [ - 'sessionConfig' => $sessionConfig, - 'appState' => $adminAppState - ] - ); + $session = $objectManager->get(\Magento\Backend\Model\Auth\Session::class); + // check if session was already set in \Magento\Setup\Mvc\Bootstrap\InitParamListener::authPreDispatch + if (!$session->isSessionExists()) { + /** @var \Magento\Framework\App\State $adminAppState */ + $adminAppState = $objectManager->get(\Magento\Framework\App\State::class); + $adminAppState->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML); + $sessionConfig = $objectManager->get(\Magento\Backend\Model\Session\AdminConfig::class); + /** @var \Magento\Backend\Model\Url $backendUrl */ + $backendUrl = $objectManager->get(\Magento\Backend\Model\Url::class); + $urlPath = parse_url($backendUrl->getBaseUrl(), PHP_URL_PATH); + $cookiePath = $urlPath . 'setup'; + $sessionConfig->setCookiePath($cookiePath); + /* @var \Magento\Backend\Model\Auth\Session $session */ + $session = $objectManager->create( + \Magento\Backend\Model\Auth\Session::class, + [ + 'sessionConfig' => $sessionConfig, + 'appState' => $adminAppState + ] + ); + } $session->prolong(); return new \Zend\View\Model\JsonModel(['success' => true]); } @@ -78,6 +86,8 @@ public function prolongAction() } /** + * Unlogin action, return 401 error page + * * @return \Zend\View\Model\ViewModel|\Zend\Http\Response */ public function unloginAction() diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/SessionTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/SessionTest.php index f8e5e7cdc4d70..216013ebfc8d9 100644 --- a/setup/src/Magento/Setup/Test/Unit/Controller/SessionTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Controller/SessionTest.php @@ -48,6 +48,12 @@ public function testUnloginAction() $this->createPartialMock(\Magento\Framework\App\DeploymentConfig::class, ['isAvailable']); $deployConfigMock->expects($this->once())->method('isAvailable')->will($this->returnValue(true)); + $sessionMock = $this->createPartialMock( + \Magento\Backend\Model\Auth\Session::class, + ['prolong', 'isSessionExists'] + ); + $sessionMock->expects($this->once())->method('isSessionExists')->will($this->returnValue(false)); + $stateMock = $this->createPartialMock(\Magento\Framework\App\State::class, ['setAreaCode']); $stateMock->expects($this->once())->method('setAreaCode'); @@ -57,6 +63,7 @@ public function testUnloginAction() $urlMock = $this->createMock(\Magento\Backend\Model\Url::class); $returnValueMap = [ + [\Magento\Backend\Model\Auth\Session::class, $sessionMock], [\Magento\Framework\App\State::class, $stateMock], [\Magento\Backend\Model\Session\AdminConfig::class, $sessionConfigMock], [\Magento\Backend\Model\Url::class, $urlMock] @@ -68,7 +75,6 @@ public function testUnloginAction() ->method('get') ->will($this->returnValueMap($returnValueMap)); - $sessionMock = $this->createPartialMock(\Magento\Backend\Model\Auth\Session::class, ['prolong']); $this->objectManager->expects($this->once()) ->method('create') ->will($this->returnValue($sessionMock)); @@ -87,4 +93,29 @@ public function testIndexAction() $viewModel = $controller->unloginAction(); $this->assertInstanceOf(\Zend\View\Model\ViewModel::class, $viewModel); } + + /** + * @covers \Magento\Setup\Controller\SystemConfig::prolongAction + */ + public function testProlongActionWithExistingSession() + { + $this->objectManagerProvider->expects($this->once())->method('get')->will( + $this->returnValue($this->objectManager) + ); + $deployConfigMock = + $this->createPartialMock(\Magento\Framework\App\DeploymentConfig::class, ['isAvailable']); + $deployConfigMock->expects($this->once())->method('isAvailable')->will($this->returnValue(true)); + $sessionMock = $this->createPartialMock( + \Magento\Backend\Model\Auth\Session::class, + ['prolong', 'isSessionExists'] + ); + $sessionMock->expects($this->once())->method('isSessionExists')->will($this->returnValue(true)); + + $this->serviceManager->expects($this->once())->method('get')->will($this->returnValue($deployConfigMock)); + $this->objectManager->expects($this->once()) + ->method('get') + ->will($this->returnValue($sessionMock)); + $controller = new Session($this->serviceManager, $this->objectManagerProvider); + $this->assertEquals(new \Zend\View\Model\JsonModel(['success' => true]), $controller->prolongAction()); + } }