From aec946d2074ee3ba7865c89c7776ccca6d430f29 Mon Sep 17 00:00:00 2001 From: Serhii Balko Date: Mon, 4 Jan 2021 15:38:44 +0200 Subject: [PATCH 01/38] MC-39140: Error when adding products widget to CMS page in the admin --- .../ResourceModel/Product/Collection.php | 7 ++- .../ResourceModel/Product/CollectionTest.php | 50 ++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php index 3f908663c8e5e..a247e6b09760b 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php @@ -916,7 +916,12 @@ public function addWebsiteFilter($websites = null) } $this->_productLimitationFilters['website_ids'] = $websites; - $this->_applyProductLimitations(); + + if ($this->getStoreId() == Store::DEFAULT_STORE_ID) { + $this->_productLimitationJoinWebsite(); + } else { + $this->_applyProductLimitations(); + } return $this; } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php index 2bf504369b8a7..9a55e48cfb1b4 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php @@ -38,6 +38,7 @@ use Magento\Framework\Stdlib\DateTime\TimezoneInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Framework\Validator\UniversalFactory; +use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -93,6 +94,11 @@ class CollectionTest extends TestCase */ private $storeManager; + /** + * @var ProductLimitation|MockObject + */ + private $productLimitationMock; + /** * @var EntityFactory|MockObject */ @@ -192,7 +198,7 @@ protected function setUp(): void $this->entityMock->expects($this->any())->method('getTable')->willReturnArgument(0); $this->connectionMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock); - $productLimitationMock = $this->createMock( + $this->productLimitationMock = $this->createMock( ProductLimitation::class ); $productLimitationFactoryMock = $this->getMockBuilder( @@ -201,7 +207,7 @@ protected function setUp(): void ->setMethods(['create'])->getMock(); $productLimitationFactoryMock->method('create') - ->willReturn($productLimitationMock); + ->willReturn($this->productLimitationMock); $this->collection = $this->objectManager->getObject( Collection::class, [ @@ -432,4 +438,44 @@ public function testGetNewEmptyItem() $secondItem = $this->collection->getNewEmptyItem(); $this->assertEquals($firstItem, $secondItem); } + + /** + * Test to add website filter in admin area + */ + public function testAddWebsiteFilterOnAdminStore(): void + { + $websiteIds = [2]; + $websiteTable = 'catalog_product_website'; + $joinCondition = 'join condition'; + $this->productLimitationMock->expects($this->atLeastOnce()) + ->method('offsetSet') + ->with('website_ids', $websiteIds); + $this->productLimitationMock->method('offsetExists') + ->with('website_ids') + ->willReturn(true); + $this->productLimitationMock->method('offsetGet') + ->with('website_ids') + ->willReturn($websiteIds); + $this->connectionMock->expects($this->once()) + ->method('quoteInto') + ->with('product_website.website_id IN(?)', $websiteIds, 'int') + ->willReturn($joinCondition); + $this->selectMock->method('getPart')->with(Select::FROM)->willReturn([]); + /** @var AbstractEntity|MockObject $eavEntity */ + $eavEntity = $this->createMock(AbstractEntity::class); + $eavEntity->method('getTable') + ->with('catalog_product_website') + ->willReturn($websiteTable); + $this->selectMock->expects($this->once()) + ->method('join') + ->with( + ['product_website' => $websiteTable], + 'product_website.product_id = e.entity_id AND ' . $joinCondition, + [] + ); + + $this->collection->setEntity($eavEntity); + $this->collection->setStoreId(Store::DEFAULT_STORE_ID); + $this->collection->addWebsiteFilter($websiteIds); + } } From 73dc5381044021596dc68b467755d71b9d35b770 Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi Date: Mon, 11 Jan 2021 16:46:41 +0200 Subject: [PATCH 02/38] MC-39759: Navigation arrow buttons not visible after video starts on product image --- .../view/frontend/web/js/fotorama-add-video-events.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js b/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js index acaf2afeb6c26..bfd685543d7f7 100644 --- a/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js +++ b/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js @@ -714,6 +714,7 @@ define([ } $('.' + this.FTAR).addClass(this.isFullscreen ? 'fotorama__arr--shown' : 'fotorama__arr--hidden'); + $('.' + this.FTVC).addClass('fotorama-show-control'); } }, From 02a93cbd776e7a30a796ac4397ba050e047ebcf4 Mon Sep 17 00:00:00 2001 From: rostyslav-hymon Date: Tue, 12 Jan 2021 14:57:06 +0200 Subject: [PATCH 03/38] MC-40305: Can not delete upsell and crosssell products via import --- .../Model/Import/Product/LinkProcessor.php | 2 +- .../Model/Import/ProductTest.php | 41 ++++++++++++++++--- ...ort_with_product_links_with_empty_data.csv | 2 + ...product_export_with_product_links_data.php | 29 +++++++++---- 4 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_product_links_with_empty_data.csv diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/LinkProcessor.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/LinkProcessor.php index 22a83671f630a..84cdc4608148c 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/LinkProcessor.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/LinkProcessor.php @@ -220,7 +220,7 @@ private function deleteProductsLinks( if (!empty($linksToDelete) && Import::BEHAVIOR_APPEND === $importEntity->getBehavior()) { foreach ($linksToDelete as $linkTypeId => $productIds) { if (!empty($productIds)) { - $whereLinkId = $importEntity->getConnection()->quoteInto('link_type_id', $linkTypeId); + $whereLinkId = $importEntity->getConnection()->quoteInto('link_type_id = ?', $linkTypeId); $whereProductId = $importEntity->getConnection()->quoteInto( 'product_id IN (?)', array_unique($productIds) diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index 53e32483ee3d6..ceb07e3445c0e 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -1721,15 +1721,23 @@ public function testValidateUrlKeysMultipleStores() } /** + * Test import product with product links and empty value + * + * @param string $pathToFile + * @param bool $expectedResultCrossell + * @param bool $expectedResultUpsell + * * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_with_product_links_data.php * @magentoAppArea adminhtml * @magentoDbIsolation enabled * @magentoAppIsolation enabled + * @dataProvider getEmptyLinkedData */ - public function testProductLinksWithEmptyValue() - { - // import data from CSV file - $pathToFile = __DIR__ . '/_files/products_to_import_with_product_links_with_empty_value.csv'; + public function testProductLinksWithEmptyValue( + string $pathToFile, + bool $expectedResultCrossell, + bool $expectedResultUpsell + ): void { $filesystem = BootstrapHelper::getObjectManager()->create(Filesystem::class); $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); @@ -1759,8 +1767,29 @@ public function testProductLinksWithEmptyValue() $product = BootstrapHelper::getObjectManager()->create(Product::class); $product->load($productId); - $this->assertEmpty($product->getCrossSellProducts()); - $this->assertEmpty($product->getUpSellProducts()); + $this->assertEquals(empty($product->getCrossSellProducts()), $expectedResultCrossell); + $this->assertEquals(empty($product->getUpSellProducts()), $expectedResultUpsell); + } + + /** + * Get data for empty linked product + * + * @return array[] + */ + public function getEmptyLinkedData(): array + { + return [ + [ + __DIR__ . '/_files/products_to_import_with_product_links_with_empty_value.csv', + true, + true, + ], + [ + __DIR__ . '/_files/products_to_import_with_product_links_with_empty_data.csv', + false, + true, + ], + ]; } /** diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_product_links_with_empty_data.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_product_links_with_empty_data.csv new file mode 100644 index 0000000000000..d8812defa0828 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_product_links_with_empty_data.csv @@ -0,0 +1,2 @@ +sku,crosssell_skus,crosssell_position,upsell_skus,upsell_position +simple,,,__EMPTY__VALUE__,__EMPTY__VALUE__ diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data.php index 5dde578a1341f..8ee35d747ea1a 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data.php @@ -18,7 +18,26 @@ $objectManager = Bootstrap::getObjectManager(); /** @var ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->create(ProductRepositoryInterface::class); -$product = $productRepository->get('simple_ms_1'); +/** @var \Magento\Catalog\Api\Data\ProductLinkInterface $productLink */ +$productCrosssellLink = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Api\Data\ProductLinkInterface::class); +$productCrosssellLink->setSku('simple'); +$productCrosssellLink->setLinkedProductSku('simple_ms_1'); +$productCrosssellLink->setPosition(2); +$productCrosssellLink->setLinkType('crosssell'); +$productUpsellLink = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Api\Data\ProductLinkInterface::class); +$productUpsellLink->setSku('simple'); +$productUpsellLink->setLinkedProductSku('simple_ms_1'); +$productUpsellLink->setPosition(1); +$productUpsellLink->setLinkType('upsell'); +$productRelatedLink = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Api\Data\ProductLinkInterface::class); +$productRelatedLink->setSku('simple'); +$productRelatedLink->setLinkedProductSku('simple_ms_1'); +$productRelatedLink->setPosition(3); +$productRelatedLink->setLinkType('related'); + $productModel = $objectManager->create( \Magento\Catalog\Model\Product::class ); @@ -51,10 +70,6 @@ true )->setCategoryIds( [333] -)->setUpSellLinkData( - [$product->getId() => ['position' => 1]] -)->setCrossSellLinkData( - [$product->getId() => ['position' => 2]] -)->setRelatedLinkData( - [$product->getId() => ['position' => 3]] +)->setProductLinks( + [$productCrosssellLink, $productUpsellLink, $productRelatedLink] )->save(); From 0b3c5f11745795d453e66aa6b6f1bf213ab51ae8 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 12 Jan 2021 15:10:07 -0600 Subject: [PATCH 04/38] B2B-1637: Fix GET_LOCK error on read-only slave connection --- app/code/Magento/Config/etc/di.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Config/etc/di.xml b/app/code/Magento/Config/etc/di.xml index 4277ca0a6de26..76cfdbfa60b82 100644 --- a/app/code/Magento/Config/etc/di.xml +++ b/app/code/Magento/Config/etc/di.xml @@ -96,7 +96,7 @@ - Magento\Framework\Lock\Backend\Database + Magento\Framework\Lock\Proxy From 8d676bc8f7244e0b5abb5c98c5854dd328f78dc0 Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi Date: Wed, 13 Jan 2021 14:32:55 +0200 Subject: [PATCH 05/38] MC-39759: Navigation arrow buttons not visible after video starts on product image --- .../StorefrontProductInfoMainSection.xml | 2 + ...eoVideoControlButtonsOnProductPageTest.xml | 79 +++++++++++++++++++ lib/web/mage/gallery/gallery.less | 2 +- 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml index e94d426ba7638..44c65c197f7db 100644 --- a/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml +++ b/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -14,5 +14,7 @@ + + diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml b/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml new file mode 100644 index 0000000000000..dab325e19d102 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml @@ -0,0 +1,79 @@ + + + + + + + + + + <description value="Navigation arrow buttons not visible after video starts on product image"/> + <severity value="MAJOR"/> + <testCaseId value="MC-40398"/> + <group value="productVideo"/> + </annotations> + <before> + <createData entity="SimpleProduct2" stepKey="createProduct"/> + <!-- Login to Admin page --> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <!-- Logout from Admin page --> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <!-- Open product edit page --> + <amOnPage url="{{AdminProductEditPage.url($createProduct.id$)}}" stepKey="goToProductEditPage"/> + <!-- Add image to product --> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImageForProduct"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + <!-- Add product video --> + <actionGroup ref="AddProductVideoActionGroup" stepKey="addProductVideo"> + <argument name="video" value="VimeoProductVideo"/> + </actionGroup> + <!-- Save product form --> + <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProductForm"/> + + <!-- Open storefront product page --> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="goToStorefrontProductPage"> + <argument name="productUrl" value="$createProduct.custom_attributes[url_key]$"/> + </actionGroup> + + <!-- Assert product navigation arrows --> + <dontSeeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="dontSeePrevButton"/> + <seeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="seeNextButton"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickNextButton"/> + + <!-- Assert product video present in the storefront product page --> + <actionGroup ref="AssertProductVideoStorefrontProductPageActionGroup" stepKey="assertProductVideoPresentInStorefrontProductPage"> + <argument name="videoType" value="vimeo"/> + </actionGroup> + <dontSeeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="dontSeeCloseVideo"/> + + <!-- Click Play video button --> + <click stepKey="clickToPlayVideo" selector="{{StorefrontProductInfoMainSection.clickPlayVideo}}"/> + <wait stepKey="waitFiveSecondsToPlayVideo" time="5"/> + + <!-- Assert product navigation arrows --> + <dontSeeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="dontSeePrevButton2"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="dontSeeNextButton"/> + + <!-- Click Close video button --> + <seeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="seeCloseVideo"/> + <click stepKey="clickCloseVideo" selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}"/> + <wait stepKey="waitTwoSecondsToCloseVideo" time="2"/> + + <!-- Assert product navigation arrows --> + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> + <seeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="seePrevButton"/> + <click selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="clickPrevButton"/> + </test> +</tests> diff --git a/lib/web/mage/gallery/gallery.less b/lib/web/mage/gallery/gallery.less index 86ccdb858bf19..d6926720d7984 100644 --- a/lib/web/mage/gallery/gallery.less +++ b/lib/web/mage/gallery/gallery.less @@ -964,7 +964,7 @@ height: @fotorama_close_button; opacity: 0; right: 0; - top: 0; + top: 10%; transform: translate3d((@fotorama_close_button), (-@fotorama_close_button), 0); transition: opacity 0.3s ease-in-out; width: @fotorama_close_button; From 08bfb7519d5ebaa8e723fed3595d82957e6d646f Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi <tsviklinskyi@gmail.com> Date: Wed, 13 Jan 2021 16:59:17 +0200 Subject: [PATCH 06/38] MC-39759: Navigation arrow buttons not visible after video starts on product image --- ...oseButtonHiddenProductVideoActionGroup.xml | 19 ++++++++++++ ...extButtonHiddenProductVideoActionGroup.xml | 20 +++++++++++++ ...revButtonHiddenProductVideoActionGroup.xml | 20 +++++++++++++ ...lickCloseButtonProductVideoActionGroup.xml | 21 +++++++++++++ ...ClickNextButtonProductVideoActionGroup.xml | 21 +++++++++++++ ...ClickPlayButtonProductVideoActionGroup.xml | 20 +++++++++++++ ...ClickPrevButtonProductVideoActionGroup.xml | 21 +++++++++++++ ...eoVideoControlButtonsOnProductPageTest.xml | 30 ++++++++----------- 8 files changed, 155 insertions(+), 17 deletions(-) create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertCloseButtonHiddenProductVideoActionGroup.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickCloseButtonProductVideoActionGroup.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickNextButtonProductVideoActionGroup.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPlayButtonProductVideoActionGroup.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPrevButtonProductVideoActionGroup.xml diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertCloseButtonHiddenProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertCloseButtonHiddenProductVideoActionGroup.xml new file mode 100644 index 0000000000000..edd837db6c31c --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertCloseButtonHiddenProductVideoActionGroup.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 that close button is hidden on Storefront Product page --> + <actionGroup name="AssertCloseButtonHiddenProductVideoActionGroup"> + <annotations> + <description>Validates that the close button is absent on the Storefront Product page.</description> + </annotations> + + <dontSeeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="dontSeeCloseVideo"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml new file mode 100644 index 0000000000000..d6d756847e0b7 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.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"> + <!-- Assert that next button is hidden on Storefront Product page --> + <actionGroup name="AssertNextButtonHiddenProductVideoActionGroup"> + <annotations> + <description>Validates that the next button is absent on the Storefront Product page.</description> + </annotations> + + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="dontSeeNextButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml new file mode 100644 index 0000000000000..b5b9e801d3a9c --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.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"> + <!-- Assert that previous button is hidden on Storefront Product page --> + <actionGroup name="AssertPrevButtonHiddenProductVideoActionGroup"> + <annotations> + <description>Validates that the previous button is absent on the Storefront Product page.</description> + </annotations> + + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="dontSeePrevButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickCloseButtonProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickCloseButtonProductVideoActionGroup.xml new file mode 100644 index 0000000000000..a18e98eebb48c --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickCloseButtonProductVideoActionGroup.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"> + <!-- Click close button in product video on Storefront Product page --> + <actionGroup name="ClickCloseButtonProductVideoActionGroup"> + <annotations> + <description>Click close button in product video on the Storefront Product page.</description> + </annotations> + + <seeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="seeCloseVideo"/> + <click stepKey="clickCloseVideo" selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}"/> + <wait stepKey="waitTwoSecondsToCloseVideo" time="2"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickNextButtonProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickNextButtonProductVideoActionGroup.xml new file mode 100644 index 0000000000000..eb7c94514fa24 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickNextButtonProductVideoActionGroup.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"> + <!-- Click next button in product video on Storefront Product page --> + <actionGroup name="ClickNextButtonProductVideoActionGroup"> + <annotations> + <description>Click next button in product video on the Storefront Product page.</description> + </annotations> + + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> + <seeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="seeNextButton"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickNextButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPlayButtonProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPlayButtonProductVideoActionGroup.xml new file mode 100644 index 0000000000000..481097b488be8 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPlayButtonProductVideoActionGroup.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"> + <!-- Click play button in product video on Storefront Product page --> + <actionGroup name="ClickPlayButtonProductVideoActionGroup"> + <annotations> + <description>Click play button in product video on the Storefront Product page.</description> + </annotations> + + <click selector="{{StorefrontProductInfoMainSection.clickPlayVideo}}" stepKey="clickToPlayVideo"/> + <wait stepKey="waitFiveSecondsToPlayVideo" time="5"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPrevButtonProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPrevButtonProductVideoActionGroup.xml new file mode 100644 index 0000000000000..aa32812997624 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPrevButtonProductVideoActionGroup.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"> + <!-- Click previous button in product video on Storefront Product page --> + <actionGroup name="ClickPrevButtonProductVideoActionGroup"> + <annotations> + <description>Click previous button in product video on the Storefront Product page.</description> + </annotations> + + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> + <seeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="seePrevButton"/> + <click selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="clickPrevButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml b/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml index dab325e19d102..c86b11660bef8 100644 --- a/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml +++ b/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml @@ -30,7 +30,9 @@ </after> <!-- Open product edit page --> - <amOnPage url="{{AdminProductEditPage.url($createProduct.id$)}}" stepKey="goToProductEditPage"/> + <actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="goToProductEditPage"> + <argument name="productId" value="$createProduct.id$"/> + </actionGroup> <!-- Add image to product --> <actionGroup ref="AddProductImageActionGroup" stepKey="addImageForProduct"> <argument name="image" value="MagentoLogo"/> @@ -47,33 +49,27 @@ <argument name="productUrl" value="$createProduct.custom_attributes[url_key]$"/> </actionGroup> - <!-- Assert product navigation arrows --> - <dontSeeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="dontSeePrevButton"/> - <seeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="seeNextButton"/> - <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickNextButton"/> + <!-- Click next button --> + <actionGroup ref="AssertPrevButtonHiddenProductVideoActionGroup" stepKey="assertPrevButtonIsHidden"/> + <actionGroup ref="ClickNextButtonProductVideoActionGroup" stepKey="clickNextNavigationButton"/> <!-- Assert product video present in the storefront product page --> <actionGroup ref="AssertProductVideoStorefrontProductPageActionGroup" stepKey="assertProductVideoPresentInStorefrontProductPage"> <argument name="videoType" value="vimeo"/> </actionGroup> - <dontSeeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="dontSeeCloseVideo"/> + <actionGroup ref="AssertCloseButtonHiddenProductVideoActionGroup" stepKey="assertCloseVideoButtonIsHidden"/> <!-- Click Play video button --> - <click stepKey="clickToPlayVideo" selector="{{StorefrontProductInfoMainSection.clickPlayVideo}}"/> - <wait stepKey="waitFiveSecondsToPlayVideo" time="5"/> + <actionGroup ref="ClickPlayButtonProductVideoActionGroup" stepKey="clickPlayVideoButton"/> <!-- Assert product navigation arrows --> - <dontSeeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="dontSeePrevButton2"/> - <dontSeeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="dontSeeNextButton"/> + <actionGroup ref="AssertPrevButtonHiddenProductVideoActionGroup" stepKey="assertPrevButtonIsHidden2"/> + <actionGroup ref="AssertNextButtonHiddenProductVideoActionGroup" stepKey="assertNextButtonIsHidden"/> <!-- Click Close video button --> - <seeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="seeCloseVideo"/> - <click stepKey="clickCloseVideo" selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}"/> - <wait stepKey="waitTwoSecondsToCloseVideo" time="2"/> + <actionGroup ref="ClickCloseButtonProductVideoActionGroup" stepKey="clickCloseVideoButton"/> - <!-- Assert product navigation arrows --> - <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> - <seeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="seePrevButton"/> - <click selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="clickPrevButton"/> + <!-- Click previous button --> + <actionGroup ref="ClickPrevButtonProductVideoActionGroup" stepKey="clickPrevNavigationButton"/> </test> </tests> From 5b94d69af88c7693834612c8c4e1a6882aab84fb Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi <tsviklinskyi@gmail.com> Date: Wed, 13 Jan 2021 17:10:57 +0200 Subject: [PATCH 07/38] MC-39759: Navigation arrow buttons not visible after video starts on product image --- .../Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml b/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml index c86b11660bef8..a4719fa281f29 100644 --- a/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml +++ b/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml @@ -16,6 +16,7 @@ <description value="Navigation arrow buttons not visible after video starts on product image"/> <severity value="MAJOR"/> <testCaseId value="MC-40398"/> + <useCaseId value="MC-39759"/> <group value="productVideo"/> </annotations> <before> From 21d42cbb94bb8b6c331b540f75504bace159e7df Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Wed, 13 Jan 2021 11:19:18 -0600 Subject: [PATCH 08/38] B2B-1640: Add MFTF test for MC-38222 - Adding MFTF import test for MC-38222 --- ...efrontNavigateToCategoryUrlActionGroup.xml | 18 ++ ...geSelectDropDownOptionValueActionGroup.xml | 1 + .../Section/AdminProductImagesSection.xml | 1 + .../AdminClickCheckDataImportActionGroup.xml | 19 ++ .../AdminClickImportActionGroup.xml | 20 ++ .../AdminFillImportFormActionGroup.xml | 30 +++ .../AdminNavigateToImportPageActionGroup.xml | 17 ++ .../Test/Mftf/Data/ImportData.xml | 98 +++++++++ ...igurableProductsWithAssignedImagesTest.xml | 193 ++++++++++++++++++ 9 files changed, 397 insertions(+) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontNavigateToCategoryUrlActionGroup.xml create mode 100644 app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminClickCheckDataImportActionGroup.xml create mode 100644 app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminClickImportActionGroup.xml create mode 100644 app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminFillImportFormActionGroup.xml create mode 100644 app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminNavigateToImportPageActionGroup.xml create mode 100644 app/code/Magento/ImportExport/Test/Mftf/Data/ImportData.xml create mode 100644 app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontNavigateToCategoryUrlActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontNavigateToCategoryUrlActionGroup.xml new file mode 100644 index 0000000000000..f938627886540 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontNavigateToCategoryUrlActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontNavigateToCategoryUrlActionGroup"> + <annotations> + <description>Goes to the Storefront Category page for the provided Category URL.</description> + </annotations> + <arguments> + <argument name="categoryUrl" type="string"/> + </arguments> + <amOnPage url="{{StorefrontCategoryPage.url(categoryUrl)}}" stepKey="goToStorefrontCategoryPage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageSelectDropDownOptionValueActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageSelectDropDownOptionValueActionGroup.xml index 31b18e1f0d37e..9cb3f3faf2f33 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageSelectDropDownOptionValueActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageSelectDropDownOptionValueActionGroup.xml @@ -18,5 +18,6 @@ </arguments> <selectOption selector="{{StorefrontProductInfoMainSection.productOptionSelect(attributeLabel)}}" userInput="{{optionLabel}}" stepKey="fillDropDownAttributeOption"/> + <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductImagesSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductImagesSection.xml index c2de91aadbc0c..0d26c43d2c34b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductImagesSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductImagesSection.xml @@ -13,6 +13,7 @@ <element name="imageFileUpload" type="input" selector="#fileupload"/> <element name="imageUploadButton" type="button" selector="div.image div.fileinput-button"/> <element name="imageFile" type="text" selector="//*[@id='media_gallery_content']//img[contains(@src, '{{url}}')]" parameterized="true"/> + <element name="imageElement" type="text" selector="#media_gallery_content img"/> <element name="removeImageButton" type="button" selector=".action-remove"/> <element name="removeImageButtonForExactImage" type="button" selector="[id='media_gallery_content'] img[src*='{{imageName}}'] + div[class='actions'] button[class='action-remove']" parameterized="true"/> <element name="modalOkBtn" type="button" selector="button.action-primary.action-accept"/> diff --git a/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminClickCheckDataImportActionGroup.xml b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminClickCheckDataImportActionGroup.xml new file mode 100644 index 0000000000000..4b072e0c60a31 --- /dev/null +++ b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminClickCheckDataImportActionGroup.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="AdminClickCheckDataImportActionGroup"> + <annotations> + <description>Clicks the 'Check Data' button on the Admin Import page.</description> + </annotations> + <waitForElementVisible selector="{{AdminImportHeaderSection.checkDataButton}}" stepKey="waitForCheckDataButton"/> + <click selector="{{AdminImportHeaderSection.checkDataButton}}" stepKey="clickCheckDataButton"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminClickImportActionGroup.xml b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminClickImportActionGroup.xml new file mode 100644 index 0000000000000..2e64c35d8c822 --- /dev/null +++ b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminClickImportActionGroup.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="AdminClickImportActionGroup"> + <annotations> + <description>Clicks the 'Import' button on the Admin Import page.</description> + </annotations> + <waitForElementVisible selector="{{AdminImportMainSection.importButton}}" stepKey="waitForImportButton"/> + <click selector="{{AdminImportMainSection.importButton}}" stepKey="clickImportButton"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <waitForElementVisible selector="{{AdminImportValidationMessagesSection.notice}}" stepKey="waitForNoticeMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminFillImportFormActionGroup.xml b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminFillImportFormActionGroup.xml new file mode 100644 index 0000000000000..a15c58b4d2b2e --- /dev/null +++ b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminFillImportFormActionGroup.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"> + <actionGroup name="AdminFillImportFormActionGroup"> + <annotations> + <description>Fills the form on the System > Data Transfer > Import page.</description> + </annotations> + <arguments> + <argument name="entityType" defaultValue="Products" type="string"/> + <argument name="importBehavior" defaultValue="Add/Update" type="string"/> + <argument name="validationStrategy" defaultValue="Stop on Error" type="string" /> + <argument name="allowedErrorsCount" defaultValue="10" type="string" /> + <argument name="importFile" type="string"/> + </arguments> + <waitForElementVisible selector="{{AdminImportMainSection.entityType}}" stepKey="waitForEntityType"/> + <selectOption selector="{{AdminImportMainSection.entityType}}" userInput="{{entityType}}" stepKey="selectEntityType"/> + <waitForElementVisible selector="{{AdminImportMainSection.importBehavior}}" stepKey="waitForImportBehavior"/> + <selectOption selector="{{AdminImportMainSection.importBehavior}}" userInput="{{importBehavior}}" stepKey="selectImportBehaviorOption"/> + <selectOption selector="{{AdminImportMainSection.validationStrategy}}" userInput="{{validationStrategy}}" stepKey="selectValidationStrategyOption"/> + <fillField selector="{{AdminImportMainSection.allowedErrorsCount}}" userInput="{{allowedErrorsCount}}" stepKey="fillAllowedErrorsCountField"/> + <attachFile selector="{{AdminImportMainSection.selectFileToImport}}" userInput="{{importFile}}" stepKey="attachFileForImport"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminNavigateToImportPageActionGroup.xml b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminNavigateToImportPageActionGroup.xml new file mode 100644 index 0000000000000..03c2fea998991 --- /dev/null +++ b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminNavigateToImportPageActionGroup.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="AdminNavigateToImportPageActionGroup"> + <annotations> + <description>Navigates to the admin System > Data Transfer > Import page.</description> + </annotations> + <amOnPage url="{{AdminImportIndexPage.url}}" stepKey="navigateToImportPage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ImportExport/Test/Mftf/Data/ImportData.xml b/app/code/Magento/ImportExport/Test/Mftf/Data/ImportData.xml new file mode 100644 index 0000000000000..6160a12223552 --- /dev/null +++ b/app/code/Magento/ImportExport/Test/Mftf/Data/ImportData.xml @@ -0,0 +1,98 @@ +<?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"> + <!-- Categories --> + <entity name="Import1" type="category"> + <data key="name">Import1</data> + <data key="name_lwr">import1</data> + <data key="is_active">true</data> + <data key="include_in_menu">true</data> + </entity> + + <!-- Products --> + <entity name="ImportSimple1" type="product"> + <data key="name">import-simple1</data> + <data key="sku">import-simple1</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="price">12.00</data> + <data key="visibility">4</data> + <data key="status">1</data> + <data key="quantity">100</data> + <data key="urlKey">import-simple1</data> + <data key="weight">12</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> + <entity name="ImportSimple2" type="product"> + <data key="name">import-simple2</data> + <data key="sku">import-simple2</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="price">15.00</data> + <data key="visibility">4</data> + <data key="status">1</data> + <data key="quantity">100</data> + <data key="urlKey">import-simple2</data> + <data key="weight">12</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> + <entity name="ImportSimple3" type="product"> + <data key="name">import-simple3</data> + <data key="sku">import-simple3</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="price">10.00</data> + <data key="visibility">4</data> + <data key="status">1</data> + <data key="quantity">100</data> + <data key="urlKey">import-simple3</data> + <data key="weight">12</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> + <entity name="ImportConfigurable" type="product"> + <data key="name">import-configurable</data> + <data key="sku">import-configurable</data> + <data key="type_id">configurable</data> + <data key="attribute_set_id">4</data> + <data key="price"/> + <data key="visibility">4</data> + <data key="status">1</data> + <data key="quantity"/> + <data key="urlKey">import-configurable</data> + <data key="weight">12</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> + + <!-- Product Attributes --> + <entity name="ProductAttributeFrontendLabelImport1" type="FrontendLabel"> + <data key="store_id">0</data> + <data key="label">import_attribute1</data> + </entity> + <entity name="ProductAttributeWithThreeOptionsForImport" extends="productAttributeDropdownTwoOptions" type="ProductAttribute"> + <data key="attribute_code">import_attribute1</data> + <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabelImport1</requiredEntity> + </entity> + <entity name="ProductAttributeOptionThreeForImport" extends="productAttributeOption3" type="ProductAttributeOption"> + <data key="label">option3</data> + </entity> + + <!-- Images --> + <entity name="TestImageImageContentExportImport" extends="TestImageContent" type="ImageContent"> + <data key="name">test_image.jpg</data> + </entity> + <entity name="ApiProductAttributeMediaGalleryForExportImport2" extends="ApiProductAttributeMediaGalleryEntryTestImage" type="ProductAttributeMediaGalleryEntry"> + <data key="label">Test Image</data> + <requiredEntity type="ImageContent">TestImageImageContentExportImport</requiredEntity> + </entity> +</entities> diff --git a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml new file mode 100644 index 0000000000000..8d19407d05c55 --- /dev/null +++ b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml @@ -0,0 +1,193 @@ +<?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="AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest"> + <annotations> + <features value="Import/Export"/> + <stories value="Import Products"/> + <title value="Import Configurable Product With Simple Child Products With Images"/> + <description value="Imports a .csv file containing a configurable product with 3 child simple products that + have images. Verifies that products are imported successfully and that the images are attached to the + products as expected."/> + <severity value="MAJOR"/> + <testCaseId value="MC-38222"/> + <group value="importExport"/> + </annotations> + + <before> + <!-- Create Product Attribute with 3 Options --> + <createData entity="ProductAttributeWithThreeOptionsForImport" stepKey="createImportProductAttribute"/> + <createData entity="ProductAttributeOptionOneForExportImport" stepKey="createImportProductAttributeOption1"> + <requiredEntity createDataKey="createImportProductAttribute"/> + </createData> + <createData entity="ProductAttributeOptionTwoForExportImport" stepKey="createImportProductAttributeOption2"> + <requiredEntity createDataKey="createImportProductAttribute"/> + </createData> + <createData entity="ProductAttributeOptionThreeForImport" stepKey="createImportProductAttributeOption3"> + <requiredEntity createDataKey="createImportProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="addToProductAttributeSet"> + <requiredEntity createDataKey="createImportProductAttribute"/> + </createData> + + <!-- Create a Product & Attach a JPG & PNG --> + <createData entity="Import1" stepKey="createImportCategory"/> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="ApiSimpleProduct" stepKey="productForImages"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryForExportImport" stepKey="productImage1"> + <requiredEntity createDataKey="productForImages"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryForExportImport2" stepKey="productImage2"> + <requiredEntity createDataKey="productForImages"/> + </createData> + + <!-- Login as Admin --> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + + <after> + <!-- Delete Data --> + <deleteData createDataKey="createImportCategory" stepKey="deleteImportCategory"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="productForImages" stepKey="deleteProductForImages"/> + <deleteData url="/V1/products/{{ImportSimple1.urlKey}}" stepKey="deleteImportedSimpleProduct1"/> + <deleteData url="/V1/products/{{ImportSimple2.urlKey}}" stepKey="deleteImportedSimpleProduct2"/> + <deleteData url="/V1/products/{{ImportSimple3.urlKey}}" stepKey="deleteImportedSimpleProduct3"/> + <deleteData url="/V1/products/{{ImportConfigurable.urlKey}}" stepKey="deleteImportedConfigurableProduct"/> + <deleteData createDataKey="createImportProductAttribute" stepKey="deleteProductAttribute"/> + <actionGroup ref="NavigateToAndResetProductGridToDefaultViewActionGroup" stepKey="navigateToAndResetProductGridToDefaultView"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> + </after> + + <!-- Import Configurable Product with Simple Child Products & Assert No Errors --> + <actionGroup ref="AdminNavigateToImportPageActionGroup" stepKey="navigateToImportPage"/> + <actionGroup ref="AdminFillImportFormActionGroup" stepKey="fillImportForm"> + <argument name="importFile" value="configurable_and_simple_child_products.csv"/> + </actionGroup> + <actionGroup ref="AdminClickCheckDataImportActionGroup" stepKey="clickCheckData"/> + <see selector="{{AdminImportValidationMessagesSection.success}}" userInput="File is valid! To start import process press "Import" button" stepKey="seeCheckDataResultMessage"/> + <dontSeeElementInDOM selector="{{AdminImportValidationMessagesSection.importErrorList}}" stepKey="dontSeeErrorMessage"/> + <actionGroup ref="AdminClickImportActionGroup" stepKey="clickImport"/> + <see selector="{{AdminImportValidationMessagesSection.notice}}" userInput="Created: 4, Updated: 0, Deleted: 0" stepKey="seeNoticeMessage"/> + <see selector="{{AdminImportValidationMessagesSection.messageByType('success')}}" userInput="Import successfully done" stepKey="seeImportMessage"/> + <dontSeeElementInDOM selector="{{AdminImportValidationMessagesSection.importErrorList}}" stepKey="dontSeeErrorMessage2"/> + + <!-- Admin: Verify Simple Product 1 on Product Index Page --> + <actionGroup ref="AssertProductOnAdminGridActionGroup" stepKey="assertSimpleProduct1InAdminGrid"> + <argument name="product" value="ImportSimple1"/> + </actionGroup> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" userInput="1" stepKey="seeOnly1Product"/> + + <!-- Admin: Verify Simple Product 1 on Edit Product Page --> + <actionGroup ref="AssertProductInfoOnEditPageActionGroup" stepKey="assertSimpleProduct1OnEditPage"> + <argument name="product" value="ImportSimple1"/> + </actionGroup> + <actionGroup ref="AssertProductImageAdminProductPageActionGroup" stepKey="assertProduct1ImageOnEditPage"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + + <!-- Admin: Verify Simple Product 2 on Product Index Page --> + <actionGroup ref="AssertProductOnAdminGridActionGroup" stepKey="assertSimpleProduct2InAdminGrid"> + <argument name="product" value="ImportSimple2"/> + </actionGroup> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" userInput="1" stepKey="seeOnly1Product2"/> + + <!-- Admin: Verify Simple Product 2 on Edit Product Page --> + <actionGroup ref="AssertProductInfoOnEditPageActionGroup" stepKey="assertSimpleProduct2OnEditPage"> + <argument name="product" value="ImportSimple2"/> + </actionGroup> + <actionGroup ref="AssertProductImageAdminProductPageActionGroup" stepKey="assertProduct2ImageOnEditPage"> + <argument name="image" value="TestImage"/> + </actionGroup> + + <!-- Admin: Verify Simple Product 3 on Product Index Page --> + <actionGroup ref="AssertProductOnAdminGridActionGroup" stepKey="assertSimpleProduct3InAdminGrid"> + <argument name="product" value="ImportSimple3"/> + </actionGroup> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" userInput="1" stepKey="seeOnly1Product3"/> + + <!-- Admin: Verify Simple Product 3 on Edit Product Page --> + <actionGroup ref="AssertProductInfoOnEditPageActionGroup" stepKey="assertSimpleProduct3OnEditPage"> + <argument name="product" value="ImportSimple3"/> + </actionGroup> + <actionGroup ref="ExpandAdminProductSectionActionGroup" stepKey="expandImageAndVideosSection"> + <argument name="sectionSelector" value="{{AdminProductImagesSection.productImagesToggle}}"/> + <argument name="sectionDependentSelector" value="{{AdminProductImagesSection.imageUploadButton}}"/> + </actionGroup> + <dontSeeElementInDOM selector="{{AdminProductImagesSection.imageElement}}" stepKey="dontSeeProductImage"/> + + <!-- Admin: Verify Configurable Product on Product Index Page --> + <actionGroup ref="AssertProductOnAdminGridActionGroup" stepKey="assertConfigurableProductInAdminGrid"> + <argument name="product" value="ImportConfigurable"/> + </actionGroup> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" userInput="1" stepKey="seeOnly1Product4"/> + + <!-- Admin: Verify Configurable Product on Edit Product Page --> + <actionGroup ref="AssertProductInfoOnEditPageActionGroup" stepKey="assertConfigurableProductOnEditPage"> + <argument name="product" value="ImportConfigurable"/> + </actionGroup> + <actionGroup ref="ExpandAdminProductSectionActionGroup" stepKey="expandImageAndVideosSection2"> + <argument name="sectionSelector" value="{{AdminProductImagesSection.productImagesToggle}}"/> + <argument name="sectionDependentSelector" value="{{AdminProductImagesSection.imageUploadButton}}"/> + </actionGroup> + <dontSeeElementInDOM selector="{{AdminProductImagesSection.imageElement}}" stepKey="dontSeeProductImage2"/> + + <!-- Storefront: Verify Configurable Product In Category --> + <actionGroup ref="StorefrontNavigateToCategoryUrlActionGroup" stepKey="goToCategoryPage"> + <argument name="categoryUrl" value="{{Import1.name_lwr}}"/> + </actionGroup> + <seeNumberOfElements selector="{{StorefrontCategoryMainSection.productName}}" userInput="1" stepKey="seeOnly1Product5"/> + <see selector="{{StorefrontCategoryMainSection.productName}}" userInput="{{ImportConfigurable.name}}" stepKey="seeConfigurableProduct"/> + <dontSee selector="{{StorefrontCategoryMainSection.productName}}" userInput="{{ImportSimple1.name}}" stepKey="dontSeeSimpleProduct1"/> + <dontSee selector="{{StorefrontCategoryMainSection.productName}}" userInput="{{ImportSimple2.name}}" stepKey="dontSeeSimpleProduct2"/> + <dontSee selector="{{StorefrontCategoryMainSection.productName}}" userInput="{{ImportSimple3.name}}" stepKey="dontSeeSimpleProduct3"/> + + <!-- Storefront: Verify Configurable Product Info & Image --> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductStorefrontPage"> + <argument name="productUrl" value="{{ImportConfigurable.urlKey}}"/> + </actionGroup> + <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="{{ImportConfigurable.name}}" stepKey="seeProductName"/> + <see selector="{{StorefrontProductInfoMainSection.productSku}}" userInput="{{ImportConfigurable.sku}}" stepKey="seeSku"/> + <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="As low as ${{ImportSimple3.price}}" stepKey="seePrice"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productImageSrc('placeholder')}}" stepKey="seePlaceholderImage"/> + + <!-- Storefront: Verify Configurable Product Option 1 Info & Image --> + <actionGroup ref="StorefrontProductPageSelectDropDownOptionValueActionGroup" stepKey="selectOption1"> + <argument name="attributeLabel" value="{{ProductAttributeFrontendLabelImport1.label}}"/> + <argument name="optionLabel" value="{{ProductAttributeOptionOneForExportImport.label}}"/> + </actionGroup> + <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="{{ImportConfigurable.name}}" stepKey="seeProductName2"/> + <see selector="{{StorefrontProductInfoMainSection.productSku}}" userInput="{{ImportConfigurable.sku}}" stepKey="seeSku2"/> + <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="${{ImportSimple1.price}}" stepKey="seePrice2"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productImageSrc(MagentoLogo.filename)}}" stepKey="seeImage1"/> + + <!-- Storefront: Verify Configurable Product Option 2 Info & Image --> + <actionGroup ref="StorefrontProductPageSelectDropDownOptionValueActionGroup" stepKey="selectOption2"> + <argument name="attributeLabel" value="{{ProductAttributeFrontendLabelImport1.label}}"/> + <argument name="optionLabel" value="{{ProductAttributeOptionTwoForExportImport.label}}"/> + </actionGroup> + <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="{{ImportConfigurable.name}}" stepKey="seeProductName3"/> + <see selector="{{StorefrontProductInfoMainSection.productSku}}" userInput="{{ImportConfigurable.sku}}" stepKey="seeSku3"/> + <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="${{ImportSimple2.price}}" stepKey="seePrice3"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productImageSrc(TestImage.filename)}}" stepKey="seeImage2"/> + + <!-- Storefront: Verify Configurable Product Option 3 Info & Image --> + <actionGroup ref="StorefrontProductPageSelectDropDownOptionValueActionGroup" stepKey="selectOption3"> + <argument name="attributeLabel" value="{{ProductAttributeFrontendLabelImport1.label}}"/> + <argument name="optionLabel" value="{{ProductAttributeOptionThreeForImport.label}}"/> + </actionGroup> + <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="{{ImportConfigurable.name}}" stepKey="seeProductName4"/> + <see selector="{{StorefrontProductInfoMainSection.productSku}}" userInput="{{ImportConfigurable.sku}}" stepKey="seeSku4"/> + <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="${{ImportSimple3.price}}" stepKey="seePrice4"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productImageSrc('placeholder')}}" stepKey="seePlaceholderImage2"/> + </test> +</tests> From 476e755752d7348f303b316990b51937568dcd90 Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Wed, 13 Jan 2021 13:40:52 -0600 Subject: [PATCH 09/38] B2B-1640: Add MFTF test for MC-38222 - Adding MFTF S3 import test for MC-38222 --- ...igurableProductsWithAssignedImagesTest.xml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 app/code/Magento/AwsS3/Test/Mftf/Test/AwsS3AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml diff --git a/app/code/Magento/AwsS3/Test/Mftf/Test/AwsS3AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml b/app/code/Magento/AwsS3/Test/Mftf/Test/AwsS3AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml new file mode 100644 index 0000000000000..b8d9f57dc4d2c --- /dev/null +++ b/app/code/Magento/AwsS3/Test/Mftf/Test/AwsS3AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml @@ -0,0 +1,34 @@ +<?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="AwsS3AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest" extends="AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest"> + <annotations> + <features value="AwsS3"/> + <stories value="Import Products"/> + <title value="Import Configurable Product With Simple Child Products With Images"/> + <description value="Imports a .csv file containing a configurable product with 3 child simple products that + have images. Verifies that products are imported successfully and that the images are attached to the + products as expected."/> + <severity value="MAJOR"/> + <group value="importExport"/> + <group value="remote_storage_aws_s3"/> + </annotations> + + <before> + <!-- Enable AWS S3 Remote Storage --> + <magentoCLI command="setup:config:set {{RemoteStorageAwsS3ConfigData.enable_options}}" stepKey="enableRemoteStorage"/> + </before> + + <after> + <!-- Disable AWS S3 Remote Storage --> + <magentoCLI command="setup:config:set {{RemoteStorageAwsS3ConfigData.disable_options}}" stepKey="disableRemoteStorage"/> + </after> + </test> +</tests> From b850e35ff8e97789e725e121ff5d9890375d969c Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Wed, 13 Jan 2021 13:55:05 -0600 Subject: [PATCH 10/38] B2B-1640: Add MFTF test for MC-38222 - Adding csv file for import --- .../tests/_data/configurable_and_simple_child_products.csv | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 dev/tests/acceptance/tests/_data/configurable_and_simple_child_products.csv diff --git a/dev/tests/acceptance/tests/_data/configurable_and_simple_child_products.csv b/dev/tests/acceptance/tests/_data/configurable_and_simple_child_products.csv new file mode 100644 index 0000000000000..6eaf2a2429a74 --- /dev/null +++ b/dev/tests/acceptance/tests/_data/configurable_and_simple_child_products.csv @@ -0,0 +1,5 @@ +sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,deferred_stock_update,use_config_deferred_stock_update,related_skus,related_position,crosssell_skus,crosssell_position,upsell_skus,upsell_position,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,bundle_shipment_type,giftcard_type,giftcard_allow_open_amount,giftcard_open_amount_min,giftcard_open_amount_max,giftcard_amount,use_config_is_redeemable,giftcard_is_redeemable,use_config_lifetime,giftcard_lifetime,use_config_allow_message,giftcard_allow_message,use_config_email_template,giftcard_email_template,associated_skus,downloadable_links,downloadable_samples,configurable_variations,configurable_variation_labels +import-simple1,,Default,simple,Default Category/Import1,base,import-simple1,,,12,1,Taxable Goods,Not Visible Individually,12,,,,import-simple1,Conf11,Conf11,Conf11 ,/m/a/magento-logo.png,Magento Logo,/m/a/magento-logo.png,Magento Logo,/m/a/magento-logo.png,Magento Logo,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,No,,,,,,,,,"import_attribute1=option1,gift_wrapping_available=Yes",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,/m/a/magento-logo.png,Magento Logo,,,,,,,,,,,,,,,,,,,,,,,,,, +import-simple2,,Default,simple,Default Category/Import1,base,import-simple2,,,12,1,Taxable Goods,Not Visible Individually,15,,,,import-simple2,Conf11,Conf11,Conf11 ,/t/e/test_image.jpg,Test Image,/t/e/test_image.jpg,Test Image,/t/e/test_image.jpg,Test Image,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,No,,,,,,,,,"import_attribute1=option2,gift_wrapping_available=Yes",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,/t/e/test_image.jpg,Test Image,,,,,,,,,,,,,,,,,,,,,,,,,, +import-simple3,,Default,simple,Default Category/Import1,base,import-simple3,,,12,1,Taxable Goods,Not Visible Individually,10,,,,import-simple3,Conf11,Conf11,Conf11 ,,,,,,,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,No,,,,,,,,,"import_attribute1=option3,gift_wrapping_available=Yes",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +import-configurable,,Default,configurable,Default Category/Import1,base,import-configurable,,,12,1,Taxable Goods,"Catalog, Search",,,,,import-configurable,Conf11,Conf11,Conf11 ,,,,,,,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,Use config,,,,,,,Use config,,gift_wrapping_available=Use config,0,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,,",,",,,,,,,,,,,,,,,,,,,,,,,,,"sku=import-simple1,import_attribute1=option1|sku=import-simple2,import_attribute1=option2|sku=import-simple3,import_attribute1=option3",import_attribute1=import_attribute1 \ No newline at end of file From 8d203cccaebf0a4dd4c2b6a2fc11a3559d9c693d Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Wed, 13 Jan 2021 20:24:16 -0600 Subject: [PATCH 11/38] B2B-1640: Add MFTF test for MC-38222 - Skipping S3 test --- ...rtSimpleAndConfigurableProductsWithAssignedImagesTest.xml | 5 ++++- ...rtSimpleAndConfigurableProductsWithAssignedImagesTest.xml | 2 +- ...le_child_products.csv => import_configurable_product.csv} | 0 3 files changed, 5 insertions(+), 2 deletions(-) rename dev/tests/acceptance/tests/_data/{configurable_and_simple_child_products.csv => import_configurable_product.csv} (100%) diff --git a/app/code/Magento/AwsS3/Test/Mftf/Test/AwsS3AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml b/app/code/Magento/AwsS3/Test/Mftf/Test/AwsS3AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml index b8d9f57dc4d2c..fe8c6c6f7f9ef 100644 --- a/app/code/Magento/AwsS3/Test/Mftf/Test/AwsS3AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml +++ b/app/code/Magento/AwsS3/Test/Mftf/Test/AwsS3AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml @@ -12,13 +12,16 @@ <annotations> <features value="AwsS3"/> <stories value="Import Products"/> - <title value="Import Configurable Product With Simple Child Products With Images"/> + <title value="S3 - Import Configurable Product With Simple Child Products With Images"/> <description value="Imports a .csv file containing a configurable product with 3 child simple products that have images. Verifies that products are imported successfully and that the images are attached to the products as expected."/> <severity value="MAJOR"/> <group value="importExport"/> <group value="remote_storage_aws_s3"/> + <skip> + <issueId value="MC-39280"/> + </skip> </annotations> <before> diff --git a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml index 8d19407d05c55..93fe8206d69b7 100644 --- a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml +++ b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml @@ -71,7 +71,7 @@ <!-- Import Configurable Product with Simple Child Products & Assert No Errors --> <actionGroup ref="AdminNavigateToImportPageActionGroup" stepKey="navigateToImportPage"/> <actionGroup ref="AdminFillImportFormActionGroup" stepKey="fillImportForm"> - <argument name="importFile" value="configurable_and_simple_child_products.csv"/> + <argument name="importFile" value="import_configurable_product.csv"/> </actionGroup> <actionGroup ref="AdminClickCheckDataImportActionGroup" stepKey="clickCheckData"/> <see selector="{{AdminImportValidationMessagesSection.success}}" userInput="File is valid! To start import process press "Import" button" stepKey="seeCheckDataResultMessage"/> diff --git a/dev/tests/acceptance/tests/_data/configurable_and_simple_child_products.csv b/dev/tests/acceptance/tests/_data/import_configurable_product.csv similarity index 100% rename from dev/tests/acceptance/tests/_data/configurable_and_simple_child_products.csv rename to dev/tests/acceptance/tests/_data/import_configurable_product.csv From bd3c0363b7c01271c8225b98d203de27576a2858 Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi <tsviklinskyi@gmail.com> Date: Thu, 14 Jan 2021 09:47:50 +0200 Subject: [PATCH 12/38] MC-39759: Navigation arrow buttons not visible after video starts on product image --- .../AssertNextButtonHiddenProductVideoActionGroup.xml | 1 - .../AssertPrevButtonHiddenProductVideoActionGroup.xml | 1 - 2 files changed, 2 deletions(-) diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml index d6d756847e0b7..6778ade18b496 100644 --- a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml @@ -14,7 +14,6 @@ <description>Validates that the next button is absent on the Storefront Product page.</description> </annotations> - <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> <dontSeeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="dontSeeNextButton"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml index b5b9e801d3a9c..1a588f4a23f84 100644 --- a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml @@ -14,7 +14,6 @@ <description>Validates that the previous button is absent on the Storefront Product page.</description> </annotations> - <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> <dontSeeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="dontSeePrevButton"/> </actionGroup> </actionGroups> From 8ff8dbe7e35c3549fc55e4673b093364bb2cf4f7 Mon Sep 17 00:00:00 2001 From: rostyslav-hymon <rostyslav.hymon@transoftgroup.com> Date: Thu, 14 Jan 2021 12:04:53 +0200 Subject: [PATCH 13/38] MC-40379: [Magento Cloud] - [vodacom]-Upsell,Cross Sell Products are visible in Graphql Response even those the product is disabled --- .../Products/DataProvider/Product.php | 2 +- .../RelatedProduct/GetRelatedProductsTest.php | 36 ++++++++++ .../products_related_disabled_in_store.php | 70 +++++++++++++++++++ ...cts_related_disabled_in_store_rollback.php | 33 +++++++++ 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/products_related_disabled_in_store.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/products_related_disabled_in_store_rollback.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product.php index 3e955ae303453..30be41072242b 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product.php @@ -89,7 +89,7 @@ public function getList( $this->collectionPreProcessor->process($collection, $searchCriteria, $attributes, $context); - if (!$isChildSearch) { + if ($isChildSearch) { $visibilityIds = $isSearch ? $this->visibility->getVisibleInSearchIds() : $this->visibility->getVisibleInCatalogIds(); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/RelatedProduct/GetRelatedProductsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/RelatedProduct/GetRelatedProductsTest.php index f2cf90c95de18..8575f1d33c435 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/RelatedProduct/GetRelatedProductsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/RelatedProduct/GetRelatedProductsTest.php @@ -190,4 +190,40 @@ private function assertRelatedProducts(array $relatedProducts): void self::assertEquals($product['url_key'], $productExpectedData['url_key']); } } + + /** + * Test query with disabled linked product in the default store + * + * @magentoApiDataFixture Magento/Catalog/_files/products_related_disabled_in_store.php + * + * @return void + */ + public function testQueryDisableRelatedProductInStore(): void + { + $productSku = 'simple_with_related'; + $query = <<<QUERY +{ + products(filter: {sku: {eq: "{$productSku}"}}) + { + items { + related_products + { + sku + name + url_key + } + } + } +} +QUERY; + $response = $this->graphQlQuery($query, [], '', ['Store' => 'default']); + + self::assertArrayHasKey('products', $response); + self::assertArrayHasKey('items', $response['products']); + self::assertCount(1, $response['products']['items']); + self::assertArrayHasKey(0, $response['products']['items']); + self::assertArrayHasKey('related_products', $response['products']['items'][0]); + $relatedProducts = $response['products']['items'][0]['related_products']; + self::assertCount(0, $relatedProducts); + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_related_disabled_in_store.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_related_disabled_in_store.php new file mode 100644 index 0000000000000..b8e6d4702b44f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_related_disabled_in_store.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Catalog\Api\Data\ProductInterfaceFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Eav\Model\Config; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Catalog\Api\Data\ProductLinkInterface; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$baseWebsite = $websiteRepository->get('base'); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +$defaultAttributeSet = $objectManager->get(Config::class)->getEntityType(Product::ENTITY)->getDefaultAttributeSetId(); +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var ProductInterfaceFactory $productInterfaceFactory */ +$productInterfaceFactory = $objectManager->get(ProductInterfaceFactory::class); + +/** @var Product $product */ +$product = $productInterfaceFactory->create(); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId($defaultAttributeSet) + ->setStoreId($storeManager->getDefaultStoreView()->getId()) + ->setWebsiteIds([$baseWebsite->getId()]) + ->setName('Simple Product') + ->setSku('simple') + ->setPrice(10) + ->setWeight(18) + ->setStockData(['use_config_manage_stock' => 0]) + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED); + +$simple = $productRepository->save($product); +$simple->setStoreId($storeManager->getDefaultStoreView()->getId()) +->setStatus(Status::STATUS_DISABLED); +$productRepository->save($simple); +/** @var ProductLinkInterface $productLink */ +$productLink = $objectManager->create(ProductLinkInterface::class); +$productLink->setSku('simple_with_related'); +$productLink->setLinkedProductSku('simple'); +$productLink->setPosition(1); +$productLink->setLinkType('related'); + +/** @var Product $product */ +$product = $productInterfaceFactory->create(); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId($defaultAttributeSet) + ->setStoreId($storeManager->getDefaultStoreView()->getId()) + ->setWebsiteIds([$baseWebsite->getId()]) + ->setName('Simple Product With Related Product') + ->setSku('simple_with_related') + ->setPrice(10) + ->setWeight(18) + ->setProductLinks([$productLink]) + ->setStockData(['use_config_manage_stock' => 0]) + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_related_disabled_in_store_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_related_disabled_in_store_rollback.php new file mode 100644 index 0000000000000..6ca27b71b9057 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_related_disabled_in_store_rollback.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +try { + $firstProduct = $productRepository->get('simple', false, null, true); + $productRepository->delete($firstProduct); +} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + //Product already removed +} + +try { + $secondProduct = $productRepository->get('simple_with_related', false, null, true); + $productRepository->delete($secondProduct); +} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From ef975c5d883dc5ff05a1a5c825773dcae7b06284 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Thu, 14 Jan 2021 14:57:14 +0200 Subject: [PATCH 14/38] MC-40053: Create automated test for: "Update attribute option by API call" --- ...AttributeOptionManagementInterfaceTest.php | 122 +++++++++++++++++- 1 file changed, 120 insertions(+), 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Swatches/Api/ProductAttributeOptionManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Swatches/Api/ProductAttributeOptionManagementInterfaceTest.php index 39ca42b57511e..d1cc52fc52e48 100644 --- a/dev/tests/api-functional/testsuite/Magento/Swatches/Api/ProductAttributeOptionManagementInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Swatches/Api/ProductAttributeOptionManagementInterfaceTest.php @@ -25,6 +25,7 @@ class ProductAttributeOptionManagementInterfaceTest extends WebapiAbstract { private const ATTRIBUTE_CODE = 'select_attribute'; + private const SERVICE_NAME_UPDATE = 'catalogProductAttributeOptionUpdateV1'; private const SERVICE_NAME = 'catalogProductAttributeOptionManagementV1'; private const SERVICE_VERSION = 'V1'; private const RESOURCE_PATH = '/V1/products/attributes'; @@ -47,7 +48,8 @@ public function testAdd( int $expectedSwatchType, string $expectedLabel, string $expectedValue - ) { + ) + { $objectManager = Bootstrap::getObjectManager(); /** @var $attributeRepository AttributeRepository */ $attributeRepository = $objectManager->get(AttributeRepository::class); @@ -74,7 +76,7 @@ public function testAdd( ); $this->assertNotNull($response); - $optionId = (int) ltrim($response, 'id_'); + $optionId = (int)ltrim($response, 'id_'); $swatch = $this->getSwatch($optionId); $this->assertEquals($expectedValue, $swatch->getValue()); $this->assertEquals($expectedSwatchType, $swatch->getType()); @@ -83,6 +85,41 @@ public function testAdd( $this->assertEquals($expectedLabel, $options[2]->getLabel()); } + /** + * @magentoApiDataFixture Magento/Swatches/_files/text_swatch_attribute.php + */ + public function testUpdate() + { + $testAttributeCode = 'test_configurable'; + $optionData = [ + AttributeOptionInterface::LABEL => 'Fixture Option Changed', + AttributeOptionInterface::VALUE => 'option_value', + ]; + + $existOptionLabel = 'option 1'; + $existAttributeOption = $this->getAttributeOption($testAttributeCode, $existOptionLabel); + $optionId = $existAttributeOption['value']; + + $response = $this->webApiCallAttributeOptions( + $testAttributeCode, + Request::HTTP_METHOD_PUT, + 'update', + [ + 'attributeCode' => $testAttributeCode, + 'optionId' => $optionId, + 'option' => $optionData, + ], + $optionId + ); + $this->assertTrue($response); + $this->assertNotNull( + $this->getAttributeOption( + $testAttributeCode, + $optionData[AttributeOptionLabelInterface::LABEL] + ) + ); + } + /** * @return array * @SuppressWarnings(PHPMD.ExcessiveMethodLength) @@ -222,4 +259,85 @@ private function getSwatch(int $optionId) $collection->setPageSize(1); return $collection->getFirstItem(); } + + /** + * Perform Web API call to the system under test + * + * @param string $attributeCode + * @param string $httpMethod + * @param string $soapMethod + * @param array $arguments + * @param null $storeCode + * @param null $optionId + * @return array|bool|float|int|string + */ + private function webApiCallAttributeOptions( + string $attributeCode, + string $httpMethod, + string $soapMethod, + array $arguments = [], + $optionId = null, + $storeCode = null + ) { + $resourcePath = self::RESOURCE_PATH . "/{$attributeCode}/options"; + if ($optionId) { + $resourcePath .= '/' . $optionId; + } + $serviceName = $soapMethod === 'update' ? self::SERVICE_NAME_UPDATE : self::SERVICE_NAME; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $resourcePath, + 'httpMethod' => $httpMethod, + ], + 'soap' => [ + 'service' => $serviceName, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => $serviceName . $soapMethod, + ], + ]; + + return $this->_webApiCall($serviceInfo, $arguments, null, $storeCode); + } + + /** + * @param string $testAttributeCode + * @param string|null $storeCode + * @return array|bool|float|int|string + */ + private function getAttributeOptions(string $testAttributeCode, ?string $storeCode = null) + { + return $this->webApiCallAttributeOptions( + $testAttributeCode, + Request::HTTP_METHOD_GET, + 'getItems', + ['attributeCode' => $testAttributeCode], + null, + $storeCode + ); + } + + /** + * @param string $attributeCode + * @param string $optionLabel + * @param string|null $storeCode + * @return array|null + */ + private function getAttributeOption( + string $attributeCode, + string $optionLabel, + ?string $storeCode = null + ): ?array + { + $attributeOptions = $this->getAttributeOptions($attributeCode, $storeCode); + $option = null; + /** @var array $attributeOption */ + foreach ($attributeOptions as $attributeOption) { + if ($attributeOption['label'] === $optionLabel) { + $option = $attributeOption; + break; + } + } + + return $option; + } } From b208c0b31acdd776c4d576778be2499b617c2260 Mon Sep 17 00:00:00 2001 From: rostyslav-hymon <rostyslav.hymon@transoftgroup.com> Date: Thu, 14 Jan 2021 14:59:41 +0200 Subject: [PATCH 15/38] MC-40379: [Magento Cloud] - [vodacom]-Upsell,Cross Sell Products are visible in Graphql Response even those the product is disabled --- .../Model/Resolver/Products/DataProvider/Deferred/Product.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Deferred/Product.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Deferred/Product.php index 22bbc991a78e2..8218c22b8056d 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Deferred/Product.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Deferred/Product.php @@ -132,7 +132,7 @@ private function fetch() : array $this->searchCriteriaBuilder->create(), $this->attributeCodes, false, - true + false ); /** @var \Magento\Catalog\Model\Product $product */ From 4099fef3d1981815d5b976c5c07411e36e200dee Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Thu, 14 Jan 2021 08:15:18 -0600 Subject: [PATCH 16/38] B2B-1640: Add MFTF test for MC-38222 - Adding reindex to test --- ...tSimpleAndConfigurableProductsWithAssignedImagesTest.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml index 93fe8206d69b7..bc496a06e52cb 100644 --- a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml +++ b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml @@ -81,6 +81,12 @@ <see selector="{{AdminImportValidationMessagesSection.messageByType('success')}}" userInput="Import successfully done" stepKey="seeImportMessage"/> <dontSeeElementInDOM selector="{{AdminImportValidationMessagesSection.importErrorList}}" stepKey="dontSeeErrorMessage2"/> + <!-- Reindex --> + <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> + <argument name="indices" value=""/> + </actionGroup> + <pause stepKey="pause"/> + <!-- Admin: Verify Simple Product 1 on Product Index Page --> <actionGroup ref="AssertProductOnAdminGridActionGroup" stepKey="assertSimpleProduct1InAdminGrid"> <argument name="product" value="ImportSimple1"/> From 02163a683dbe5602c2a04fcdb8628ec5240e01ea Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Thu, 14 Jan 2021 08:16:11 -0600 Subject: [PATCH 17/38] B2B-1640: Add MFTF test for MC-38222 - Remove pause --- ...ImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml index bc496a06e52cb..df7c671d6a5b6 100644 --- a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml +++ b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml @@ -85,7 +85,6 @@ <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> <argument name="indices" value=""/> </actionGroup> - <pause stepKey="pause"/> <!-- Admin: Verify Simple Product 1 on Product Index Page --> <actionGroup ref="AssertProductOnAdminGridActionGroup" stepKey="assertSimpleProduct1InAdminGrid"> From 2a8f5a6324fb601abdbe46def6b1d85bbe8f7cb6 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Thu, 14 Jan 2021 18:17:32 +0200 Subject: [PATCH 18/38] MC-40053: Create automated test for: "Update attribute option by API call" --- ...AttributeOptionManagementInterfaceTest.php | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Swatches/Api/ProductAttributeOptionManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Swatches/Api/ProductAttributeOptionManagementInterfaceTest.php index d1cc52fc52e48..f4eeb12170f4a 100644 --- a/dev/tests/api-functional/testsuite/Magento/Swatches/Api/ProductAttributeOptionManagementInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Swatches/Api/ProductAttributeOptionManagementInterfaceTest.php @@ -12,6 +12,7 @@ use Magento\Eav\Api\Data\AttributeOptionInterface; use Magento\Eav\Api\Data\AttributeOptionLabelInterface; use Magento\Eav\Model\AttributeRepository; +use Magento\Framework\DataObject; use Magento\Framework\Webapi\Rest\Request; use Magento\Swatches\Model\ResourceModel\Swatch\Collection; use Magento\Swatches\Model\ResourceModel\Swatch\CollectionFactory; @@ -33,6 +34,7 @@ class ProductAttributeOptionManagementInterfaceTest extends WebapiAbstract /** * Test add option to swatch attribute * + * @dataProvider addDataProvider * @magentoApiDataFixture Magento/Catalog/Model/Product/Attribute/_files/select_attribute.php * @param array $data * @param array $payload @@ -40,7 +42,7 @@ class ProductAttributeOptionManagementInterfaceTest extends WebapiAbstract * @param string $expectedLabel * @param string $expectedValue * - * @dataProvider addDataProvider + * @return void */ public function testAdd( array $data, @@ -48,8 +50,7 @@ public function testAdd( int $expectedSwatchType, string $expectedLabel, string $expectedValue - ) - { + ): void { $objectManager = Bootstrap::getObjectManager(); /** @var $attributeRepository AttributeRepository */ $attributeRepository = $objectManager->get(AttributeRepository::class); @@ -87,8 +88,9 @@ public function testAdd( /** * @magentoApiDataFixture Magento/Swatches/_files/text_swatch_attribute.php + * @return void */ - public function testUpdate() + public function testUpdate(): void { $testAttributeCode = 'test_configurable'; $optionData = [ @@ -115,7 +117,7 @@ public function testUpdate() $this->assertNotNull( $this->getAttributeOption( $testAttributeCode, - $optionData[AttributeOptionLabelInterface::LABEL] + $optionData[AttributeOptionInterface::LABEL] ) ); } @@ -124,7 +126,7 @@ public function testUpdate() * @return array * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function addDataProvider() + public function addDataProvider(): array { return [ 'visual swatch option with value' => [ @@ -249,14 +251,15 @@ public function addDataProvider() * Get swatch model * * @param int $optionId - * @return Swatch + * @return DataObject */ - private function getSwatch(int $optionId) + private function getSwatch(int $optionId): DataObject { /** @var Collection $collection */ $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class)->create(); $collection->addFieldToFilter('option_id', $optionId); $collection->setPageSize(1); + return $collection->getFirstItem(); } @@ -300,6 +303,8 @@ private function webApiCallAttributeOptions( } /** + * Get Attribute options by attribute code + * * @param string $testAttributeCode * @param string|null $storeCode * @return array|bool|float|int|string @@ -317,6 +322,8 @@ private function getAttributeOptions(string $testAttributeCode, ?string $storeCo } /** + * Get Attribute option by attribute code + * * @param string $attributeCode * @param string $optionLabel * @param string|null $storeCode @@ -326,8 +333,7 @@ private function getAttributeOption( string $attributeCode, string $optionLabel, ?string $storeCode = null - ): ?array - { + ): ?array { $attributeOptions = $this->getAttributeOptions($attributeCode, $storeCode); $option = null; /** @var array $attributeOption */ From eb96baf57060027ebef5e2df2ae10aa29ab1805f Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi <tsviklinskyi@gmail.com> Date: Fri, 15 Jan 2021 08:43:15 +0200 Subject: [PATCH 19/38] MC-39759: Navigation arrow buttons not visible after video starts on product image --- lib/web/mage/gallery/gallery.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web/mage/gallery/gallery.less b/lib/web/mage/gallery/gallery.less index d6926720d7984..86ccdb858bf19 100644 --- a/lib/web/mage/gallery/gallery.less +++ b/lib/web/mage/gallery/gallery.less @@ -964,7 +964,7 @@ height: @fotorama_close_button; opacity: 0; right: 0; - top: 10%; + top: 0; transform: translate3d((@fotorama_close_button), (-@fotorama_close_button), 0); transition: opacity 0.3s ease-in-out; width: @fotorama_close_button; From 1b2187218fcfea7b52d283fe80a83ba607479613 Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi <tsviklinskyi@gmail.com> Date: Fri, 15 Jan 2021 12:58:13 +0200 Subject: [PATCH 20/38] MC-39759: Navigation arrow buttons not visible after video starts on product image --- ...oseButtonHiddenProductVideoActionGroup.xml | 19 --------- ...extButtonHiddenProductVideoActionGroup.xml | 19 --------- ...revButtonHiddenProductVideoActionGroup.xml | 19 --------- ...roductVideoNavigationArrowsActionGroup.xml | 42 +++++++++++++++++++ ...lickCloseButtonProductVideoActionGroup.xml | 21 ---------- ...ClickNextButtonProductVideoActionGroup.xml | 21 ---------- ...ClickPlayButtonProductVideoActionGroup.xml | 20 --------- ...ClickPrevButtonProductVideoActionGroup.xml | 21 ---------- ...eoVideoControlButtonsOnProductPageTest.xml | 22 +--------- 9 files changed, 44 insertions(+), 160 deletions(-) delete mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertCloseButtonHiddenProductVideoActionGroup.xml delete mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml delete mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertProductVideoNavigationArrowsActionGroup.xml delete mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickCloseButtonProductVideoActionGroup.xml delete mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickNextButtonProductVideoActionGroup.xml delete mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPlayButtonProductVideoActionGroup.xml delete mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPrevButtonProductVideoActionGroup.xml diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertCloseButtonHiddenProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertCloseButtonHiddenProductVideoActionGroup.xml deleted file mode 100644 index edd837db6c31c..0000000000000 --- a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertCloseButtonHiddenProductVideoActionGroup.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?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 that close button is hidden on Storefront Product page --> - <actionGroup name="AssertCloseButtonHiddenProductVideoActionGroup"> - <annotations> - <description>Validates that the close button is absent on the Storefront Product page.</description> - </annotations> - - <dontSeeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="dontSeeCloseVideo"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml deleted file mode 100644 index 6778ade18b496..0000000000000 --- a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertNextButtonHiddenProductVideoActionGroup.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?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 that next button is hidden on Storefront Product page --> - <actionGroup name="AssertNextButtonHiddenProductVideoActionGroup"> - <annotations> - <description>Validates that the next button is absent on the Storefront Product page.</description> - </annotations> - - <dontSeeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="dontSeeNextButton"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml deleted file mode 100644 index 1a588f4a23f84..0000000000000 --- a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertPrevButtonHiddenProductVideoActionGroup.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?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 that previous button is hidden on Storefront Product page --> - <actionGroup name="AssertPrevButtonHiddenProductVideoActionGroup"> - <annotations> - <description>Validates that the previous button is absent on the Storefront Product page.</description> - </annotations> - - <dontSeeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="dontSeePrevButton"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertProductVideoNavigationArrowsActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertProductVideoNavigationArrowsActionGroup.xml new file mode 100644 index 0000000000000..d0673dfc1adb7 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AssertProductVideoNavigationArrowsActionGroup.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"> + <!-- Assert the navigation arrows on Storefront Product page --> + <actionGroup name="AssertProductVideoNavigationArrowsActionGroup"> + <annotations> + <description>Validates the navigation arrows on the Storefront Product page.</description> + </annotations> + <arguments> + <argument name="videoType" type="string" defaultValue="vimeo"/> + </arguments> + + <dontSeeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="dontSeePrevButton"/> + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> + <seeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="seeNextButton"/> + <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickNextButton"/> + <seeElement selector="{{StorefrontProductInfoMainSection.productVideo(videoType)}}" stepKey="seeProductVideoDataType"/> + + <dontSeeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="dontSeeCloseVideo"/> + + <click selector="{{StorefrontProductInfoMainSection.clickPlayVideo}}" stepKey="clickToPlayVideo"/> + <wait stepKey="waitFiveSecondsToPlayVideo" time="5"/> + + <dontSeeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="dontSeePrevButtonSecond"/> + <dontSeeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="dontSeeNextButton"/> + + <seeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="seeCloseVideo"/> + <click selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="clickToCloseVideo"/> + <wait stepKey="waitTwoSecondsToCloseVideo" time="2"/> + + <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImageSecond"/> + <seeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="seePrevButton"/> + <click selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="clickPrevButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickCloseButtonProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickCloseButtonProductVideoActionGroup.xml deleted file mode 100644 index a18e98eebb48c..0000000000000 --- a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickCloseButtonProductVideoActionGroup.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?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"> - <!-- Click close button in product video on Storefront Product page --> - <actionGroup name="ClickCloseButtonProductVideoActionGroup"> - <annotations> - <description>Click close button in product video on the Storefront Product page.</description> - </annotations> - - <seeElement selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}" stepKey="seeCloseVideo"/> - <click stepKey="clickCloseVideo" selector="{{StorefrontProductInfoMainSection.clickCloseVideo}}"/> - <wait stepKey="waitTwoSecondsToCloseVideo" time="2"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickNextButtonProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickNextButtonProductVideoActionGroup.xml deleted file mode 100644 index eb7c94514fa24..0000000000000 --- a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickNextButtonProductVideoActionGroup.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?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"> - <!-- Click next button in product video on Storefront Product page --> - <actionGroup name="ClickNextButtonProductVideoActionGroup"> - <annotations> - <description>Click next button in product video on the Storefront Product page.</description> - </annotations> - - <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> - <seeElement selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="seeNextButton"/> - <click selector="{{StorefrontProductMediaSection.imageNextButton}}" stepKey="clickNextButton"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPlayButtonProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPlayButtonProductVideoActionGroup.xml deleted file mode 100644 index 481097b488be8..0000000000000 --- a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPlayButtonProductVideoActionGroup.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?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"> - <!-- Click play button in product video on Storefront Product page --> - <actionGroup name="ClickPlayButtonProductVideoActionGroup"> - <annotations> - <description>Click play button in product video on the Storefront Product page.</description> - </annotations> - - <click selector="{{StorefrontProductInfoMainSection.clickPlayVideo}}" stepKey="clickToPlayVideo"/> - <wait stepKey="waitFiveSecondsToPlayVideo" time="5"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPrevButtonProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPrevButtonProductVideoActionGroup.xml deleted file mode 100644 index aa32812997624..0000000000000 --- a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/ClickPrevButtonProductVideoActionGroup.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?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"> - <!-- Click previous button in product video on Storefront Product page --> - <actionGroup name="ClickPrevButtonProductVideoActionGroup"> - <annotations> - <description>Click previous button in product video on the Storefront Product page.</description> - </annotations> - - <moveMouseOver selector="{{StorefrontProductMediaSection.mainImageForJsActions}}" stepKey="hoverOverImage"/> - <seeElement selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="seePrevButton"/> - <click selector="{{StorefrontProductMediaSection.imagePrevButton}}" stepKey="clickPrevButton"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml b/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml index a4719fa281f29..a60a5526498ce 100644 --- a/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml +++ b/app/code/Magento/ProductVideo/Test/Mftf/Test/VimeoVideoControlButtonsOnProductPageTest.xml @@ -50,27 +50,9 @@ <argument name="productUrl" value="$createProduct.custom_attributes[url_key]$"/> </actionGroup> - <!-- Click next button --> - <actionGroup ref="AssertPrevButtonHiddenProductVideoActionGroup" stepKey="assertPrevButtonIsHidden"/> - <actionGroup ref="ClickNextButtonProductVideoActionGroup" stepKey="clickNextNavigationButton"/> - - <!-- Assert product video present in the storefront product page --> - <actionGroup ref="AssertProductVideoStorefrontProductPageActionGroup" stepKey="assertProductVideoPresentInStorefrontProductPage"> + <!-- Check the navigation arrows on Storefront Product page --> + <actionGroup ref="AssertProductVideoNavigationArrowsActionGroup" stepKey="assertProductVideoNavigationArrowsOnStorefrontProductPage"> <argument name="videoType" value="vimeo"/> </actionGroup> - <actionGroup ref="AssertCloseButtonHiddenProductVideoActionGroup" stepKey="assertCloseVideoButtonIsHidden"/> - - <!-- Click Play video button --> - <actionGroup ref="ClickPlayButtonProductVideoActionGroup" stepKey="clickPlayVideoButton"/> - - <!-- Assert product navigation arrows --> - <actionGroup ref="AssertPrevButtonHiddenProductVideoActionGroup" stepKey="assertPrevButtonIsHidden2"/> - <actionGroup ref="AssertNextButtonHiddenProductVideoActionGroup" stepKey="assertNextButtonIsHidden"/> - - <!-- Click Close video button --> - <actionGroup ref="ClickCloseButtonProductVideoActionGroup" stepKey="clickCloseVideoButton"/> - - <!-- Click previous button --> - <actionGroup ref="ClickPrevButtonProductVideoActionGroup" stepKey="clickPrevNavigationButton"/> </test> </tests> From bf2207aa47c53f2b63d0dea74bdf93c20e4a7d0b Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Mon, 18 Jan 2021 11:39:39 +0200 Subject: [PATCH 21/38] MC-40059: Create automated test for: "Subscribe to price alert" --- .../Edit/Tab/Alerts/AbstractAlertTest.php | 91 +++++++++++++++++ .../Product/Edit/Tab/Alerts/PriceTest.php | 99 +++++++++++++++++++ .../Product/Edit/Tab/Alerts/StockTest.php | 50 ++++++---- .../Adminhtml/Product/AbstractAlertTest.php | 76 ++++++++++++++ .../Adminhtml/Product/AlertsPriceGridTest.php | 63 ++++++++++++ .../Adminhtml/Product/AlertsStockGridTest.php | 63 ++++++++++++ .../Product/Form/Modifier/AlertsTest.php | 10 +- .../_files/price_alert_on_second_website.php | 66 +++++++++++++ ...price_alert_on_second_website_rollback.php | 53 ++++++++++ .../_files/product_alert_rollback.php | 6 ++ .../_files/simple_product_with_two_alerts.php | 59 +++++++++++ ...imple_product_with_two_alerts_rollback.php | 39 ++++++++ 12 files changed, 652 insertions(+), 23 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/AbstractAlertTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/PriceTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AbstractAlertTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AlertsPriceGridTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AlertsStockGridTest.php create mode 100644 dev/tests/integration/testsuite/Magento/ProductAlert/_files/price_alert_on_second_website.php create mode 100644 dev/tests/integration/testsuite/Magento/ProductAlert/_files/price_alert_on_second_website_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/ProductAlert/_files/simple_product_with_two_alerts.php create mode 100644 dev/tests/integration/testsuite/Magento/ProductAlert/_files/simple_product_with_two_alerts_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/AbstractAlertTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/AbstractAlertTest.php new file mode 100644 index 0000000000000..8ac709c584648 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/AbstractAlertTest.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Alerts; + +use Magento\Catalog\Model\ResourceModel\Product as ProductResource; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Module\Manager; +use Magento\Framework\ObjectManagerInterface; +use Magento\Store\Model\Store; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Base alert's tab test logic + */ +abstract class AbstractAlertTest extends TestCase +{ + /** @var ObjectManagerInterface */ + protected $objectManager; + + /** @var RequestInterface */ + protected $request; + + /** @var StoreManagerInterface */ + private $storeManager; + + /** @var ProductResource */ + private $productResource; + + /** + * @inheritdoc + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + $objectManager = Bootstrap::getObjectManager(); + /** @var Manager $moduleManager */ + $moduleManager = $objectManager->get(Manager::class); + //This check is needed because module Magento_Catalog is independent of Magento_ProductAlert + if (!$moduleManager->isEnabled('Magento_ProductAlert')) { + self::markTestSkipped('Magento_ProductAlert module disabled.'); + } + } + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + $this->request = $this->objectManager->get(RequestInterface::class); + $this->productResource = $this->objectManager->get(ProductResource::class); + } + + /** + * Prepare request + * + * @param string|null $sku + * @param string|null $storeCode + * @return void + */ + protected function prepareRequest(?string $sku = null, ?string $storeCode = null): void + { + $productId = (int)$this->productResource->getIdBySku($sku); + $storeId = $storeCode ? (int)$this->storeManager->getStore($storeCode)->getId() : null; + $this->request->setParams(['id' => $productId, 'store' => $storeId]); + } + + /** + * Assert grid url + * + * @param string $url + * @param string|null $storeCode + * @return void + */ + protected function assertGridUrl(string $url, ?string $storeCode): void + { + $storeId = $storeCode ? (int)$this->storeManager->getStore($storeCode)->getId() : Store::DEFAULT_STORE_ID; + $this->assertStringContainsString(sprintf('/store/%s', $storeId), $url); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/PriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/PriceTest.php new file mode 100644 index 0000000000000..38f03a4558507 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/PriceTest.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Alerts; + +use Magento\Framework\View\LayoutInterface; + +/** + * Check price alert grid + * + * @see \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Alerts\Price + * + * @magentoAppArea adminhtml + */ +class PriceTest extends AbstractAlertTest +{ + /** @var Price */ + private $block; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->block = $this->objectManager->get(LayoutInterface::class)->createBlock(Price::class); + } + + /** + * @dataProvider alertsDataProvider + * + * @magentoDbIsolation disabled + * + * @magentoDataFixture Magento/ProductAlert/_files/product_alert.php + * @magentoDataFixture Magento/ProductAlert/_files/price_alert_on_second_website.php + * + * @param string $sku + * @param string $expectedEmail + * @param string|null $storeCode + * @return void + */ + public function testGridCollectionWithStoreId(string $sku, string $expectedEmail, ?string $storeCode = null): void + { + $this->prepareRequest($sku, $storeCode); + $collection = $this->block->getPreparedCollection(); + $this->assertCount(1, $collection); + $this->assertEquals($expectedEmail, $collection->getFirstItem()->getEmail()); + } + + /** + * @return array + */ + public function alertsDataProvider(): array + { + return [ + 'without_store_id_filter' => [ + 'product_sku' => 'simple', + 'expected_customer_emails' => 'customer@example.com', + ], + 'with_store_id_filter' => [ + 'product_sku' => 'simple_on_second_website_for_price_alert', + 'expected_customer_emails' => 'customer_second_ws_with_addr@example.com', + 'store_code' => 'fixture_third_store', + ], + ]; + } + + /** + * @dataProvider storeProvider + * + * @param string|null $storeCode + * @return void + */ + public function testGetGridUrl(?string $storeCode): void + { + $this->prepareRequest(null, $storeCode); + $this->assertGridUrl($this->block->getGridUrl(), $storeCode); + } + + /** + * @return array + */ + public function storeProvider(): array + { + return [ + 'without_store_id_param' => [ + 'store_code' => null, + ], + 'with_store_id_param' => [ + 'store_code' => 'default', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php index b9ccfd6d52458..b221695a78e3b 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php @@ -7,12 +7,7 @@ namespace Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Alerts; -use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Framework\ObjectManagerInterface; use Magento\Framework\View\LayoutInterface; -use Magento\Store\Model\StoreManagerInterface; -use Magento\TestFramework\Helper\Bootstrap; -use PHPUnit\Framework\TestCase; /** * Check stock alert grid @@ -21,20 +16,11 @@ * * @magentoAppArea adminhtml */ -class StockTest extends TestCase +class StockTest extends AbstractAlertTest { - /** @var ObjectManagerInterface */ - private $objectManager; - /** @var Stock */ private $block; - /** @var StoreManagerInterface */ - private $storeManager; - - /** @var ProductRepositoryInterface */ - private $productRepository; - /** * @inheritdoc */ @@ -42,10 +28,7 @@ protected function setUp(): void { parent::setUp(); - $this->objectManager = Bootstrap::getObjectManager(); $this->block = $this->objectManager->get(LayoutInterface::class)->createBlock(Stock::class); - $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); - $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); } /** @@ -62,9 +45,7 @@ protected function setUp(): void */ public function testGridCollectionWithStoreId(string $sku, string $expectedEmail, ?string $storeCode = null): void { - $productId = (int)$this->productRepository->get($sku)->getId(); - $storeId = $storeCode ? (int)$this->storeManager->getStore($storeCode)->getId() : null; - $this->block->getRequest()->setParams(['id' => $productId, 'store' => $storeId]); + $this->prepareRequest($sku, $storeCode); $collection = $this->block->getPreparedCollection(); $this->assertCount(1, $collection); $this->assertEquals($expectedEmail, $collection->getFirstItem()->getEmail()); @@ -87,4 +68,31 @@ public function alertsDataProvider(): array ], ]; } + + /** + * @dataProvider storeProvider + * + * @param string|null $storeCode + * @return void + */ + public function testGetGridUrl(?string $storeCode): void + { + $this->prepareRequest(null, $storeCode); + $this->assertGridUrl($this->block->getGridUrl(), $storeCode); + } + + /** + * @return array + */ + public function storeProvider(): array + { + return [ + 'without_store_id_param' => [ + 'store_code' => null, + ], + 'with_store_id_param' => [ + 'store_code' => 'default', + ], + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AbstractAlertTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AbstractAlertTest.php new file mode 100644 index 0000000000000..5eea3b214435d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AbstractAlertTest.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Controller\Adminhtml\Product; + +use Magento\Catalog\Model\ResourceModel\Product as ProductResource; +use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Xpath; +use Magento\TestFramework\TestCase\AbstractBackendController; + +/** + * Class contains of base logic for alert controllers tests + */ +abstract class AbstractAlertTest extends AbstractBackendController +{ + /** @var ProductResource */ + private $productResource; + + /** @var StoreManagerInterface */ + private $storeManager; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->productResource = $this->_objectManager->get(ProductResource::class); + $this->storeManager = $this->_objectManager->get(StoreManagerInterface::class); + } + + /** + * Prepare request + * + * @param string $productSku + * @param string $storeCode + * @param int|null $limit + * @return void + */ + protected function prepareRequest(string $productSku, string $storeCode, ?int $limit): void + { + $productId = $this->productResource->getIdBySku($productSku); + $storeId = $this->storeManager->getStore($storeCode)->getId(); + $this->getRequest()->setMethod(HttpRequest::METHOD_GET); + $this->getRequest()->setParams(['id' => $productId, 'store' => $storeId, 'limit' => $limit]); + } + + /** + * Assert alert grid records count related to provided email + * + * @param string $email + * @param int $expectedCount + * @return void + */ + protected function assertGridRecords(string $email, int $expectedCount): void + { + $content = $this->getResponse()->getContent(); + $this->assertEquals( + $expectedCount, + Xpath::getElementsCountForXpath(sprintf($this->getRecordXpathTemplate(), $email), $content) + ); + } + + /** + * Get alert grid record xpath template + * + * @return string + */ + abstract protected function getRecordXpathTemplate(): string; +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AlertsPriceGridTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AlertsPriceGridTest.php new file mode 100644 index 0000000000000..f9eafaf2cdc19 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AlertsPriceGridTest.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Controller\Adminhtml\Product; + +/** + * Tests for price alert grid controller + * + * @see \Magento\Catalog\Controller\Adminhtml\Product\AlertsPriceGrid + * + * @magentoAppArea adminhtml + * @magentoDbIsolation disabled + */ +class AlertsPriceGridTest extends AbstractAlertTest +{ + /** + * @dataProvider priceLimitProvider + * + * @magentoDataFixture Magento/ProductAlert/_files/simple_product_with_two_alerts.php + * + * @param string $email + * @param int|null $limit + * @param $expectedCount + * @return void + */ + public function testExecute(string $email, ?int $limit, $expectedCount): void + { + $this->prepareRequest('simple', 'default', $limit); + $this->dispatch('backend/catalog/product/alertsPriceGrid'); + $this->assertGridRecords($email, $expectedCount); + } + + /** + * @return array + */ + public function priceLimitProvider(): array + { + return [ + 'default_limit' => [ + 'email' => 'customer@example.com', + 'limit' => null, + 'expected_count' => 2, + ], + 'limit_1' => [ + 'email' => 'customer@example.com', + 'limit' => 1, + 'expected_count' => 1, + ], + ]; + } + + /** + * @inheritdoc + */ + protected function getRecordXpathTemplate(): string + { + return "//div[@id='alertPrice']//tbody/tr/td[contains(text(), '%s')]"; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AlertsStockGridTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AlertsStockGridTest.php new file mode 100644 index 0000000000000..06e3fbda4c69e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AlertsStockGridTest.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Controller\Adminhtml\Product; + +/** + * Tests for stock alert grid controller + * + * @see \Magento\Catalog\Controller\Adminhtml\Product\AlertsStockGrid + * + * @magentoAppArea adminhtml + * @magentoDbIsolation disabled + */ +class AlertsStockGridTest extends AbstractAlertTest +{ + /** + * @dataProvider stockLimitProvider + * + * @magentoDataFixture Magento/ProductAlert/_files/simple_product_with_two_alerts.php + * + * @param string $email + * @param int|null $limit + * @param int $expectedCount + * @return void + */ + public function testExecute(string $email, ?int $limit, int $expectedCount): void + { + $this->prepareRequest('simple', 'default', $limit); + $this->dispatch('backend/catalog/product/alertsStockGrid'); + $this->assertGridRecords($email, $expectedCount); + } + + /** + * @return array + */ + public function stockLimitProvider(): array + { + return [ + 'default_limit' => [ + 'email' => 'customer@example.com', + 'limit' => null, + 'expected_count' => 2, + ], + 'limit_1' => [ + 'email' => 'customer@example.com', + 'limit' => 1, + 'expected_count' => 1, + ], + ]; + } + + /** + * @inheritdoc + */ + protected function getRecordXpathTemplate(): string + { + return "//div[@id='alertStock']//tbody/tr/td[contains(text(), '%s')]"; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AlertsTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AlertsTest.php index 96ddc66c875b7..8516916ba8cb3 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AlertsTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AlertsTest.php @@ -40,6 +40,7 @@ protected function setUp(): void /** * @magentoConfigFixture current_store catalog/productalert/allow_stock 1 + * @magentoConfigFixture current_store catalog/productalert/allow_price 1 * * @return void */ @@ -47,10 +48,15 @@ public function testModifyMeta(): void { $meta = $this->stockAlertsModifier->modifyMeta([]); $this->assertArrayHasKey('alerts', $meta); - $content = $meta['alerts']['children'][Alerts::DATA_SCOPE_STOCK]['arguments']['data']['config']['content']; + $stockContent = $meta['alerts']['children'][Alerts::DATA_SCOPE_STOCK]['arguments']['data']['config']['content']; $this->assertEquals( 1, - Xpath::getElementsCountForXpath("//div[@data-grid-id='alertStock']", $content) + Xpath::getElementsCountForXpath("//div[@data-grid-id='alertStock']", $stockContent) + ); + $priceContent = $meta['alerts']['children'][Alerts::DATA_SCOPE_PRICE]['arguments']['data']['config']['content']; + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath("//div[@data-grid-id='alertPrice']", $priceContent) ); } } diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/price_alert_on_second_website.php b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/price_alert_on_second_website.php new file mode 100644 index 0000000000000..7bbcbd37bc0e7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/price_alert_on_second_website.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\Data\ProductInterfaceFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\ProductAlert\Model\ResourceModel\Price as PriceResource; +use Magento\ProductAlert\Model\PriceFactory; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer_for_second_website_with_address.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +$secondWebsite = $storeManager->getWebsite('test'); +/** @var ProductInterfaceFactory $productFactory */ +$productFactory = $objectManager->get(ProductInterfaceFactory::class); +/** @var ProductRepositoryInterface $peoductRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$productRepository->cleanCache(); +/** @var PriceFactory $priceFactory */ +$priceFactory = $objectManager->get(PriceFactory::class); +/** @var PriceResource $priceResource */ +$priceResource = $objectManager->get(PriceResource::class); +/** @var CustomerRepositoryInterface $customerRepository */ +$customerRepository = $objectManager->get(CustomerRepositoryInterface::class); +$customer = $customerRepository->get('customer_second_ws_with_addr@example.com', (int)$secondWebsite->getId()); + + +$product = $productFactory->create(); +$product + ->setTypeId('simple') + ->setAttributeSetId($product->getDefaultAttributeSetId()) + ->setWebsiteIds([(int)$secondWebsite->getId()]) + ->setName('Simple Product2') + ->setSku('simple_on_second_website_for_price_alert') + ->setPrice(10) + ->setMetaTitle('meta title2') + ->setMetaKeyword('meta keyword2') + ->setMetaDescription('meta description2') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + +$productRepository->save($product); + +$priceAlert = $priceFactory->create(); +$priceAlert->setCustomerId( + $customer->getId() +)->setProductId( + (int)$productRepository->get($product->getSku())->getId() +)->setWebsiteId( + (int)$secondWebsite->getId() +)->setStoreId( + (int)$storeManager->getStore('fixture_third_store')->getId() +); +$priceResource->save($priceAlert); diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/price_alert_on_second_website_rollback.php b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/price_alert_on_second_website_rollback.php new file mode 100644 index 0000000000000..fce542dca24a1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/price_alert_on_second_website_rollback.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Registry; +use Magento\ProductAlert\Model\ResourceModel\Price as PriceResource; +use Magento\ProductAlert\Model\PriceFactory; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + + +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $peoductRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$productRepository->cleanCache(); +/** @var PriceFactory $priceFactory */ +$priceFactory = $objectManager->get(PriceFactory::class); +/** @var PriceResource $stockResource */ +$stockResource = $objectManager->get(PriceResource::class); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +$secondWebsite = $storeManager->getWebsite('test'); +/** @var CustomerRepositoryInterface $customerRepository */ +$customerRepository = $objectManager->get(CustomerRepositoryInterface::class); +$customer = $customerRepository->get('customer_second_ws_with_addr@example.com', (int)$secondWebsite->getId()); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $productRepository->deleteById('simple_on_second_website_for_price_alert'); +} catch (NoSuchEntityException $e) { + //already removed +} + + +$priceAlert = $priceFactory->create(); +$priceAlert->deleteCustomer((int)$customer->getId(), (int)$secondWebsite->getId()); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +Resolver::getInstance() + ->requireDataFixture('Magento/Customer/_files/customer_for_second_website_with_address_rollback.php'); diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_rollback.php b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_rollback.php index e9c4900ded341..3db4933f8a12c 100644 --- a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_rollback.php +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_rollback.php @@ -7,6 +7,7 @@ use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Framework\Registry; +use Magento\ProductAlert\Model\PriceFactory; use Magento\ProductAlert\Model\StockFactory; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Workaround\Override\Fixture\Resolver; @@ -14,6 +15,8 @@ $objectManager = Bootstrap::getObjectManager(); /** @var StockFactory $stockFactory */ $stockFactory = $objectManager->get(StockFactory::class); +/** @var PriceFactory $priceFactory */ +$priceFactory = $objectManager->get(PriceFactory::Class); /** @var CustomerRepositoryInterface $customerRepository */ $customerRepository = $objectManager->get(CustomerRepositoryInterface::class); $customer = $customerRepository->get('customer@example.com'); @@ -26,6 +29,9 @@ $stockAlert = $stockFactory->create(); $stockAlert->deleteCustomer((int)$customer->getId()); +$priceAlert = $priceFactory->create(); +$priceAlert->deleteCustomer(($customer->getId())); + $registry->unregister('isSecureArea'); $registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/simple_product_with_two_alerts.php b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/simple_product_with_two_alerts.php new file mode 100644 index 0000000000000..70f9e2fa97f7f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/simple_product_with_two_alerts.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Customer\Model\CustomerRegistry; +use Magento\ProductAlert\Model\PriceFactory; +use Magento\ProductAlert\Model\ResourceModel\Price as PriceResource; +use Magento\ProductAlert\Model\ResourceModel\Stock as StockResource; +use Magento\ProductAlert\Model\StockFactory; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer.php'); +Resolver::getInstance()->requireDataFixture('Magento/ProductAlert/_files/product_alert.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$productRepository->cleanCache(); +$product = $productRepository->get('simple'); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$baseWebsiteId = (int)$websiteRepository->get('base')->getId(); +/** @var CustomerRegistry $customerRegistry */ +$customerRegistry = $objectManager->create(CustomerRegistry::class); +$customer = $customerRegistry->retrieve(1); +/** @var PriceFactory $priceFactory */ +$priceFactory = $objectManager->get(PriceFactory::class); +/** @var PriceResource $priceResource */ +$priceResource = $objectManager->get(PriceResource::class); +$priceAlert = $priceFactory->create(); +$priceAlert->setCustomerId( + $customer->getId() +)->setProductId( + $product->getId() +)->setPrice( + $product->getPrice()+1 +)->setWebsiteId( + $baseWebsiteId +); +$priceResource->save($priceAlert); +/** @var StockFactory $stockFactory */ +$stockFactory = $objectManager->get(StockFactory::class); +/** @var StockResource $stockResource */ +$stockResource = $objectManager->get(StockResource::class); +$stockAlert = $stockFactory->create(); +$stockAlert->setCustomerId( + $customer->getId() +)->setProductId( + $product->getId() +)->setWebsiteId( + $baseWebsiteId +); +$stockResource->save($stockAlert); diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/simple_product_with_two_alerts_rollback.php b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/simple_product_with_two_alerts_rollback.php new file mode 100644 index 0000000000000..93614e974931d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/simple_product_with_two_alerts_rollback.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Framework\Registry; +use Magento\ProductAlert\Model\PriceFactory; +use Magento\ProductAlert\Model\StockFactory; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +$objectManager = Bootstrap::getObjectManager(); +/** @var StockFactory $stockFactory */ +$stockFactory = $objectManager->get(StockFactory::class); +/** @var PriceFactory $priceFactory */ +$priceFactory = $objectManager->get(PriceFactory::Class); +/** @var CustomerRepositoryInterface $customerRepository */ +$customerRepository = $objectManager->get(CustomerRepositoryInterface::class); +$customer = $customerRepository->get('customer@example.com'); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$stockAlert = $stockFactory->create(); +$stockAlert->deleteCustomer((int)$customer->getId()); + +$priceAlert = $priceFactory->create(); +$priceAlert->deleteCustomer(($customer->getId())); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer_rollback.php'); +Resolver::getInstance()->requireDataFixture('Magento/ProductAlert/_files/product_alert_rollback.php'); From 5a92ebf39a5fdf290107e69383fb74efd9fa7423 Mon Sep 17 00:00:00 2001 From: Serhii Bohomaz <serhii.bohomaz@transoftgroup.com> Date: Mon, 18 Jan 2021 12:28:28 +0200 Subject: [PATCH 22/38] MC-39584: Create automated test for: "Switching store views of category" --- .../Adminhtml/Category/EditTest.php | 75 +++++++++++++++++++ .../Catalog/_files/second_root_category.php | 21 ++++++ .../_files/second_root_category_rollback.php | 37 +++++++++ 3 files changed, 133 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/EditTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/EditTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/EditTest.php new file mode 100644 index 0000000000000..3c3dc26464d1e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/EditTest.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Controller\Adminhtml\Category; + +use Magento\Catalog\Api\Data\CategoryInterface; +use Magento\Catalog\Model\ResourceModel\Category\Collection; +use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; +use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\TestCase\AbstractBackendController; + +/** + * Test cases related to edit category. + * + * @see \Magento\Catalog\Controller\Adminhtml\Category\Edit + * @magentoAppArea adminhtml + * @magentoDbIsolation enabled + */ +class EditTest extends AbstractBackendController +{ + /** @var Collection */ + private $categoryCollectionFactory; + + /** @var StoreManagerInterface */ + private $storeManager; + + /** + * @inheritDoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->categoryCollectionFactory = $this->_objectManager->get(CollectionFactory::class); + $this->storeManager = $this->_objectManager->get(StoreManagerInterface::class); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/second_root_category.php + * + * @return void + */ + public function testSwitchingStoreViewsCategory(): void + { + $this->getRequest()->setMethod(HttpRequest::METHOD_GET); + $id = (int)$this->getCategoryIdByName('Second Root Category'); + $storeId = (int)$this->storeManager->getStore('default')->getId(); + $this->getRequest()->setParams(['store' => $storeId, 'id' => $id]); + $this->dispatch('backend/catalog/category/edit'); + $this->assertRedirect($this->stringContains('backend/catalog/category/index')); + $this->assertStringNotContainsString('/id/', $this->getResponse()->getHeader('Location')->getFieldValue()); + } + + /** + * Get category id by name + * + * @param string $name + * @return string|null + */ + private function getCategoryIdByName(string $name): ?string + { + $categoryCollection = $this->categoryCollectionFactory->create(); + $category = $categoryCollection + ->addAttributeToFilter(CategoryInterface::KEY_NAME, $name) + ->setPageSize(1) + ->getFirstItem(); + + return $category->getId(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category.php new file mode 100644 index 0000000000000..fec1be2fe5d3e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\CategoryRepositoryInterface; +use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\CategoryFactory; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var CategoryFactory $categoryFactory */ +$categoryFactory = $objectManager->get(CategoryFactory::class); +$categoryRepository = $objectManager->get(CategoryRepositoryInterface::class); +$rootCategory = $categoryFactory->create(); +$rootCategory->setName('Second Root Category') + ->setParentId(Category::TREE_ROOT_ID) + ->setIsActive(true); +$rootCategory = $categoryRepository->save($rootCategory); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category_rollback.php new file mode 100644 index 0000000000000..f6d347988c526 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category_rollback.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\CategoryRepositoryInterface; +use Magento\Catalog\Api\Data\CategoryInterface; +use Magento\Catalog\Model\CategoryRepository; +use Magento\Catalog\Model\ResourceModel\Category\Collection; +use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; +use Magento\Framework\Registry; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var CategoryRepository $categoryRepository */ +$categoryRepository = $objectManager->create(CategoryRepositoryInterface::class); +/** @var CollectionFactory $categoryCollectionFactory */ +$categoryCollectionFactory = $objectManager->get(CollectionFactory::class); + +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +/** @var Collection $categoryCollection */ +$categoryCollection = $categoryCollectionFactory->get(); +$category = $categoryCollection + ->addAttributeToFilter(CategoryInterface::KEY_NAME, 'Second Root Category') + ->setPageSize(1) + ->getFirstItem(); +if ($category->getId()) { + $categoryRepository->delete($category); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From 52e04e64df08ddd5c939f82f4d6aefde83d3a9e6 Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi <tsviklinskyi@gmail.com> Date: Mon, 18 Jan 2021 16:43:32 +0200 Subject: [PATCH 23/38] MC-40376: Auto suggestion box not reappearing after clicking outside the text field --- app/code/Magento/Search/view/frontend/web/js/form-mini.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/code/Magento/Search/view/frontend/web/js/form-mini.js b/app/code/Magento/Search/view/frontend/web/js/form-mini.js index b8034fead76d0..df651feb89d45 100644 --- a/app/code/Magento/Search/view/frontend/web/js/form-mini.js +++ b/app/code/Magento/Search/view/frontend/web/js/form-mini.js @@ -253,6 +253,8 @@ define([ } this.element.val(this.responseList.selected.find('.qs-option-name').text()); this.element.attr('aria-activedescendant', this.responseList.selected.attr('id')); + this._updateAriaHasPopup(true); + this.autoComplete.show(); } break; @@ -269,6 +271,8 @@ define([ } this.element.val(this.responseList.selected.find('.qs-option-name').text()); this.element.attr('aria-activedescendant', this.responseList.selected.attr('id')); + this._updateAriaHasPopup(true); + this.autoComplete.show(); } break; default: From 77e1e2beacbcd03da2fe612ccfdb6c0c23e00951 Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Mon, 18 Jan 2021 17:23:44 +0200 Subject: [PATCH 24/38] MC-40384: [Magento Cloud] Order Grid created time showing wrong --- .../ResourceModel/Order/Grid/Collection.php | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Grid/Collection.php index 82c612c1a781d..094fac313d398 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/Order/Grid/Collection.php +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Grid/Collection.php @@ -5,16 +5,25 @@ */ namespace Magento\Sales\Model\ResourceModel\Order\Grid; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy; use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory; use Magento\Framework\Event\ManagerInterface as EventManager; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; +use Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult; +use Magento\Sales\Model\ResourceModel\Order; use Psr\Log\LoggerInterface as Logger; /** * Order grid collection */ -class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult +class Collection extends SearchResult { + /** + * @var TimezoneInterface + */ + private $timeZone; + /** * Initialize dependencies. * @@ -24,6 +33,7 @@ class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvide * @param EventManager $eventManager * @param string $mainTable * @param string $resourceModel + * @param TimezoneInterface|null $timeZone */ public function __construct( EntityFactory $entityFactory, @@ -31,9 +41,12 @@ public function __construct( FetchStrategy $fetchStrategy, EventManager $eventManager, $mainTable = 'sales_order_grid', - $resourceModel = \Magento\Sales\Model\ResourceModel\Order::class + $resourceModel = Order::class, + TimezoneInterface $timeZone = null ) { parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); + $this->timeZone = $timeZone ?: ObjectManager::getInstance() + ->get(TimezoneInterface::class); } /** @@ -50,4 +63,20 @@ protected function _initSelect() return $this; } + + /** + * @inheritDoc + */ + public function addFieldToFilter($field, $condition = null) + { + if ($field === 'created_at') { + if (is_array($condition)) { + foreach ($condition as $key => $value) { + $condition[$key] = $this->timeZone->convertConfigTimeToUtc($value); + } + } + } + + return parent::addFieldToFilter($field, $condition); + } } From dfb79dc044c6e57b0d035adf51fa206813d3e120 Mon Sep 17 00:00:00 2001 From: Serhii Bohomaz <serhii.bohomaz@transoftgroup.com> Date: Mon, 18 Jan 2021 18:44:16 +0200 Subject: [PATCH 25/38] MC-39584: Create automated test for: "Switching store views of category" --- .../Adminhtml/Category/EditTest.php | 3 +- .../Category/Save/SaveCategoryTest.php | 38 +++++++++++++++++++ .../Catalog/_files/second_root_category.php | 3 +- .../_files/second_root_category_rollback.php | 9 ++--- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/EditTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/EditTest.php index 3c3dc26464d1e..f8a22ad05172c 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/EditTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/EditTest.php @@ -8,7 +8,6 @@ namespace Magento\Catalog\Controller\Adminhtml\Category; use Magento\Catalog\Api\Data\CategoryInterface; -use Magento\Catalog\Model\ResourceModel\Category\Collection; use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; use Magento\Framework\App\Request\Http as HttpRequest; use Magento\Store\Model\StoreManagerInterface; @@ -23,7 +22,7 @@ */ class EditTest extends AbstractBackendController { - /** @var Collection */ + /** @var CollectionFactory */ private $categoryCollectionFactory; /** @var StoreManagerInterface */ diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/SaveCategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/SaveCategoryTest.php index 3a93161517301..7e921b5c7ac12 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/SaveCategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/SaveCategoryTest.php @@ -15,6 +15,7 @@ use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Message\MessageInterface; use Magento\Store\Model\StoreManagerInterface; +use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; /** * Test cases for save category controller. @@ -36,6 +37,9 @@ class SaveCategoryTest extends AbstractSaveCategoryTest /** @var StoreManagerInterface */ private $storeManager; + /** @var CollectionFactory */ + private $categoryCollectionFactory; + /** * @inheritdoc */ @@ -46,6 +50,7 @@ protected function setUp(): void $this->categoryRepository = $this->_objectManager->get(CategoryRepositoryInterface::class); $this->getBlockByIdentifier = $this->_objectManager->get(GetBlockByIdentifierInterface::class); $this->storeManager = $this->_objectManager->get(StoreManagerInterface::class); + $this->categoryCollectionFactory = $this->_objectManager->get(CollectionFactory::class); } /** @@ -109,4 +114,37 @@ public function testTryToCreateCategoryWithEmptyValues(): void ); $this->assertSessionMessages($this->containsEqual($message), MessageInterface::TYPE_ERROR); } + + /** + * @magentoDataFixture Magento/Catalog/_files/second_root_category.php + * + * @return void + */ + public function testSwitchingStoreViewsCategory(): void + { + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $id = (int)$this->getCategoryIdByName('Second Root Category'); + $storeId = (int)$this->storeManager->getStore('default')->getId(); + $this->getRequest()->setParams(['store' => $storeId, 'id' => $id]); + $this->dispatch('backend/catalog/category/save'); + $this->assertRedirect($this->stringContains('backend/catalog/category/index')); + $this->assertStringNotContainsString('/id/', $this->getResponse()->getHeader('Location')->getFieldValue()); + } + + /** + * Get category id by name + * + * @param string $name + * @return string|null + */ + private function getCategoryIdByName(string $name): ?string + { + $categoryCollection = $this->categoryCollectionFactory->create(); + $category = $categoryCollection + ->addAttributeToFilter(CategoryInterface::KEY_NAME, $name) + ->setPageSize(1) + ->getFirstItem(); + + return $category->getId(); + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category.php index fec1be2fe5d3e..7a38cd6eeb52c 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category.php @@ -13,9 +13,10 @@ $objectManager = Bootstrap::getObjectManager(); /** @var CategoryFactory $categoryFactory */ $categoryFactory = $objectManager->get(CategoryFactory::class); +/** @var CategoryRepositoryInterface $categoryRepository */ $categoryRepository = $objectManager->get(CategoryRepositoryInterface::class); $rootCategory = $categoryFactory->create(); $rootCategory->setName('Second Root Category') ->setParentId(Category::TREE_ROOT_ID) ->setIsActive(true); -$rootCategory = $categoryRepository->save($rootCategory); +$categoryRepository->save($rootCategory); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category_rollback.php index f6d347988c526..142ebf5412c10 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_root_category_rollback.php @@ -7,15 +7,13 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Api\Data\CategoryInterface; -use Magento\Catalog\Model\CategoryRepository; -use Magento\Catalog\Model\ResourceModel\Category\Collection; use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; use Magento\Framework\Registry; use Magento\TestFramework\Helper\Bootstrap; $objectManager = Bootstrap::getObjectManager(); -/** @var CategoryRepository $categoryRepository */ -$categoryRepository = $objectManager->create(CategoryRepositoryInterface::class); +/** @var CategoryRepositoryInterface $categoryRepository */ +$categoryRepository = $objectManager->get(CategoryRepositoryInterface::class); /** @var CollectionFactory $categoryCollectionFactory */ $categoryCollectionFactory = $objectManager->get(CollectionFactory::class); @@ -23,8 +21,7 @@ $registry = $objectManager->get(Registry::class); $registry->unregister('isSecureArea'); $registry->register('isSecureArea', true); -/** @var Collection $categoryCollection */ -$categoryCollection = $categoryCollectionFactory->get(); +$categoryCollection = $categoryCollectionFactory->create(); $category = $categoryCollection ->addAttributeToFilter(CategoryInterface::KEY_NAME, 'Second Root Category') ->setPageSize(1) From 94987c015acc4898e1a5612d369661234c5497aa Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi <tsviklinskyi@gmail.com> Date: Tue, 19 Jan 2021 10:35:53 +0200 Subject: [PATCH 26/38] MC-40376: Auto suggestion box not reappearing after clicking outside the text field --- ...ertDropDownSearchSuggestionActionGroup.xml | 29 +++++++++ ...fySearchSuggestionByControlButtonsTest.xml | 65 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 app/code/Magento/Search/Test/Mftf/ActionGroup/StoreFrontAssertDropDownSearchSuggestionActionGroup.xml create mode 100644 app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchSuggestionByControlButtonsTest.xml diff --git a/app/code/Magento/Search/Test/Mftf/ActionGroup/StoreFrontAssertDropDownSearchSuggestionActionGroup.xml b/app/code/Magento/Search/Test/Mftf/ActionGroup/StoreFrontAssertDropDownSearchSuggestionActionGroup.xml new file mode 100644 index 0000000000000..62cb3ac70cbc4 --- /dev/null +++ b/app/code/Magento/Search/Test/Mftf/ActionGroup/StoreFrontAssertDropDownSearchSuggestionActionGroup.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StoreFrontAssertDropDownSearchSuggestionActionGroup"> + <annotations> + <description>Fills the Storefront Quick Search field. Validates that the Search Suggestion is present</description> + </annotations> + <arguments> + <argument name="searchQuery" type="string"/> + </arguments> + + <waitForElementVisible selector="{{StorefrontQuickSearchResultsSection.searchTextBox}}" stepKey="waitForQuickSearchToBeVisible"/> + <fillField selector="{{StorefrontQuickSearchResultsSection.searchTextBox}}" userInput="{{searchQuery}}" stepKey="fillSearchInput"/> + <waitForElementVisible selector="{{StorefrontQuickSearchSection.searchDropDownSuggestion}}" stepKey="WaitForSearchDropDownSuggestion"/> + <see selector="{{StorefrontQuickSearchSection.searchDropDownSuggestion}}" stepKey="seeDropDownSuggestion"/> + <click selector="//div[@class='panel wrapper']" stepKey="clickOnSomewhere"/> + <dontSee selector="{{StorefrontQuickSearchSection.searchDropDownSuggestion}}" stepKey="dontSeeDropDownSuggestion"/> + <click selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="clickOnSearchPhrase"/> + <pressKey selector="{{StorefrontQuickSearchSection.searchPhrase}}" parameterArray="[\Facebook\WebDriver\WebDriverKeys::DOWN]" stepKey="pressDown"/> + <see selector="{{StorefrontQuickSearchSection.searchDropDownSuggestion}}" stepKey="seeDropDownSuggestionSecond"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchSuggestionByControlButtonsTest.xml b/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchSuggestionByControlButtonsTest.xml new file mode 100644 index 0000000000000..e325ecd1fe3ae --- /dev/null +++ b/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchSuggestionByControlButtonsTest.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="StorefrontVerifySearchSuggestionByControlButtonsTest"> + <annotations> + <stories value="Search Term"/> + <title value="Auto suggestion box not reappearing after clicking outside the text field"/> + <description value="Auto suggestion box not reappearing after clicking outside the text field"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-40466"/> + <useCaseId value="MC-40376"/> + </annotations> + + <before> + <!-- Login as admin --> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + + <!-- Create Simple Product --> + <createData entity="defaultSimpleProduct" stepKey="simpleProduct"/> + + <!-- Perform reindex and flush cache --> + <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> + <argument name="indices" value=""/> + </actionGroup> + <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> + <argument name="tags" value=""/> + </actionGroup> + </before> + <after> + <!-- Delete create product --> + <deleteData createDataKey="simpleProduct" stepKey="deleteProduct"/> + + <!-- Go to the catalog search term page --> + <actionGroup ref="AdminOpenCatalogSearchTermIndexPageActionGroup" stepKey="openAdminCatalogSearchTermIndexPage"/> + + <!-- Filter the search term --> + <actionGroup ref="AdminSearchTermFilterBySearchQueryActionGroup" stepKey="filterByThirdSearchQuery"> + <argument name="searchQuery" value="$$simpleProduct.name$$"/> + </actionGroup> + <!-- Delete created below search terms --> + <actionGroup ref="AdminDeleteSearchTermActionGroup" stepKey="deleteSearchTerms"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <!-- Go to storefront home page --> + <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="openStoreFrontHomePage"/> + + <!-- Storefront quick search by product name --> + <actionGroup ref="StorefrontCheckQuickSearchStringActionGroup" stepKey="quickSearchByProductName"> + <argument name="phrase" value="$$simpleProduct.name$$"/> + </actionGroup> + + <!-- Verify search suggestions and select the suggestion from dropdown options --> + <actionGroup ref="StoreFrontAssertDropDownSearchSuggestionActionGroup" stepKey="seeDropDownSearchSuggestion"> + <argument name="searchQuery" value="$$simpleProduct.name$$"/> + </actionGroup> + </test> +</tests> From 609d9059436071448f493f54784b944c55502c30 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Tue, 19 Jan 2021 12:27:32 +0200 Subject: [PATCH 27/38] MC-39550: Create automated test for: "Add new website to products using mass product update and run cron." --- .../Backend/ConsumerWebsiteAssignTest.php | 262 ++++++++++++++++++ .../detach_product_website_quene_data.php | 62 +++++ ...ch_product_website_quene_data_rollback.php | 17 ++ .../update_product_website_quene_data.php | 63 +++++ ...te_product_website_quene_data_rollback.php | 18 ++ 5 files changed, 422 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Attribute/Backend/ConsumerWebsiteAssignTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Attribute/Backend/ConsumerWebsiteAssignTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Attribute/Backend/ConsumerWebsiteAssignTest.php new file mode 100644 index 0000000000000..e895a886e44e7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Attribute/Backend/ConsumerWebsiteAssignTest.php @@ -0,0 +1,262 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Attribute\Backend; + +use Magento\AsynchronousOperations\Api\Data\OperationInterface as OperationDataInterface; +use Magento\AsynchronousOperations\Model\ResourceModel\Operation\CollectionFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product\Action; +use Magento\Framework\Bulk\OperationInterface; +use Magento\Framework\DB\Adapter\DeadlockException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\MessageQueue\MessageEncoder; +use Magento\Framework\ObjectManagerInterface; +use Magento\MysqlMq\Model\Driver\Queue; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\MysqlMq\DeleteTopicRelatedMessages; +use PHPUnit\Framework\TestCase; + +/** + * Tests for Mysql website assigning consumer + * + * @see \Magento\Catalog\Model\Attribute\Backend\ConsumerWebsiteAssign + * + * @magentoDbIsolation disabled + * @magentoAppArea adminhtml + */ +class ConsumerWebsiteAssignTest extends TestCase +{ + private const TOPIC_NAME = 'product_action_attribute.website.update'; + + /** @var DeleteTopicRelatedMessages */ + private static $deleteTopicRelatedMessages; + + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var ConsumerWebsiteAssign */ + private $consumer; + + /** @var Queue */ + private $queue; + + /** @var MessageEncoder */ + private $messageEncoder; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** @var WebsiteRepositoryInterface */ + private $websiteRepository; + + /** @var CollectionFactory */ + private $operationCollectionFactory; + + /** + * @inheritdoc + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + $objectManager = Bootstrap::getObjectManager(); + self::$deleteTopicRelatedMessages = $objectManager->get(DeleteTopicRelatedMessages::class); + self::$deleteTopicRelatedMessages->execute(self::TOPIC_NAME); + } + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->consumer = $this->objectManager->get(ConsumerWebsiteAssign::class); + $this->queue = $this->objectManager->create( + Queue::class, + ['queueName' => 'product_action_attribute.website.update'] + ); + $this->messageEncoder = $this->objectManager->get(MessageEncoder::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class); + $this->operationCollectionFactory = $this->objectManager->get(CollectionFactory::class); + } + + /** + * @return void + */ + protected function tearDown(): void + { + $this->objectManager->removeSharedInstance(Action::class); + self::$deleteTopicRelatedMessages->execute(self::TOPIC_NAME); + + parent::tearDown(); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/update_product_website_quene_data.php + * + * @return void + */ + public function testAddWebsite(): void + { + $this->processMessages(); + $this->assertProductWebsites('simple2', ['base', 'test']); + $this->assertOperation(OperationInterface::STATUS_TYPE_COMPLETE); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/detach_product_website_quene_data.php + * + * @return void + */ + public function testRemoveWebsite(): void + { + $this->processMessages(); + $this->assertProductWebsites('unique-simple-azaza', ['base']); + $this->assertOperation(OperationInterface::STATUS_TYPE_COMPLETE); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/update_product_website_quene_data.php + * + * @return void + */ + public function testAddWebsiteToDeletedProduct(): void + { + $expectedMessage = __('Something went wrong while adding products to websites.'); + $this->productRepository->deleteById('simple2'); + $this->processMessages(); + $this->assertOperation(OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED, (string)$expectedMessage); + } + + /** + * @dataProvider errorProvider + * + * @magentoDataFixture Magento/Catalog/_files/update_product_website_quene_data.php + * + * @param \Throwable $exception + * @param int $code + * @return void + */ + public function testWithException(\Throwable $exception, int $code): void + { + $this->prepareMock($exception); + $this->processMessages(); + $this->assertOperation($code, $exception->getMessage()); + } + + /** + * @return array + */ + public function errorProvider(): array + { + return [ + 'with_dead_lock_exception' => [ + 'exception' => new DeadlockException('Test lock'), + 'code' => OperationDataInterface::STATUS_TYPE_RETRIABLY_FAILED, + ], + 'with_db_exception' => [ + 'exception' => new \Zend_Db_Adapter_Exception( + (string)__( + 'Sorry, something went wrong during product attributes update. Please see log for details.' + ) + ), + 'code' => OperationDataInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED, + ], + 'with_no_such_entity_exception' => [ + 'exception' => new NoSuchEntityException(), + 'code' => OperationDataInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED, + ], + 'with_general_exception' => [ + 'exception' => new \Exception( + (string)__( + 'Sorry, something went wrong during product attributes update. Please see log for details.' + ) + ), + 'code' => OperationDataInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED, + ], + ]; + } + + /** + * Assert product website ids + * + * @param string $sku + * @param array $expectedWebsites + * @return void + */ + private function assertProductWebsites(string $sku, array $expectedWebsites): void + { + $product = $this->productRepository->get($sku, false, null, true); + $websitesIds = $product->getWebsiteIds(); + $this->assertCount(count($expectedWebsites), $websitesIds); + + foreach ($expectedWebsites as $expectedWebsite) { + $expectedWebsiteId = $this->websiteRepository->get($expectedWebsite)->getId(); + $this->assertContains($expectedWebsiteId, $websitesIds); + } + } + + /** + * Process current consumer topic messages + * + * @return void + */ + private function processMessages(): void + { + $envelope = $this->queue->dequeue(); + $decodedMessage = $this->messageEncoder->decode(self::TOPIC_NAME, $envelope->getBody()); + $this->consumer->process($decodedMessage); + } + + /** + * Get last current topic related operation + * + * @return OperationDataInterface + */ + private function getLastTopicOperation(): OperationDataInterface + { + $collection = $this->operationCollectionFactory->create(); + $collection->addFieldToFilter('topic_name', self::TOPIC_NAME); + $collection->setPageSize(1)->setCurPage($collection->getLastPageNumber()); + + return $collection->getLastItem(); + } + + /** + * Assert performed operation + * + * @param int $status + * @param string|null $resultMessage + * @return void + */ + private function assertOperation(int $status, ?string $resultMessage = null): void + { + $operation = $this->getLastTopicOperation(); + $this->assertNotNull($operation->getData('id')); + $this->assertEquals($status, $operation->getStatus()); + $this->assertEquals($resultMessage, $operation->getResultMessage()); + } + + /** + * Create mock with provided exception + * + * @param \Throwable $exception + * @return void + */ + private function prepareMock(\Throwable $exception): void + { + $object = $this->createPartialMock(Action::class, ['updateWebsites']); + $object->method('updateWebsites')->willThrowException($exception); + $this->objectManager->addSharedInstance($object, Action::class); + $this->consumer = $this->objectManager->create(ConsumerWebsiteAssign::class); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data.php new file mode 100644 index 0000000000000..ab03ff5bf6b65 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data.php @@ -0,0 +1,62 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\AsynchronousOperations\Api\Data\OperationInterfaceFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Bulk\BulkManagementInterface; +use Magento\Framework\Bulk\OperationInterface; +use Magento\Framework\DataObject\IdentityGeneratorInterface; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_with_two_websites.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$productRepository->cleanCache(); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +/** @var IdentityGeneratorInterface $identityService */ +$identityService = $objectManager->get(IdentityGeneratorInterface::class); +/** @var SerializerInterface $jsonEncoder */ +$jsonEncoder = $objectManager->get(SerializerInterface::class); +/** @var OperationInterfaceFactory $optionFactory */ +$optionFactory = $objectManager->get(OperationInterfaceFactory::class); +/** @var BulkManagementInterface $bulkManagement */ +$bulkManagement = $objectManager->get(BulkManagementInterface::class); +$productIds = [(int)$productRepository->get('unique-simple-azaza')->getId()]; +$websiteId = (int)$websiteRepository->get('second_website')->getId(); +$bulkDescription = __('Update attributes for ' . 1 . ' selected products'); +$dataToEncode = [ + 'meta_information' => 'Update website assign', + 'product_ids' => $productIds, + 'store_id' => 0, + 'website_id' => $websiteId, + 'attributes' => [ + 'website_assign' => [], + 'website_detach' => [$websiteId], + ], +]; +$bulkUid = $identityService->generateId(); +$data = [ + 'data' => [ + 'bulk_uuid' => $bulkUid, + 'topic_name' => 'product_action_attribute.website.update', + 'serialized_data' => $jsonEncoder->serialize($dataToEncode), + 'status' => OperationInterface::STATUS_TYPE_OPEN, + ] +]; + +$bulkManagement->scheduleBulk( + $bulkUid, + [$optionFactory->create($data)], + $bulkDescription, + 1 +); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data_rollback.php new file mode 100644 index 0000000000000..df62ecc22c623 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data_rollback.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\MysqlMq\DeleteTopicRelatedMessages; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +$objectManager = Bootstrap::getObjectManager(); +/** @var DeleteTopicRelatedMessages $deleteTopicRelatedMessages */ +$deleteTopicRelatedMessages = $objectManager->get(DeleteTopicRelatedMessages::class); +$deleteTopicRelatedMessages->execute('product_action_attribute.website.update'); + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_with_two_websites_rollback.php'); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data.php new file mode 100644 index 0000000000000..dca8fb26c0b55 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\AsynchronousOperations\Api\Data\OperationInterfaceFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Bulk\BulkManagementInterface; +use Magento\Framework\Bulk\OperationInterface; +use Magento\Framework\DataObject\IdentityGeneratorInterface; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Store/_files/second_website_with_two_stores.php'); +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/second_product_simple.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$productRepository->cleanCache(); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +/** @var IdentityGeneratorInterface $identityService */ +$identityService = $objectManager->get(IdentityGeneratorInterface::class); +/** @var SerializerInterface $jsonEncoder */ +$jsonEncoder = $objectManager->get(SerializerInterface::class); +/** @var OperationInterfaceFactory $optionFactory */ +$optionFactory = $objectManager->get(OperationInterfaceFactory::class); +/** @var BulkManagementInterface $bulkManagement */ +$bulkManagement = $objectManager->get(BulkManagementInterface::class); +$productIds = [(int)$productRepository->get('simple2')->getId()]; +$websiteId = (int)$websiteRepository->get('test')->getId(); +$bulkDescription = __('Update attributes for ' . 1 . ' selected products'); +$dataToEncode = [ + 'meta_information' => 'Update website assign', + 'product_ids' => $productIds, + 'store_id' => 0, + 'website_id' => $websiteId, + 'attributes' => [ + 'website_assign' => [$websiteId], + 'website_detach' => [], + ], +]; +$bulkUid = $identityService->generateId(); +$data = [ + 'data' => [ + 'bulk_uuid' => $bulkUid, + 'topic_name' => 'product_action_attribute.website.update', + 'serialized_data' => $jsonEncoder->serialize($dataToEncode), + 'status' => OperationInterface::STATUS_TYPE_OPEN, + ] +]; + +$bulkManagement->scheduleBulk( + $bulkUid, + [$optionFactory->create($data)], + $bulkDescription, + 1 +); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data_rollback.php new file mode 100644 index 0000000000000..5273947cd28ea --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data_rollback.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\MysqlMq\DeleteTopicRelatedMessages; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +$objectManager = Bootstrap::getObjectManager(); +/** @var DeleteTopicRelatedMessages $deleteTopicRelatedMessages */ +$deleteTopicRelatedMessages = $objectManager->get(DeleteTopicRelatedMessages::class); +$deleteTopicRelatedMessages->execute('product_action_attribute.website.update'); + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/second_product_simple_rollback.php'); +Resolver::getInstance()->requireDataFixture('Magento/Store/_files/second_website_with_store_group_and_store_rollback.php'); From 105bc1f22a29ae1be87f611fd43d19cc823aba6e Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Tue, 19 Jan 2021 14:51:23 +0200 Subject: [PATCH 28/38] MC-40384: [Magento Cloud] Order Grid created time showing wrong --- .../Order/Grid/CollectionTest.php | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Grid/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Grid/CollectionTest.php index d2d71ab880026..abf845aca0d88 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Grid/CollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Grid/CollectionTest.php @@ -7,10 +7,26 @@ namespace Magento\Sales\Model\ResourceModel\Order\Grid; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; -class CollectionTest extends \PHPUnit\Framework\TestCase +class CollectionTest extends TestCase { + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @inheritDoc + */ + protected function setUp(): void + { + $this->objectManager = Bootstrap::getObjectManager(); + } + /** * Tests collection properties. * @@ -19,10 +35,8 @@ class CollectionTest extends \PHPUnit\Framework\TestCase */ public function testCollectionCreate(): void { - $objectManager = Bootstrap::getObjectManager(); - /** @var Collection $gridCollection */ - $gridCollection = $objectManager->get(Collection::class); + $gridCollection = $this->objectManager->get(Collection::class); $tableDescription = $gridCollection->getConnection() ->describeTable($gridCollection->getMainTable()); @@ -42,4 +56,25 @@ public function testCollectionCreate(): void self::assertStringContainsString('main_table.', $mappedName); } } + + /** + * Verifies that filter condition date is being converted to config timezone before select sql query + * + * @return void + */ + public function testAddFieldToFilter(): void + { + $filterDate = "2021-01-19 00:00:00"; + /** @var TimezoneInterface $timeZone */ + $timeZone = $this->objectManager->get(TimezoneInterface::class); + /** @var Collection $gridCollection */ + $gridCollection = $this->objectManager->get(Collection::class); + $convertedDate = $timeZone->convertConfigTimeToUtc($filterDate); + + $collection = $gridCollection->addFieldToFilter('created_at', ['qteq' => $filterDate]); + $expectedSelect = "SELECT `main_table`.* FROM `sales_order_grid` AS `main_table` " . + "WHERE (((`main_table`.`created_at` = '{$convertedDate}')))"; + + $this->assertEquals($expectedSelect, $collection->getSelectSql(true)); + } } From 3e3a639fe64ccc2a701c823a23c418976178f214 Mon Sep 17 00:00:00 2001 From: Vasya Tsviklinskyi <tsviklinskyi@gmail.com> Date: Tue, 19 Jan 2021 14:59:16 +0200 Subject: [PATCH 29/38] MC-40376: Auto suggestion box not reappearing after clicking outside the text field --- ...ontAssertDropDownSearchSuggestionActionGroup.xml | 3 +-- ...ntVerifySearchSuggestionByControlButtonsTest.xml | 13 ++++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Search/Test/Mftf/ActionGroup/StoreFrontAssertDropDownSearchSuggestionActionGroup.xml b/app/code/Magento/Search/Test/Mftf/ActionGroup/StoreFrontAssertDropDownSearchSuggestionActionGroup.xml index 62cb3ac70cbc4..226e30486251c 100644 --- a/app/code/Magento/Search/Test/Mftf/ActionGroup/StoreFrontAssertDropDownSearchSuggestionActionGroup.xml +++ b/app/code/Magento/Search/Test/Mftf/ActionGroup/StoreFrontAssertDropDownSearchSuggestionActionGroup.xml @@ -19,11 +19,10 @@ <waitForElementVisible selector="{{StorefrontQuickSearchResultsSection.searchTextBox}}" stepKey="waitForQuickSearchToBeVisible"/> <fillField selector="{{StorefrontQuickSearchResultsSection.searchTextBox}}" userInput="{{searchQuery}}" stepKey="fillSearchInput"/> <waitForElementVisible selector="{{StorefrontQuickSearchSection.searchDropDownSuggestion}}" stepKey="WaitForSearchDropDownSuggestion"/> - <see selector="{{StorefrontQuickSearchSection.searchDropDownSuggestion}}" stepKey="seeDropDownSuggestion"/> <click selector="//div[@class='panel wrapper']" stepKey="clickOnSomewhere"/> <dontSee selector="{{StorefrontQuickSearchSection.searchDropDownSuggestion}}" stepKey="dontSeeDropDownSuggestion"/> <click selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="clickOnSearchPhrase"/> <pressKey selector="{{StorefrontQuickSearchSection.searchPhrase}}" parameterArray="[\Facebook\WebDriver\WebDriverKeys::DOWN]" stepKey="pressDown"/> - <see selector="{{StorefrontQuickSearchSection.searchDropDownSuggestion}}" stepKey="seeDropDownSuggestionSecond"/> + <waitForElementVisible selector="{{StorefrontQuickSearchSection.searchDropDownSuggestion}}" stepKey="WaitForSearchDropDownSuggestionSecond"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchSuggestionByControlButtonsTest.xml b/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchSuggestionByControlButtonsTest.xml index e325ecd1fe3ae..b9c491705316c 100644 --- a/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchSuggestionByControlButtonsTest.xml +++ b/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchSuggestionByControlButtonsTest.xml @@ -19,12 +19,12 @@ </annotations> <before> - <!-- Login as admin --> - <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> - <!-- Create Simple Product --> <createData entity="defaultSimpleProduct" stepKey="simpleProduct"/> + <!-- Login as admin --> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <!-- Perform reindex and flush cache --> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> <argument name="indices" value=""/> @@ -42,11 +42,10 @@ <!-- Filter the search term --> <actionGroup ref="AdminSearchTermFilterBySearchQueryActionGroup" stepKey="filterByThirdSearchQuery"> - <argument name="searchQuery" value="$$simpleProduct.name$$"/> + <argument name="searchQuery" value="$simpleProduct.name$"/> </actionGroup> <!-- Delete created below search terms --> <actionGroup ref="AdminDeleteSearchTermActionGroup" stepKey="deleteSearchTerms"/> - <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> <!-- Go to storefront home page --> @@ -54,12 +53,12 @@ <!-- Storefront quick search by product name --> <actionGroup ref="StorefrontCheckQuickSearchStringActionGroup" stepKey="quickSearchByProductName"> - <argument name="phrase" value="$$simpleProduct.name$$"/> + <argument name="phrase" value="$simpleProduct.name$"/> </actionGroup> <!-- Verify search suggestions and select the suggestion from dropdown options --> <actionGroup ref="StoreFrontAssertDropDownSearchSuggestionActionGroup" stepKey="seeDropDownSearchSuggestion"> - <argument name="searchQuery" value="$$simpleProduct.name$$"/> + <argument name="searchQuery" value="$simpleProduct.name$"/> </actionGroup> </test> </tests> From 07b208151a68ad36d7ba7a417c4e96e28ee8d992 Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Tue, 19 Jan 2021 08:03:52 -0600 Subject: [PATCH 30/38] B2B-1640: Add MFTF test for MC-38222 - Adding check on Import History page --- ...NavigateToImportHistoryPageActionGroup.xml | 17 ++++++++++++++ .../Test/Mftf/Page/AdminImportHistoryPage.xml | 12 ++++++++++ ...igurableProductsWithAssignedImagesTest.xml | 8 +++++++ ...dminGridSortColumnAscendingActionGroup.xml | 23 +++++++++++++++++++ ...minGridSortColumnDescendingActionGroup.xml | 23 +++++++++++++++++++ .../Section/AdminDataGridHeaderSection.xml | 5 ++++ 6 files changed, 88 insertions(+) create mode 100644 app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminNavigateToImportHistoryPageActionGroup.xml create mode 100644 app/code/Magento/ImportExport/Test/Mftf/Page/AdminImportHistoryPage.xml create mode 100644 app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridSortColumnAscendingActionGroup.xml create mode 100644 app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridSortColumnDescendingActionGroup.xml diff --git a/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminNavigateToImportHistoryPageActionGroup.xml b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminNavigateToImportHistoryPageActionGroup.xml new file mode 100644 index 0000000000000..02a5990b9ad25 --- /dev/null +++ b/app/code/Magento/ImportExport/Test/Mftf/ActionGroup/AdminNavigateToImportHistoryPageActionGroup.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="AdminNavigateToImportHistoryPageActionGroup"> + <annotations> + <description>Navigates to the admin System > Data Transfer > Import History page.</description> + </annotations> + <amOnPage url="{{AdminImportHistoryPage.url}}" stepKey="navigateToImportHistoryPage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ImportExport/Test/Mftf/Page/AdminImportHistoryPage.xml b/app/code/Magento/ImportExport/Test/Mftf/Page/AdminImportHistoryPage.xml new file mode 100644 index 0000000000000..211d81582793f --- /dev/null +++ b/app/code/Magento/ImportExport/Test/Mftf/Page/AdminImportHistoryPage.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminImportHistoryPage" url="admin/history" area="admin" module="Magento_ImportExport"/> +</pages> diff --git a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml index df7c671d6a5b6..f8768283dfa2d 100644 --- a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml +++ b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml @@ -86,6 +86,14 @@ <argument name="indices" value=""/> </actionGroup> + <!-- Admin: Verify Data on Import History Page --> + <actionGroup ref="AdminNavigateToImportHistoryPageActionGroup" stepKey="navigateToImportHistoryPage"/> + <actionGroup ref="AdminGridSortColumnDescendingActionGroup" stepKey="sortColumnByIdDescending"> + <argument name="columnLabel" value="history_id"/> + </actionGroup> + <see userInput="import_configurable_product.csv" selector="{{AdminDataGridTableSection.firstRow}}" stepKey="seeImportedFile"/> + <see userInput="Created: 4, Updated: 0, Deleted: 0" selector="{{AdminDataGridTableSection.firstRow}}" stepKey="seeSummary"/> + <!-- Admin: Verify Simple Product 1 on Product Index Page --> <actionGroup ref="AssertProductOnAdminGridActionGroup" stepKey="assertSimpleProduct1InAdminGrid"> <argument name="product" value="ImportSimple1"/> diff --git a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridSortColumnAscendingActionGroup.xml b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridSortColumnAscendingActionGroup.xml new file mode 100644 index 0000000000000..c11f0bb1dd720 --- /dev/null +++ b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridSortColumnAscendingActionGroup.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="AdminGridSortColumnAscendingActionGroup"> + <annotations> + <description>Sorts the specified column in ascending order on Admin Grid page.</description> + </annotations> + <arguments> + <argument name="columnLabel" type="string"/> + </arguments> + <conditionalClick selector="{{AdminDataGridHeaderSection.columnByLabel(columnLabel)}}" dependentSelector="{{AdminDataGridHeaderSection.columnNotSorted(columnLabel)}}" visible="true" stepKey="clickColumnIfNotSorted"/> + <waitForPageLoad stepKey="waitForGridLoad1"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.columnByLabel(columnLabel)}}" dependentSelector="{{AdminDataGridHeaderSection.columnSortedDescending(columnLabel)}}" visible="true" stepKey="clickColumnIfDescending"/> + <waitForPageLoad stepKey="waitForGridLoad2"/> + <waitForElementVisible selector="{{AdminDataGridHeaderSection.columnSortedAscending(columnLabel)}}" stepKey="seeColumnAscending"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridSortColumnDescendingActionGroup.xml b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridSortColumnDescendingActionGroup.xml new file mode 100644 index 0000000000000..0d1ab2a8ac8b5 --- /dev/null +++ b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridSortColumnDescendingActionGroup.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="AdminGridSortColumnDescendingActionGroup"> + <annotations> + <description>Sorts the specified column in descending order on Admin Grid page.</description> + </annotations> + <arguments> + <argument name="columnLabel" type="string"/> + </arguments> + <conditionalClick selector="{{AdminDataGridHeaderSection.columnByLabel(columnLabel)}}" dependentSelector="{{AdminDataGridHeaderSection.columnNotSorted(columnLabel)}}" visible="true" stepKey="clickColumnIfNotSorted"/> + <waitForPageLoad stepKey="waitForGridLoad1"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.columnByLabel(columnLabel)}}" dependentSelector="{{AdminDataGridHeaderSection.columnSortedAscending(columnLabel)}}" visible="true" stepKey="clickColumnIfAscending"/> + <waitForPageLoad stepKey="waitForGridLoad2"/> + <waitForElementVisible selector="{{AdminDataGridHeaderSection.columnSortedDescending(columnLabel)}}" stepKey="seeColumnDescending"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridHeaderSection.xml b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridHeaderSection.xml index 4ee38e30f98e6..15835aa439b08 100644 --- a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridHeaderSection.xml +++ b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridHeaderSection.xml @@ -27,5 +27,10 @@ <element name="columnCheckbox" type="checkbox" selector="//div[contains(@class,'admin__data-grid-action-columns')]//div[contains(@class, 'admin__field-option')]//label[text() = '{{column}}']/preceding-sibling::input" parameterized="true"/> <element name="perPage" type="select" selector="#product_attributes_listing.product_attributes_listing.listing_top.listing_paging_sizes"/> <element name="attributeName" type="input" selector="//div[text()='{{arg}}']/../preceding-sibling::td//input" parameterized="true"/> + <!--Sorting--> + <element name="columnByLabel" type="text" parameterized="true" selector="th[data-sort='{{columnName}}']"/> + <element name="columnNotSorted" type="text" parameterized="true" selector="th[data-sort='{{columnName}}'].not-sort"/> + <element name="columnSortedAscending" type="text" parameterized="true" selector="th[data-sort='{{columnName}}']._ascend"/> + <element name="columnSortedDescending" type="text" parameterized="true" selector="th[data-sort='{{columnName}}']._descend"/> </section> </sections> From aff2b004973f9587be4abf365fbb33ceff0706c6 Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Tue, 19 Jan 2021 16:28:39 +0200 Subject: [PATCH 31/38] MC-40283: Catalog Rule does not work for multi-website with different timezones --- .../Model/Indexer/ReindexRuleProduct.php | 51 +++++++++++++++---- .../Model/Indexer/ReindexRuleProductPrice.php | 38 +++++++++++--- ...ontinueEditCatalogPriceRuleActionGroup.xml | 20 ++++++++ .../Indexer/ReindexRuleProductPriceTest.php | 3 +- .../Model/Indexer/ReindexRuleProductTest.php | 15 ++++-- 5 files changed, 103 insertions(+), 24 deletions(-) create mode 100644 app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/SaveAndContinueEditCatalogPriceRuleActionGroup.xml diff --git a/app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProduct.php b/app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProduct.php index 944710773123f..3e2301f34c4f8 100644 --- a/app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProduct.php +++ b/app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProduct.php @@ -6,8 +6,8 @@ namespace Magento\CatalogRule\Model\Indexer; -use Magento\CatalogRule\Model\Indexer\IndexerTableSwapperInterface as TableSwapper; use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher; +use Magento\CatalogRule\Model\Indexer\IndexerTableSwapperInterface as TableSwapper; use Magento\CatalogRule\Model\Rule; use Magento\Framework\App\ResourceConnection; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; @@ -18,6 +18,8 @@ */ class ReindexRuleProduct { + private const ADMIN_WEBSITE_ID = 0; + /** * @var ResourceConnection */ @@ -38,22 +40,30 @@ class ReindexRuleProduct */ private $localeDate; + /** + * @var bool + */ + private $useWebsiteTimezone; + /** * @param ResourceConnection $resource * @param ActiveTableSwitcher $activeTableSwitcher * @param TableSwapper $tableSwapper * @param TimezoneInterface $localeDate + * @param bool $useWebsiteTimezone */ public function __construct( ResourceConnection $resource, ActiveTableSwitcher $activeTableSwitcher, TableSwapper $tableSwapper, - TimezoneInterface $localeDate + TimezoneInterface $localeDate, + bool $useWebsiteTimezone = true ) { $this->resource = $resource; $this->activeTableSwitcher = $activeTableSwitcher; $this->tableSwapper = $tableSwapper; $this->localeDate = $localeDate; + $this->useWebsiteTimezone = $useWebsiteTimezone; } /** @@ -95,18 +105,18 @@ public function execute(Rule $rule, $batchCount, $useAdditionalTable = false) $actionOperator = $rule->getSimpleAction(); $actionAmount = $rule->getDiscountAmount(); $actionStop = $rule->getStopRulesProcessing(); + $fromTimeInAdminTz = $this->parseDateByWebsiteTz((string)$rule->getFromDate(), self::ADMIN_WEBSITE_ID); + $toTimeInAdminTz = $this->parseDateByWebsiteTz((string)$rule->getToDate(), self::ADMIN_WEBSITE_ID); $rows = []; foreach ($websiteIds as $websiteId) { - $scopeTz = new \DateTimeZone( - $this->localeDate->getConfigTimezone(ScopeInterface::SCOPE_WEBSITE, $websiteId) - ); - $fromTime = $rule->getFromDate() - ? (new \DateTime($rule->getFromDate(), $scopeTz))->getTimestamp() - : 0; - $toTime = $rule->getToDate() - ? (new \DateTime($rule->getToDate(), $scopeTz))->getTimestamp() + IndexBuilder::SECONDS_IN_DAY - 1 - : 0; + $fromTime = $this->useWebsiteTimezone + ? $this->parseDateByWebsiteTz((string)$rule->getFromDate(), (int)$websiteId) + : $fromTimeInAdminTz; + $toTime = $this->useWebsiteTimezone + ? $this->parseDateByWebsiteTz((string)$rule->getToDate(), (int)$websiteId) + + ($rule->getToDate() ? IndexBuilder::SECONDS_IN_DAY - 1 : 0) + : $toTimeInAdminTz; foreach ($productIds as $productId => $validationByWebsite) { if (empty($validationByWebsite[$websiteId])) { @@ -140,4 +150,23 @@ public function execute(Rule $rule, $batchCount, $useAdditionalTable = false) return true; } + + /** + * Parse date value by the timezone of the website + * + * @param string $date + * @param int $websiteId + * @return int + */ + private function parseDateByWebsiteTz(string $date, int $websiteId): int + { + if (empty($date)) { + return 0; + } + + $websiteTz = $this->localeDate->getConfigTimezone(ScopeInterface::SCOPE_WEBSITE, $websiteId); + $dateTime = new \DateTime($date, new \DateTimeZone($websiteTz)); + + return $dateTime->getTimestamp(); + } } diff --git a/app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProductPrice.php b/app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProductPrice.php index 51869f1accbb3..ccc5352567ff0 100644 --- a/app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProductPrice.php +++ b/app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProductPrice.php @@ -7,6 +7,7 @@ namespace Magento\CatalogRule\Model\Indexer; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; +use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; /** @@ -39,25 +40,33 @@ class ReindexRuleProductPrice */ private $pricesPersistor; + /** + * @var bool + */ + private $useWebsiteTimezone; + /** * @param StoreManagerInterface $storeManager * @param RuleProductsSelectBuilder $ruleProductsSelectBuilder * @param ProductPriceCalculator $productPriceCalculator * @param TimezoneInterface $localeDate * @param RuleProductPricesPersistor $pricesPersistor + * @param bool $useWebsiteTimezone */ public function __construct( StoreManagerInterface $storeManager, RuleProductsSelectBuilder $ruleProductsSelectBuilder, ProductPriceCalculator $productPriceCalculator, TimezoneInterface $localeDate, - RuleProductPricesPersistor $pricesPersistor + RuleProductPricesPersistor $pricesPersistor, + bool $useWebsiteTimezone = true ) { $this->storeManager = $storeManager; $this->ruleProductsSelectBuilder = $ruleProductsSelectBuilder; $this->productPriceCalculator = $productPriceCalculator; $this->localeDate = $localeDate; $this->pricesPersistor = $pricesPersistor; + $this->useWebsiteTimezone = $useWebsiteTimezone; } /** @@ -82,11 +91,9 @@ public function execute(int $batchCount, ?int $productId = null, bool $useAdditi $prevKey = null; $storeGroup = $this->storeManager->getGroup($website->getDefaultGroupId()); - $currentDate = $this->localeDate->scopeDate($storeGroup->getDefaultStoreId(), null, true); - $previousDate = (clone $currentDate)->modify('-1 day'); - $previousDate->setTime(23, 59, 59); - $nextDate = (clone $currentDate)->modify('+1 day'); - $nextDate->setTime(0, 0, 0); + $dateInterval = $this->useWebsiteTimezone + ? $this->getDateInterval((int)$storeGroup->getDefaultStoreId()) + : $this->getDateInterval(Store::DEFAULT_STORE_ID); while ($ruleData = $productsStmt->fetch()) { $ruleProductId = $ruleData['product_id']; @@ -107,7 +114,7 @@ public function execute(int $batchCount, ?int $productId = null, bool $useAdditi /** * Build prices for each day */ - foreach ([$previousDate, $currentDate, $nextDate] as $date) { + foreach ($dateInterval as $date) { $time = $date->getTimestamp(); if (($ruleData['from_time'] == 0 || $time >= $ruleData['from_time']) && ($ruleData['to_time'] == 0 || @@ -157,4 +164,21 @@ public function execute(int $batchCount, ?int $productId = null, bool $useAdditi return true; } + + /** + * Retrieve date sequence in store time zone + * + * @param int $storeId + * @return \DateTime[] + */ + private function getDateInterval(int $storeId): array + { + $currentDate = $this->localeDate->scopeDate($storeId, null, true); + $previousDate = (clone $currentDate)->modify('-1 day'); + $previousDate->setTime(23, 59, 59); + $nextDate = (clone $currentDate)->modify('+1 day'); + $nextDate->setTime(0, 0, 0); + + return [$previousDate, $currentDate, $nextDate]; + } } diff --git a/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/SaveAndContinueEditCatalogPriceRuleActionGroup.xml b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/SaveAndContinueEditCatalogPriceRuleActionGroup.xml new file mode 100644 index 0000000000000..cf8499ca1b466 --- /dev/null +++ b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/SaveAndContinueEditCatalogPriceRuleActionGroup.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="SaveAndContinueEditCatalogPriceRuleActionGroup"> + <annotations> + <description>Clicks on Save and Continue Edit. Validates that the Success Message is present and correct on the Admin Catalog Price Rule creation/edit page.</description> + </annotations> + + <waitForElementVisible selector="{{AdminNewCatalogPriceRule.saveAndContinue}}" stepKey="waitForSaveAndContinueEditButton"/> + <click selector="{{AdminNewCatalogPriceRule.saveAndContinue}}" stepKey="saveAndContinueEdit"/> + <see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the rule." stepKey="assertSuccess"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/ReindexRuleProductPriceTest.php b/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/ReindexRuleProductPriceTest.php index 7f22634f9343d..230a6e3860950 100644 --- a/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/ReindexRuleProductPriceTest.php +++ b/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/ReindexRuleProductPriceTest.php @@ -64,7 +64,8 @@ protected function setUp(): void $this->ruleProductsSelectBuilderMock, $this->productPriceCalculatorMock, $this->localeDate, - $this->pricesPersistorMock + $this->pricesPersistorMock, + true ); } diff --git a/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/ReindexRuleProductTest.php b/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/ReindexRuleProductTest.php index ddb6a85ed614a..50f4eb0805ed2 100644 --- a/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/ReindexRuleProductTest.php +++ b/app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/ReindexRuleProductTest.php @@ -21,6 +21,8 @@ class ReindexRuleProductTest extends TestCase { + private const ADMIN_WEBSITE_ID = 0; + /** * @var ReindexRuleProduct */ @@ -57,7 +59,8 @@ protected function setUp(): void $this->resourceMock, $this->activeTableSwitcherMock, $this->tableSwapperMock, - $this->localeDateMock + $this->localeDateMock, + true ); } @@ -85,6 +88,7 @@ public function testExecuteIfRuleWithoutWebsiteIds() public function testExecute() { $websiteId = 3; + $adminTimeZone = 'America/Chicago'; $websiteTz = 'America/Los_Angeles'; $productIds = [ 4 => [$websiteId => 1], @@ -123,10 +127,11 @@ public function testExecute() $ruleMock->expects($this->once())->method('getDiscountAmount')->willReturn(43); $ruleMock->expects($this->once())->method('getStopRulesProcessing')->willReturn(true); - $this->localeDateMock->expects($this->once()) - ->method('getConfigTimezone') - ->with(ScopeInterface::SCOPE_WEBSITE, $websiteId) - ->willReturn($websiteTz); + $this->localeDateMock->method('getConfigTimezone') + ->willReturnMap([ + [ScopeInterface::SCOPE_WEBSITE, self::ADMIN_WEBSITE_ID, $adminTimeZone], + [ScopeInterface::SCOPE_WEBSITE, $websiteId, $websiteTz], + ]); $batchRows = [ [ From 3f75f677009571f84bfa619eb6e545c8d62befad Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Tue, 19 Jan 2021 17:42:54 -0600 Subject: [PATCH 32/38] B2B-1640: Add MFTF test for MC-38222 - Moving MFTF data to data files --- .../ImportExport/Test/Mftf/Data/ImportData.xml | 8 ++++++++ ...AndConfigurableProductsWithAssignedImagesTest.xml | 12 ++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/ImportExport/Test/Mftf/Data/ImportData.xml b/app/code/Magento/ImportExport/Test/Mftf/Data/ImportData.xml index 6160a12223552..5a883af443348 100644 --- a/app/code/Magento/ImportExport/Test/Mftf/Data/ImportData.xml +++ b/app/code/Magento/ImportExport/Test/Mftf/Data/ImportData.xml @@ -8,6 +8,12 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <!-- Common Messages --> + <entity name="ImportCommonMessages"> + <data key="validFile">File is valid! To start import process press "Import" button</data> + <data key="success">Import successfully done</data> + </entity> + <!-- Categories --> <entity name="Import1" type="category"> <data key="name">Import1</data> @@ -60,6 +66,8 @@ <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> <entity name="ImportConfigurable" type="product"> + <data key="fileName">import_configurable_product.csv</data> + <data key="importSummary">Created: 4, Updated: 0, Deleted: 0</data> <data key="name">import-configurable</data> <data key="sku">import-configurable</data> <data key="type_id">configurable</data> diff --git a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml index f8768283dfa2d..a046724f9ac8d 100644 --- a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml +++ b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminImportSimpleAndConfigurableProductsWithAssignedImagesTest.xml @@ -71,14 +71,14 @@ <!-- Import Configurable Product with Simple Child Products & Assert No Errors --> <actionGroup ref="AdminNavigateToImportPageActionGroup" stepKey="navigateToImportPage"/> <actionGroup ref="AdminFillImportFormActionGroup" stepKey="fillImportForm"> - <argument name="importFile" value="import_configurable_product.csv"/> + <argument name="importFile" value="{{ImportConfigurable.fileName}}"/> </actionGroup> <actionGroup ref="AdminClickCheckDataImportActionGroup" stepKey="clickCheckData"/> - <see selector="{{AdminImportValidationMessagesSection.success}}" userInput="File is valid! To start import process press "Import" button" stepKey="seeCheckDataResultMessage"/> + <see selector="{{AdminImportValidationMessagesSection.success}}" userInput="{{ImportCommonMessages.validFile}}" stepKey="seeCheckDataResultMessage"/> <dontSeeElementInDOM selector="{{AdminImportValidationMessagesSection.importErrorList}}" stepKey="dontSeeErrorMessage"/> <actionGroup ref="AdminClickImportActionGroup" stepKey="clickImport"/> - <see selector="{{AdminImportValidationMessagesSection.notice}}" userInput="Created: 4, Updated: 0, Deleted: 0" stepKey="seeNoticeMessage"/> - <see selector="{{AdminImportValidationMessagesSection.messageByType('success')}}" userInput="Import successfully done" stepKey="seeImportMessage"/> + <see selector="{{AdminImportValidationMessagesSection.notice}}" userInput="{{ImportConfigurable.importSummary}}" stepKey="seeNoticeMessage"/> + <see selector="{{AdminImportValidationMessagesSection.messageByType('success')}}" userInput="{{ImportCommonMessages.success}}" stepKey="seeImportMessage"/> <dontSeeElementInDOM selector="{{AdminImportValidationMessagesSection.importErrorList}}" stepKey="dontSeeErrorMessage2"/> <!-- Reindex --> @@ -91,8 +91,8 @@ <actionGroup ref="AdminGridSortColumnDescendingActionGroup" stepKey="sortColumnByIdDescending"> <argument name="columnLabel" value="history_id"/> </actionGroup> - <see userInput="import_configurable_product.csv" selector="{{AdminDataGridTableSection.firstRow}}" stepKey="seeImportedFile"/> - <see userInput="Created: 4, Updated: 0, Deleted: 0" selector="{{AdminDataGridTableSection.firstRow}}" stepKey="seeSummary"/> + <see userInput="{{ImportConfigurable.fileName}}" selector="{{AdminDataGridTableSection.firstRow}}" stepKey="seeImportedFile"/> + <see userInput="{{ImportConfigurable.importSummary}}" selector="{{AdminDataGridTableSection.firstRow}}" stepKey="seeSummary"/> <!-- Admin: Verify Simple Product 1 on Product Index Page --> <actionGroup ref="AssertProductOnAdminGridActionGroup" stepKey="assertSimpleProduct1InAdminGrid"> From 89123706aa430ee2c98fe641f23199351a419638 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 20 Jan 2021 11:15:45 +0200 Subject: [PATCH 33/38] MC-39550: Create automated test for: "Add new website to products using mass product update and run cron." --- .../Model/Attribute/Backend/ConsumerWebsiteAssignTest.php | 2 +- .../Catalog/_files/detach_product_website_quene_data.php | 4 ++-- .../Catalog/_files/update_product_website_quene_data.php | 2 +- .../_files/update_product_website_quene_data_rollback.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Attribute/Backend/ConsumerWebsiteAssignTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Attribute/Backend/ConsumerWebsiteAssignTest.php index e895a886e44e7..0edddd1b34f6f 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Attribute/Backend/ConsumerWebsiteAssignTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Attribute/Backend/ConsumerWebsiteAssignTest.php @@ -90,7 +90,7 @@ protected function setUp(): void } /** - * @return void + * @inheritdoc */ protected function tearDown(): void { diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data.php index ab03ff5bf6b65..e862e95cbd3e4 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/detach_product_website_quene_data.php @@ -35,7 +35,7 @@ $websiteId = (int)$websiteRepository->get('second_website')->getId(); $bulkDescription = __('Update attributes for ' . 1 . ' selected products'); $dataToEncode = [ - 'meta_information' => 'Update website assign', + 'meta_information' => 'Detach website', 'product_ids' => $productIds, 'store_id' => 0, 'website_id' => $websiteId, @@ -51,7 +51,7 @@ 'topic_name' => 'product_action_attribute.website.update', 'serialized_data' => $jsonEncoder->serialize($dataToEncode), 'status' => OperationInterface::STATUS_TYPE_OPEN, - ] + ], ]; $bulkManagement->scheduleBulk( diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data.php index dca8fb26c0b55..6feffc2a5fb3a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data.php @@ -52,7 +52,7 @@ 'topic_name' => 'product_action_attribute.website.update', 'serialized_data' => $jsonEncoder->serialize($dataToEncode), 'status' => OperationInterface::STATUS_TYPE_OPEN, - ] + ], ]; $bulkManagement->scheduleBulk( diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data_rollback.php index 5273947cd28ea..85336635f2e08 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/update_product_website_quene_data_rollback.php @@ -15,4 +15,4 @@ $deleteTopicRelatedMessages->execute('product_action_attribute.website.update'); Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/second_product_simple_rollback.php'); -Resolver::getInstance()->requireDataFixture('Magento/Store/_files/second_website_with_store_group_and_store_rollback.php'); +Resolver::getInstance()->requireDataFixture('Magento/Store/_files/second_website_with_two_stores_rollback.php'); From 8059762db4f3db35449a1c681e61f1c9c777238d Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 20 Jan 2021 13:20:18 +0200 Subject: [PATCH 34/38] MC-39722: Create automated test for: "Dropdown attribute in flat product" --- .../Indexer/Product/Flat/Action/FullTest.php | 144 +++++++++++++----- 1 file changed, 107 insertions(+), 37 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/FullTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/FullTest.php index 4313f95f24a8e..1fa6c1a8889b8 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/FullTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/FullTest.php @@ -3,40 +3,49 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Catalog\Model\Indexer\Product\Flat\Action; use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Block\Product\ListProduct; use Magento\Catalog\Model\CategoryFactory; use Magento\Catalog\Model\Indexer\Product\Flat\Processor; use Magento\Catalog\Model\Indexer\Product\Flat\State; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory; +use Magento\Catalog\Model\ResourceModel\Product\Flat as FlatResource; use Magento\CatalogSearch\Model\Indexer\Fulltext; +use Magento\Eav\Api\AttributeOptionManagementInterface; use Magento\Framework\Indexer\IndexerRegistry; +use Magento\Framework\ObjectManagerInterface; use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; -use Magento\TestFramework\ObjectManager; +use Magento\TestFramework\Indexer\TestCase; /** * Full reindex Test */ -class FullTest extends \Magento\TestFramework\Indexer\TestCase +class FullTest extends TestCase { - /** - * @var State - */ - protected $_state; + /** @var State */ + protected $state; - /** - * @var Processor - */ - protected $_processor; + /** @var Processor */ + protected $processor; - /** - * @var ObjectManager - */ + /** @var ObjectManagerInterface */ private $objectManager; + /** @var FlatResource */ + private $flatResource; + + /** @var AttributeOptionManagementInterface */ + private $optionManagement; + + /** @var ProductRepositoryInterface */ + private $productRepository; + /** * @inheritdoc */ @@ -58,9 +67,14 @@ public static function setUpBeforeClass(): void */ protected function setUp(): void { + parent::setUp(); + $this->objectManager = Bootstrap::getObjectManager(); - $this->_state = $this->objectManager->get(State::class); - $this->_processor = $this->objectManager->get(Processor::class); + $this->state = $this->objectManager->get(State::class); + $this->processor = $this->objectManager->get(Processor::class); + $this->flatResource = $this->objectManager->get(FlatResource::class); + $this->optionManagement = $this->objectManager->get(AttributeOptionManagementInterface::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); } /** @@ -68,11 +82,13 @@ protected function setUp(): void * @magentoAppIsolation enabled * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * + * @return void */ - public function testReindexAll() + public function testReindexAll(): void { - $this->assertTrue($this->_state->isFlatEnabled()); - $this->_processor->reindexAll(); + $this->assertTrue($this->state->isFlatEnabled()); + $this->processor->reindexAll(); $categoryFactory = $this->objectManager->get(CategoryFactory::class); $listProduct = $this->objectManager->get(ListProduct::class); @@ -98,11 +114,13 @@ public function testReindexAll() * @magentoDataFixture Magento/Catalog/_files/product_simple_multistore.php * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 * @magentoConfigFixture fixturestore_store catalog/frontend/flat_catalog_product 1 + * + * @return void */ - public function testReindexAllMultipleStores() + public function testReindexAllMultipleStores(): void { - $this->assertTrue($this->_state->isFlatEnabled()); - $this->_processor->reindexAll(); + $this->assertTrue($this->state->isFlatEnabled()); + $this->processor->reindexAll(); /** @var ProductCollectionFactory $productCollectionFactory */ $productCollectionFactory = $this->objectManager->create(ProductCollectionFactory::class); @@ -116,24 +134,76 @@ public function testReindexAllMultipleStores() $store->getId() => 'StoreTitle', ]; - foreach ($expectedData as $storeId => $productName) { - $storeManager->setCurrentStore($storeId); - $productCollection = $productCollectionFactory->create(); - - $this->assertTrue( - $productCollection->isEnabledFlat(), - 'Flat should be enabled for product collection.' - ); + try { + foreach ($expectedData as $storeId => $productName) { + $storeManager->setCurrentStore($storeId); + $productCollection = $productCollectionFactory->create(); + + $this->assertTrue( + $productCollection->isEnabledFlat(), + 'Flat should be enabled for product collection.' + ); + + $productCollection->addIdFilter(1)->addAttributeToSelect(ProductInterface::NAME); + + $this->assertEquals( + $productName, + $productCollection->getFirstItem()->getName(), + 'Wrong product name specified per store.' + ); + } + } finally { + $storeManager->setCurrentStore($currentStore); + } + } - $productCollection->addIdFilter(1)->addAttributeToSelect(ProductInterface::NAME); + /** + * @magentoDbIsolation disabled + * + * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 + * @magentoDataFixture Magento/Catalog/_files/dropdown_attribute.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testCheckDropdownAttributeInFlat(): void + { + $attributeCode = 'dropdown_attribute'; + $options = $this->optionManagement->getItems($this->flatResource->getTypeId(), $attributeCode); + $attributeValue = $options[1]->getValue(); + $this->updateProduct('simple2', $attributeCode, $attributeValue); + $this->processor->reindexAll(); + $this->assertFlatColumnValue($attributeCode, $attributeValue); + } - $this->assertEquals( - $productName, - $productCollection->getFirstItem()->getName(), - 'Wrong product name specified per store.' - ); - } + /** + * Assert if column exist and column value in flat table + * + * @param string $attributeCode + * @param string $value + * @return void + */ + private function assertFlatColumnValue(string $attributeCode, string $value): void + { + $connect = $this->flatResource->getConnection(); + $tableName = $this->flatResource->getFlatTableName(); + $this->assertTrue($connect->tableColumnExists($tableName, $attributeCode)); + $select = $connect->select()->from($tableName, $attributeCode); + $this->assertEquals($value, $connect->fetchOne($select)); + } - $storeManager->setCurrentStore($currentStore); + /** + * Update product + * + * @param string $sku + * @param string $attributeCode + * @param string $value + * @return void + */ + private function updateProduct(string $sku, string $attributeCode, string $value): void + { + $product = $this->productRepository->get($sku); + $product->setData($attributeCode, $value); + $this->productRepository->save($product); } } From 9f5e7060164a7ae3099a850682433c7bb6de3426 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 20 Jan 2021 15:27:09 +0200 Subject: [PATCH 35/38] MC-40081: Create automated test for: "Disable flat product" --- .../Indexer/Product/Flat/ProcessorTest.php | 120 ++++++++++++++---- 1 file changed, 96 insertions(+), 24 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/ProcessorTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/ProcessorTest.php index 5c376517ed143..5b9266dc11371 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/ProcessorTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/ProcessorTest.php @@ -3,33 +3,58 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Catalog\Model\Indexer\Product\Flat; use Magento\Catalog\Model\Product\Attribute\Repository; +use Magento\Framework\Indexer\StateInterface; +use Magento\Framework\Indexer\StateInterfaceFactory; +use Magento\Indexer\Model\ResourceModel\Indexer\State as StateResource; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Indexer\TestCase; +use Magento\TestFramework\ObjectManager; /** * Integration tests for \Magento\Catalog\Model\Indexer\Product\Flat\Processor. */ -class ProcessorTest extends \Magento\TestFramework\Indexer\TestCase +class ProcessorTest extends TestCase { /** - * @var \Magento\Catalog\Model\Indexer\Product\Flat\State + * @var ObjectManager */ - protected $_state; + private $objectManager; /** - * @var \Magento\Catalog\Model\Indexer\Product\Flat\Processor + * @var State */ - protected $_processor; + private $state; + /** + * @var Processor + */ + private $processor; + + /** + * @var StateResource + */ + private $stateResource; + + /** + * @var StateInterfaceFactory; + */ + private $stateFactory; + + /** + * @inheritdoc + */ protected function setUp(): void { - $this->_state = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Catalog\Model\Indexer\Product\Flat\State::class - ); - $this->_processor = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Catalog\Model\Indexer\Product\Flat\Processor::class - ); + $this->objectManager = Bootstrap::getObjectManager(); + $this->state = $this->objectManager->get(State::class); + $this->processor = $this->objectManager->get(Processor::class); + $this->stateResource = $this->objectManager->get(StateResource::class); + $this->stateFactory = $this->objectManager->get(StateInterfaceFactory::class); } /** @@ -37,11 +62,13 @@ protected function setUp(): void * @magentoAppIsolation enabled * @magentoAppArea adminhtml * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 + * + * @return void */ - public function testEnableProductFlat() + public function testEnableProductFlat(): void { - $this->assertTrue($this->_state->isFlatEnabled()); - $this->assertTrue($this->_processor->getIndexer()->isInvalid()); + $this->assertTrue($this->state->isFlatEnabled()); + $this->assertTrue($this->processor->getIndexer()->isInvalid()); } /** @@ -50,8 +77,10 @@ public function testEnableProductFlat() * @magentoAppArea adminhtml * @magentoDataFixture Magento/Catalog/_files/multiple_products.php * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 + * + * @return void */ - public function testSaveAttribute() + public function testSaveAttribute(): void { /** @var $product \Magento\Catalog\Model\Product */ $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( @@ -61,8 +90,7 @@ public function testSaveAttribute() /** @var \Magento\Catalog\Model\ResourceModel\Product $productResource */ $productResource = $product->getResource(); $productResource->getAttribute('sku')->setData('used_for_sort_by', 1)->save(); - - $this->assertTrue($this->_processor->getIndexer()->isInvalid()); + $this->assertTrue($this->processor->getIndexer()->isInvalid()); } /** @@ -71,8 +99,10 @@ public function testSaveAttribute() * @magentoAppArea adminhtml * @magentoDataFixture Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat.php * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 + * + * @return void */ - public function testDeleteAttribute() + public function testDeleteAttribute(): void { /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $model */ $model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() @@ -83,8 +113,7 @@ public function testDeleteAttribute() $productAttrubute = $productAttributeRepository->get('flat_attribute'); $productAttributeId = $productAttrubute->getAttributeId(); $model->load($productAttributeId)->delete(); - - $this->assertTrue($this->_processor->getIndexer()->isInvalid()); + $this->assertTrue($this->processor->getIndexer()->isInvalid()); } /** @@ -93,10 +122,12 @@ public function testDeleteAttribute() * @magentoAppArea adminhtml * @magentoDataFixture Magento/Store/_files/core_fixturestore.php * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 + * + * @return void */ - public function testAddNewStore() + public function testAddNewStore(): void { - $this->assertTrue($this->_processor->getIndexer()->isInvalid()); + $this->assertTrue($this->processor->getIndexer()->isInvalid()); } /** @@ -104,8 +135,10 @@ public function testAddNewStore() * @magentoAppIsolation enabled * @magentoAppArea adminhtml * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 + * + * @return void */ - public function testAddNewStoreGroup() + public function testAddNewStoreGroup(): void { /** @var \Magento\Store\Model\Group $storeGroup */ $storeGroup = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( @@ -115,6 +148,45 @@ public function testAddNewStoreGroup() ['website_id' => 1, 'name' => 'New Store Group', 'root_category_id' => 2, 'group_id' => null] ); $storeGroup->save(); - $this->assertTrue($this->_processor->getIndexer()->isInvalid()); + $this->assertTrue($this->processor->getIndexer()->isInvalid()); + } + + /** + * @magentoDbIsolation disabled + * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 0 + * + * @return void + */ + public function testReindexAllWithProductFlatDisabled(): void + { + $this->updateIndexerStatus(); + $this->processor->reindexAll(); + $state = $this->getIndexerState(); + $this->assertEquals(StateInterface::STATUS_INVALID, $state->getStatus()); + } + + /** + * Update status for indexer + * + * @param string $status + * @return void + */ + private function updateIndexerStatus(string $status = StateInterface::STATUS_INVALID): void + { + $state = $this->getIndexerState(); + $state->setStatus($status); + $this->stateResource->save($state); + } + + /** + * Get Indexer state + * + * @return StateInterface + */ + private function getIndexerState(): StateInterface + { + $state = $this->stateFactory->create(); + + return $state->loadByIndexer(State::INDEXER_ID); } } From bc14738eadea851875ac30eca2a2f1c6f6cfacd0 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 20 Jan 2021 18:10:13 +0200 Subject: [PATCH 36/38] MC-39722: Create automated test for: "Dropdown attribute in flat product" --- .../Model/Indexer/Product/Flat/Action/FullTest.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/FullTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/FullTest.php index 1fa6c1a8889b8..bc96b30d55c04 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/FullTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/FullTest.php @@ -29,10 +29,10 @@ class FullTest extends TestCase { /** @var State */ - protected $state; + private $state; /** @var Processor */ - protected $processor; + private $processor; /** @var ObjectManagerInterface */ private $objectManager; @@ -46,6 +46,9 @@ class FullTest extends TestCase /** @var ProductRepositoryInterface */ private $productRepository; + /** @var Full */ + private $action; + /** * @inheritdoc */ @@ -75,6 +78,7 @@ protected function setUp(): void $this->flatResource = $this->objectManager->get(FlatResource::class); $this->optionManagement = $this->objectManager->get(AttributeOptionManagementInterface::class); $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->action = $this->objectManager->get(Full::class); } /** @@ -172,7 +176,7 @@ public function testCheckDropdownAttributeInFlat(): void $options = $this->optionManagement->getItems($this->flatResource->getTypeId(), $attributeCode); $attributeValue = $options[1]->getValue(); $this->updateProduct('simple2', $attributeCode, $attributeValue); - $this->processor->reindexAll(); + $this->action->execute(); $this->assertFlatColumnValue($attributeCode, $attributeValue); } From 152b41b3f8bd6bc410e0b20ede03cfaeb1143d87 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Thu, 21 Jan 2021 13:12:00 +0200 Subject: [PATCH 37/38] MC-23915: Revert 23915 because it caused static tests failure --- .../Order/Creditmemo/Grid/Collection.php | 28 ----------- .../Creditmemo/Order/Grid/Collection.php | 28 ----------- .../sales_order_creditmemo_grid.xml | 4 +- .../sales_order_view_creditmemo_grid.xml | 4 +- .../Order/Creditmemo/Grid/CollectionTest.php | 46 ------------------- .../Creditmemo/Order/Grid/CollectionTest.php | 46 ------------------- 6 files changed, 4 insertions(+), 152 deletions(-) delete mode 100644 dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/CollectionTest.php delete mode 100644 dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/CollectionTest.php diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/Collection.php index 46e26c97556e6..6960b34b1b32f 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/Collection.php +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/Collection.php @@ -33,32 +33,4 @@ public function __construct( ) { parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); } - - /** - * @inheritDoc - */ - protected function _translateCondition($field, $condition) - { - if ($field !== 'order_currency_code' - && !isset($this->_map['fields'][$field]) - ) { - $this->_map['fields'][$field] = 'main_table.' . $field; - } - - return parent::_translateCondition($field, $condition); - } - - /** - * @inheritDoc - */ - protected function _renderFiltersBefore() - { - $this->getSelect()->joinLeft( - ['cgf' => $this->getTable('sales_order_grid')], - 'main_table.order_id = cgf.entity_id', - [ - 'order_currency_code' => 'order_currency_code', - ] - ); - } } diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/Collection.php index 4d446b6c7620d..eab3998eebcbd 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/Collection.php +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/Collection.php @@ -33,32 +33,4 @@ public function __construct( ) { parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); } - - /** - * @inheritDoc - */ - protected function _translateCondition($field, $condition) - { - if ($field !== 'order_currency_code' - && !isset($this->_map['fields'][$field]) - ) { - $this->_map['fields'][$field] = 'main_table.' . $field; - } - - return parent::_translateCondition($field, $condition); - } - - /** - * @inheritDoc - */ - protected function _renderFiltersBefore() - { - $this->getSelect()->joinLeft( - ['cgf' => $this->getTable('sales_order_grid')], - 'main_table.order_id = cgf.entity_id', - [ - 'order_currency_code' => 'order_currency_code', - ] - ); - } } diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_creditmemo_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_creditmemo_grid.xml index a7e79f23b1cca..1fc8d41ce0900 100644 --- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_creditmemo_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_creditmemo_grid.xml @@ -194,14 +194,14 @@ <visible>false</visible> </settings> </column> - <column name="subtotal" class="Magento\Sales\Ui\Component\Listing\Column\PurchasedPrice"> + <column name="subtotal" class="Magento\Sales\Ui\Component\Listing\Column\Price"> <settings> <filter>textRange</filter> <label translate="true">Subtotal</label> <visible>false</visible> </settings> </column> - <column name="shipping_and_handling" class="Magento\Sales\Ui\Component\Listing\Column\PurchasedPrice"> + <column name="shipping_and_handling" class="Magento\Sales\Ui\Component\Listing\Column\Price"> <settings> <filter>textRange</filter> <label translate="true">Shipping & Handling</label> diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml index 16a7e00b24bb3..09be15c5a3cf9 100644 --- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml @@ -207,14 +207,14 @@ <visible>false</visible> </settings> </column> - <column name="subtotal" class="Magento\Sales\Ui\Component\Listing\Column\PurchasedPrice"> + <column name="subtotal" class="Magento\Sales\Ui\Component\Listing\Column\Price"> <settings> <filter>textRange</filter> <label translate="true">Subtotal</label> <visible>false</visible> </settings> </column> - <column name="shipping_and_handling" class="Magento\Sales\Ui\Component\Listing\Column\PurchasedPrice"> + <column name="shipping_and_handling" class="Magento\Sales\Ui\Component\Listing\Column\Price"> <settings> <filter>textRange</filter> <label translate="true">Shipping & Handling</label> diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/CollectionTest.php deleted file mode 100644 index 4a96a381309db..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/CollectionTest.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Sales\Model\ResourceModel\Order\Creditmemo\Grid; - -use Magento\Framework\ObjectManagerInterface; -use Magento\TestFramework\Helper\Bootstrap; -use PHPUnit\Framework\TestCase; - -/** - * Test Magento\Sales\Model\ResourceModel\Order\Creditmemo\Grid - */ -class CollectionTest extends TestCase -{ - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $this->objectManager = Bootstrap::getObjectManager(); - } - - /** - * @magentoDataFixture Magento/Sales/_files/creditmemo_list.php - * - * @return void - */ - public function testCollectionOrderCurrencyCodeExist(): void - { - /** @var $collection Collection */ - $collection = $this->objectManager->get(Collection::class); - $collection->addFieldToFilter('increment_id', ['eq' => '456']); - foreach ($collection as $item) { - $this->assertNotNull($item->getOrderCurrencyCode()); - } - } -} diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/CollectionTest.php deleted file mode 100644 index 0b7908a122293..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/CollectionTest.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\Sales\Model\ResourceModel\Order\Creditmemo\Order\Grid; - -use Magento\Framework\ObjectManagerInterface; -use Magento\TestFramework\Helper\Bootstrap; -use PHPUnit\Framework\TestCase; - -/** - * Test Magento\Sales\Model\ResourceModel\Order\Creditmemo\Grid\Order\Grid - */ -class CollectionTest extends TestCase -{ - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $this->objectManager = Bootstrap::getObjectManager(); - } - - /** - * @magentoDataFixture Magento/Sales/_files/creditmemo_list.php - * - * @return void - */ - public function testCollectionOrderCurrencyCodeExist(): void - { - /** @var $collection Collection */ - $collection = $this->objectManager->get(Collection::class); - $collection->addFieldToFilter('increment_id', ['eq' => '456']); - foreach ($collection as $item) { - $this->assertNotNull($item->getOrderCurrencyCode()); - } - } -} From 7b9f198f703b3707ebf03d03cdc9ac1f66abe118 Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Thu, 21 Jan 2021 10:37:03 -0600 Subject: [PATCH 38/38] B2B-1640: Add MFTF test for MC-38222 - Removing gift card references from import csv --- .../tests/_data/import_configurable_product.csv | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dev/tests/acceptance/tests/_data/import_configurable_product.csv b/dev/tests/acceptance/tests/_data/import_configurable_product.csv index 6eaf2a2429a74..880e0bfb64c2e 100644 --- a/dev/tests/acceptance/tests/_data/import_configurable_product.csv +++ b/dev/tests/acceptance/tests/_data/import_configurable_product.csv @@ -1,5 +1,5 @@ -sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,deferred_stock_update,use_config_deferred_stock_update,related_skus,related_position,crosssell_skus,crosssell_position,upsell_skus,upsell_position,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,bundle_shipment_type,giftcard_type,giftcard_allow_open_amount,giftcard_open_amount_min,giftcard_open_amount_max,giftcard_amount,use_config_is_redeemable,giftcard_is_redeemable,use_config_lifetime,giftcard_lifetime,use_config_allow_message,giftcard_allow_message,use_config_email_template,giftcard_email_template,associated_skus,downloadable_links,downloadable_samples,configurable_variations,configurable_variation_labels -import-simple1,,Default,simple,Default Category/Import1,base,import-simple1,,,12,1,Taxable Goods,Not Visible Individually,12,,,,import-simple1,Conf11,Conf11,Conf11 ,/m/a/magento-logo.png,Magento Logo,/m/a/magento-logo.png,Magento Logo,/m/a/magento-logo.png,Magento Logo,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,No,,,,,,,,,"import_attribute1=option1,gift_wrapping_available=Yes",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,/m/a/magento-logo.png,Magento Logo,,,,,,,,,,,,,,,,,,,,,,,,,, -import-simple2,,Default,simple,Default Category/Import1,base,import-simple2,,,12,1,Taxable Goods,Not Visible Individually,15,,,,import-simple2,Conf11,Conf11,Conf11 ,/t/e/test_image.jpg,Test Image,/t/e/test_image.jpg,Test Image,/t/e/test_image.jpg,Test Image,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,No,,,,,,,,,"import_attribute1=option2,gift_wrapping_available=Yes",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,/t/e/test_image.jpg,Test Image,,,,,,,,,,,,,,,,,,,,,,,,,, -import-simple3,,Default,simple,Default Category/Import1,base,import-simple3,,,12,1,Taxable Goods,Not Visible Individually,10,,,,import-simple3,Conf11,Conf11,Conf11 ,,,,,,,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,No,,,,,,,,,"import_attribute1=option3,gift_wrapping_available=Yes",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -import-configurable,,Default,configurable,Default Category/Import1,base,import-configurable,,,12,1,Taxable Goods,"Catalog, Search",,,,,import-configurable,Conf11,Conf11,Conf11 ,,,,,,,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,Use config,,,,,,,Use config,,gift_wrapping_available=Use config,0,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,,",,",,,,,,,,,,,,,,,,,,,,,,,,,"sku=import-simple1,import_attribute1=option1|sku=import-simple2,import_attribute1=option2|sku=import-simple3,import_attribute1=option3",import_attribute1=import_attribute1 \ No newline at end of file +sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,deferred_stock_update,use_config_deferred_stock_update,related_skus,related_position,crosssell_skus,crosssell_position,upsell_skus,upsell_position,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,bundle_shipment_type,associated_skus,downloadable_links,downloadable_samples,configurable_variations,configurable_variation_labels +import-simple1,,Default,simple,Default Category/Import1,base,import-simple1,,,12,1,Taxable Goods,Not Visible Individually,12,,,,import-simple1,Conf11,Conf11,Conf11 ,/m/a/magento-logo.png,Magento Logo,/m/a/magento-logo.png,Magento Logo,/m/a/magento-logo.png,Magento Logo,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,No,,,,,,,,,"import_attribute1=option1,gift_wrapping_available=Yes",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,/m/a/magento-logo.png,Magento Logo,,,,,,,,,,,,, +import-simple2,,Default,simple,Default Category/Import1,base,import-simple2,,,12,1,Taxable Goods,Not Visible Individually,15,,,,import-simple2,Conf11,Conf11,Conf11 ,/t/e/test_image.jpg,Test Image,/t/e/test_image.jpg,Test Image,/t/e/test_image.jpg,Test Image,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,No,,,,,,,,,"import_attribute1=option2,gift_wrapping_available=Yes",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,/t/e/test_image.jpg,Test Image,,,,,,,,,,,,, +import-simple3,,Default,simple,Default Category/Import1,base,import-simple3,,,12,1,Taxable Goods,Not Visible Individually,10,,,,import-simple3,Conf11,Conf11,Conf11 ,,,,,,,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,No,,,,,,,,,"import_attribute1=option3,gift_wrapping_available=Yes",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,,,,,,,,,,,,,,, +import-configurable,,Default,configurable,Default Category/Import1,base,import-configurable,,,12,1,Taxable Goods,"Catalog, Search",,,,,import-configurable,Conf11,Conf11,Conf11 ,,,,,,,,,"10/5/20, 4:58 PM","10/5/20, 4:58 PM",,,Block after Info Column,,,,Use config,,,,,,,Use config,,gift_wrapping_available=Use config,0,0,1,0,0,1,1,1,10000,1,1,1,1,1,1,1,1,1,0,0,0,0,1,,,,,,,,",,",,,,,,,,,,,,"sku=import-simple1,import_attribute1=option1|sku=import-simple2,import_attribute1=option2|sku=import-simple3,import_attribute1=option3",import_attribute1=import_attribute1 \ No newline at end of file