From ccc83b21a25aee282be830891b5708017e992211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Szubert?= Date: Wed, 7 Oct 2020 10:03:28 +0200 Subject: [PATCH 01/41] Fix #30296 - Wrong ip value in sendfriend_log table --- .../Model/ResourceModel/SendFriend.php | 10 +++--- .../SendFriend/Model/SendFriendTest.php | 9 +++-- .../HTTP/PhpEnvironment/RemoteAddress.php | 10 +++--- .../Unit/PhpEnvironment/RemoteAddressTest.php | 33 +++++++------------ 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php b/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php index 618d941f7047e..468fb2ed1af66 100644 --- a/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php +++ b/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php @@ -6,10 +6,6 @@ namespace Magento\SendFriend\Model\ResourceModel; /** - * SendFriend Log Resource Model - * - * @author Magento Core Team - * * @api * @since 100.0.2 */ @@ -32,6 +28,7 @@ protected function _construct() * @param int $ip * @param int $startTime * @param int $websiteId + * * @return int * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -58,14 +55,16 @@ public function getSendCount($object, $ip, $startTime, $websiteId = null) * @param int $ip * @param int $startTime * @param int $websiteId + * * @return $this */ public function addSendItem($ip, $startTime, $websiteId) { $this->getConnection()->insert( $this->getMainTable(), - ['ip' => ip2long($ip), 'time' => $startTime, 'website_id' => $websiteId] + ['ip' => $ip, 'time' => $startTime, 'website_id' => $websiteId] ); + return $this; } @@ -73,6 +72,7 @@ public function addSendItem($ip, $startTime, $websiteId) * Delete Old logs * * @param int $time + * * @return $this */ public function deleteLogsBefore($time) diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php b/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php index 7013346fd76e2..9117f088e6b8d 100644 --- a/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php +++ b/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php @@ -13,7 +13,7 @@ use Magento\SendFriend\Helper\Data as SendFriendHelper; use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; -use Zend\Stdlib\Parameters; +use Laminas\Stdlib\Parameters; /** * Class checks send friend model behavior @@ -55,6 +55,7 @@ protected function setUp(): void * @param array $sender * @param array $recipients * @param string|bool $expectedResult + * * @return void */ public function testValidate(array $sender, array $recipients, $expectedResult): void @@ -185,11 +186,11 @@ public function testisExceedLimitByCookies(): void * @magentoDataFixture Magento/SendFriend/_files/sendfriend_log_record_half_hour_before.php * * @magentoDbIsolation disabled + * * @return void */ public function testisExceedLimitByIp(): void { - $this->markTestSkipped('Blocked by MC-31968'); $parameters = $this->objectManager->create(Parameters::class); $parameters->set('REMOTE_ADDR', '127.0.0.1'); $this->request->setServer($parameters); @@ -197,10 +198,11 @@ public function testisExceedLimitByIp(): void } /** - * Check result + * Check test result * * @param array|bool $expectedResult * @param array|bool $result + * * @return void */ private function checkResult($expectedResult, $result): void @@ -217,6 +219,7 @@ private function checkResult($expectedResult, $result): void * * @param array $sender * @param array $recipients + * * @return void */ private function prepareData(array $sender, array $recipients): void diff --git a/lib/internal/Magento/Framework/HTTP/PhpEnvironment/RemoteAddress.php b/lib/internal/Magento/Framework/HTTP/PhpEnvironment/RemoteAddress.php index dfe4b759e85be..c505c82789f81 100644 --- a/lib/internal/Magento/Framework/HTTP/PhpEnvironment/RemoteAddress.php +++ b/lib/internal/Magento/Framework/HTTP/PhpEnvironment/RemoteAddress.php @@ -120,7 +120,7 @@ function (string $ip) { public function getRemoteAddress(bool $ipToLong = false) { if ($this->remoteAddress !== null) { - return $this->remoteAddress; + return $ipToLong ? ip2long($this->remoteAddress) : $this->remoteAddress; } $remoteAddress = $this->readAddress(); @@ -135,11 +135,11 @@ public function getRemoteAddress(bool $ipToLong = false) $this->remoteAddress = false; return false; - } else { - $this->remoteAddress = $remoteAddress; - - return $ipToLong ? ip2long($this->remoteAddress) : $this->remoteAddress; } + + $this->remoteAddress = $remoteAddress; + + return $ipToLong ? ip2long($this->remoteAddress) : $this->remoteAddress; } /** diff --git a/lib/internal/Magento/Framework/HTTP/Test/Unit/PhpEnvironment/RemoteAddressTest.php b/lib/internal/Magento/Framework/HTTP/Test/Unit/PhpEnvironment/RemoteAddressTest.php index 25f665ed70e84..20aafb797ce0e 100644 --- a/lib/internal/Magento/Framework/HTTP/Test/Unit/PhpEnvironment/RemoteAddressTest.php +++ b/lib/internal/Magento/Framework/HTTP/Test/Unit/PhpEnvironment/RemoteAddressTest.php @@ -9,13 +9,10 @@ use Magento\Framework\App\Request\Http as HttpRequest; use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; /** - * Test for - * * @see RemoteAddress */ class RemoteAddressTest extends TestCase @@ -23,24 +20,17 @@ class RemoteAddressTest extends TestCase /** * @var MockObject|HttpRequest */ - protected $_request; - - /** - * @var ObjectManager - */ - protected $_objectManager; + private $requestMock; /** * @inheritdoc */ protected function setUp(): void { - $this->_request = $this->getMockBuilder(HttpRequest::class) + $this->requestMock = $this->getMockBuilder(HttpRequest::class) ->disableOriginalConstructor() - ->setMethods(['getServer']) + ->onlyMethods(['getServer']) ->getMock(); - - $this->_objectManager = new ObjectManager($this); } /** @@ -49,6 +39,7 @@ protected function setUp(): void * @param string|bool $expected * @param bool $ipToLong * @param string[]|null $trustedProxies + * * @return void * @dataProvider getRemoteAddressProvider */ @@ -59,18 +50,16 @@ public function testGetRemoteAddress( bool $ipToLong, array $trustedProxies = null ): void { - $remoteAddress = $this->_objectManager->getObject( - RemoteAddress::class, - [ - 'httpRequest' => $this->_request, - 'alternativeHeaders' => $alternativeHeaders, - 'trustedProxies' => $trustedProxies, - ] + $remoteAddress = new RemoteAddress( + $this->requestMock, + $alternativeHeaders, + $trustedProxies ); - $this->_request->expects($this->any()) - ->method('getServer') + $this->requestMock->method('getServer') ->willReturnMap($serverValueMap); + // Check twice to verify if internal variable is cached correctly + $this->assertEquals($expected, $remoteAddress->getRemoteAddress($ipToLong)); $this->assertEquals($expected, $remoteAddress->getRemoteAddress($ipToLong)); } From e9e951d639b0f8eee1454385eaa24f628b4428c5 Mon Sep 17 00:00:00 2001 From: IvanPletnyov Date: Wed, 7 Oct 2020 11:36:45 +0300 Subject: [PATCH 02/41] MC-37102: Create automated test for "Create customer, with 2 websites and with different allowed countries" --- .../CreateAccountWithAddressTest.php | 113 ++++++++++++++++++ .../Model/Address/CreateAddressTest.php | 17 +++ 2 files changed, 130 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountWithAddressTest.php diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountWithAddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountWithAddressTest.php new file mode 100644 index 0000000000000..351c84680389b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountWithAddressTest.php @@ -0,0 +1,113 @@ +objectManager = Bootstrap::getObjectManager(); + $this->accountManagement = $this->objectManager->get(AccountManagementInterface::class); + $this->customerFactory = $this->objectManager->get(CustomerInterfaceFactory::class); + $this->customerRepository = $this->objectManager->get(CustomerRepositoryInterface::class); + $this->addressFactory = $this->objectManager->get(AddressInterfaceFactory::class); + $this->registry = $this->objectManager->get(Registry::class); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + if ($this->customer instanceof CustomerInterface) { + $this->registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', true); + $this->customerRepository->delete($this->customer); + $this->registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', false); + } + + parent::tearDown(); + } + + /** + * @magentoDataFixture Magento/Store/_files/second_website_with_store_group_and_store.php + * @magentoConfigFixture default_store general/country/allow BD,BB,AF + * @magentoConfigFixture fixture_second_store_store general/country/allow AS,BM + * @return void + */ + public function testCreateNewCustomerWithAddress(): void + { + $availableCountry = 'BD'; + $address = $this->addressFactory->create(); + $address->setCountryId($availableCountry) + ->setPostcode('75477') + ->setRegionId(1) + ->setStreet(['Green str, 67']) + ->setTelephone('3468676') + ->setCity('CityM') + ->setFirstname('John') + ->setLastname('Smith') + ->setIsDefaultShipping(true) + ->setIsDefaultBilling(true); + $customerEntity = $this->customerFactory->create(); + $customerEntity->setEmail('test@example.com') + ->setFirstname('John') + ->setLastname('Smith') + ->setStoreId(1); + $customerEntity->setAddresses([$address]); + $this->customer = $this->accountManagement->createAccount($customerEntity); + $this->assertCount(1, $this->customer->getAddresses(), 'The available address wasn\'t saved.'); + $this->assertSame( + $availableCountry, + $this->customer->getAddresses()[0]->getCountryId(), + 'The address was saved with disallowed country.' + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/Address/CreateAddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/Address/CreateAddressTest.php index eb638eeb329aa..79f8b1466d8d3 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/Address/CreateAddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/Address/CreateAddressTest.php @@ -424,6 +424,23 @@ public function testAddressCreatedWithGroupAssignByVatIdWithError(): void $this->assertEquals(2, $this->getCustomerGroupId('customer5@example.com')); } + /** + * @magentoDataFixture Magento/Customer/_files/customer_no_address.php + * @magentoDataFixture Magento/Store/_files/second_website_with_store_group_and_store.php + * @magentoConfigFixture default_store general/country/allow BD,BB,AF + * @magentoConfigFixture fixture_second_store_store general/country/allow AS,BM + * + * @return void + */ + public function testCreateAvailableAddress(): void + { + $countryId = 'BB'; + $addressData = array_merge(self::STATIC_CUSTOMER_ADDRESS_DATA, [AddressInterface::COUNTRY_ID => $countryId]); + $customer = $this->customerRepository->get('customer5@example.com'); + $address = $this->createAddress((int)$customer->getId(), $addressData); + $this->assertSame($countryId, $address->getCountryId()); + } + /** * Create customer address with provided address data. * From bc53649c4aaa7cf51ab32dc7fa1000c79263d4ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Szubert?= Date: Wed, 7 Oct 2020 23:05:07 +0200 Subject: [PATCH 03/41] Fix #30296 - fix retrieving send count by ip, add verification of ip conversion into int to integration test --- .../Model/ResourceModel/SendFriend.php | 2 +- .../Magento/SendFriend/Model/SendFriendTest.php | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php b/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php index 468fb2ed1af66..edb572dfdd4d1 100644 --- a/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php +++ b/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php @@ -43,7 +43,7 @@ public function getSendCount($object, $ip, $startTime, $websiteId = null) AND time>=:time AND website_id=:website_id' ); - $bind = ['ip' => ip2long($ip), 'time' => $startTime, 'website_id' => (int)$websiteId]; + $bind = ['ip' => $ip, 'time' => $startTime, 'website_id' => (int)$websiteId]; $row = $connection->fetchRow($select, $bind); return $row['count']; diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php b/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php index 9117f088e6b8d..6098883959dd3 100644 --- a/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php +++ b/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php @@ -28,6 +28,9 @@ class SendFriendTest extends TestCase /** @var SendFriend */ private $sendFriend; + /** @var ResourceModel\SendFriend */ + private $sendFriendResource; + /** @var CookieManagerInterface */ private $cookieManager; @@ -43,6 +46,7 @@ protected function setUp(): void $this->objectManager = Bootstrap::getObjectManager(); $this->sendFriend = $this->objectManager->get(SendFriendFactory::class)->create(); + $this->sendFriendResource = $this->objectManager->get(ResourceModel\SendFriend::class); $this->cookieManager = $this->objectManager->get(CookieManagerInterface::class); $this->request = $this->objectManager->get(RequestInterface::class); } @@ -191,10 +195,21 @@ public function testisExceedLimitByCookies(): void */ public function testisExceedLimitByIp(): void { + $remoteAddr = '127.0.0.1'; $parameters = $this->objectManager->create(Parameters::class); - $parameters->set('REMOTE_ADDR', '127.0.0.1'); + $parameters->set('REMOTE_ADDR', $remoteAddr); $this->request->setServer($parameters); $this->assertTrue($this->sendFriend->isExceedLimit()); + // Verify that ip is saved correctly as integer value + $this->assertEquals( + 1, + (int)$this->sendFriendResource->getSendCount( + null, + ip2long($remoteAddr), + time() - (60 * 60 * 24 * 365), + 1 + ) + ); } /** From d00db30ea32c35aa6b5d76ca080a2f5b77c84ee7 Mon Sep 17 00:00:00 2001 From: IvanPletnyov Date: Fri, 9 Oct 2020 12:23:57 +0300 Subject: [PATCH 04/41] MC-37543: Create automated test for "Add static block on a category page" --- .../Catalog/Block/Category/ViewTest.php | 91 +++++++++++++++++++ .../Category/Save/SaveCategoryTest.php | 83 +++++++++++++++++ .../_files/category_with_cms_block.php | 46 ++++++++++ .../category_with_cms_block_rollback.php | 32 +++++++ 4 files changed, 252 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Block/Category/ViewTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/SaveCategoryTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Category/ViewTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Category/ViewTest.php new file mode 100644 index 0000000000000..d08af2b85a67b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Category/ViewTest.php @@ -0,0 +1,91 @@ +objectManager = Bootstrap::getObjectManager(); + $this->registry = $this->objectManager->get(Registry::class); + $this->getCategoryByName = $this->objectManager->get(GetCategoryByName::class); + $this->categoryRepository = $this->objectManager->get(CategoryRepositoryInterface::class); + $this->layout = $this->objectManager->get(LayoutInterface::class); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + $this->registry->unregister('current_category'); + + parent::tearDown(); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/category_with_cms_block.php + * + * @return void + */ + public function testCmsBlockDisplayedOnCategory(): void + { + $categoryId = $this->getCategoryByName->execute('Category with cms block')->getId(); + $category = $this->categoryRepository->get($categoryId, 1); + $this->registerCategory($category); + $block = $this->layout->createBlock(View::class)->setTemplate('Magento_Catalog::category/cms.phtml'); + $this->assertStringContainsString('

Fixture Block Title

', $block->toHtml()); + } + + /** + * Register category in registry + * + * @param CategoryInterface $category + * @return void + */ + private function registerCategory(CategoryInterface $category): void + { + $this->registry->unregister('current_category'); + $this->registry->register('current_category', $category); + } +} 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 new file mode 100644 index 0000000000000..36641e010dfc6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/SaveCategoryTest.php @@ -0,0 +1,83 @@ +categoryRepository = $this->_objectManager->get(CategoryRepositoryInterface::class); + $this->getBlockByIdentifier = $this->_objectManager->get(GetBlockByIdentifierInterface::class); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + try { + $this->categoryRepository->deleteByIdentifier($this->createdCategoryId); + } catch (NoSuchEntityException $e) { + //Category already deleted. + } + $this->createdCategoryId = null; + + parent::tearDown(); + + } + + /** + * @magentoDataFixture Magento/Cms/_files/block.php + * + * @return void + */ + public function testCreateCategoryWithCmsBlock(): void + { + $blockId = $this->getBlockByIdentifier->execute('fixture_block', 1)->getId(); + $postData = [ + CategoryInterface::KEY_NAME => 'Category with cms block', + CategoryInterface::KEY_IS_ACTIVE => 1, + CategoryInterface::KEY_INCLUDE_IN_MENU => 1, + 'display_mode' => Category::DM_MIXED, + 'landing_page' => $blockId, + 'available_sort_by' => 1, + 'default_sort_by' => 1, + ]; + $responseData = $this->performSaveCategoryRequest($postData); + $this->assertRequestIsSuccessfullyPerformed($responseData); + $this->createdCategoryId = $responseData['category']['entity_id']; + $category = $this->categoryRepository->get($this->createdCategoryId); + $this->assertEquals($blockId, $category->getLandingPage()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block.php new file mode 100644 index 0000000000000..03eb767741579 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block.php @@ -0,0 +1,46 @@ +requireDataFixture('Magento/Cms/_files/block.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +/** @var CategoryInterfaceFactory $categoryFactory */ +$categoryFactory = $objectManager->get(CategoryInterfaceFactory::class); +/** @var CategoryRepositoryInterface $categoryRepository */ +$categoryRepository = $objectManager->get(CategoryRepositoryInterface::class); +/** @var DefaultCategory $categoryHelper */ +$categoryHelper = $objectManager->get(DefaultCategory::class); +$currentStoreId = (int)$storeManager->getStore()->getId(); +/** @var GetBlockByIdentifierInterface $getBlockByIdentifierInterface */ +$getBlockByIdentifier = $objectManager->get(GetBlockByIdentifierInterface::class); +$block = $getBlockByIdentifier->execute('fixture_block', $currentStoreId); + +$storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); +$category = $categoryFactory->create(); +$category->setName('Category with cms block') + ->setParentId($categoryHelper->getId()) + ->setLevel(2) + ->setAvailableSortBy('name') + ->setDefaultSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->setDisplayMode(Category::DM_MIXED) + ->setLandingPage($block->getId()); +$categoryRepository->save($category); +$storeManager->setCurrentStore($currentStoreId); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block_rollback.php new file mode 100644 index 0000000000000..4725fde47818c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block_rollback.php @@ -0,0 +1,32 @@ +get(Registry::class); +/** @var CategoryRepositoryInterface $categoryRepository */ +$categoryRepository = $objectManager->get(CategoryRepositoryInterface::class); +/** @var GetCategoryByName $getCategoryByName */ +$getCategoryByName = $objectManager->get(GetCategoryByName::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$category = $getCategoryByName->execute('Category with cms block'); +if ($category->getId()) { + $categoryRepository->delete($category); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +Resolver::getInstance()->requireDataFixture('Magento/Cms/_files/block_rollback.php'); From a535faa775d861570058fd80f9ff0f34bbd7515b Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 10 Oct 2020 12:26:16 +0530 Subject: [PATCH 05/41] 26133: Fixed - Coupon code text field not display in proper width in Internet Explorer/EDGE browser --- .../luma/Magento_Checkout/web/css/source/module/_cart.less | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less index 5d9746317af55..e8f2d1c5eb1ed 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less @@ -727,6 +727,13 @@ position: static; } } + .content { + .fieldset { + .actions-toolbar { + width: auto; + } + } + } &.discount { width: auto; } From 5be9b846a007e0b08e4e3349db4e7903c88fe8ae Mon Sep 17 00:00:00 2001 From: Viktor Kopin Date: Sun, 11 Oct 2020 09:48:30 +0300 Subject: [PATCH 06/41] MC-38113: Same shipping address is repeating multiple times in storefront checkout when Reordered --- ...ckoutFillingShippingSectionActionGroup.xml | 1 + ...CustomerHasNoOtherAddressesActionGroup.xml | 17 ++++++ .../Magento/Sales/Model/AdminOrder/Create.php | 6 ++ .../ActionGroup/AdminReorderActionGroup.xml | 22 +++++++ ...eorderAddressNotSavedInAddressBookTest.xml | 58 +++++++++++++++++++ .../templates/order/create/form/address.phtml | 4 +- 6 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertCustomerHasNoOtherAddressesActionGroup.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminReorderActionGroup.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml index 60188224871eb..e1092a87e4a01 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml @@ -27,6 +27,7 @@ + diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertCustomerHasNoOtherAddressesActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertCustomerHasNoOtherAddressesActionGroup.xml new file mode 100644 index 0000000000000..58a5069403b7f --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertCustomerHasNoOtherAddressesActionGroup.xml @@ -0,0 +1,17 @@ + + + + + + Verifies customer no additional address in address book + + + + + diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 393d61b69bf22..80e0ce168d7f5 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -550,6 +550,9 @@ public function initFromOrder(\Magento\Sales\Model\Order $order) $quote = $this->getQuote(); if (!$quote->isVirtual() && $this->getShippingAddress()->getSameAsBilling()) { + $quote->getBillingAddress()->setCustomerAddressId( + $quote->getShippingAddress()->getCustomerAddressId() + ); $this->setShippingAsBilling(1); } @@ -2120,6 +2123,9 @@ private function isAddressesAreEqual(Order $order) $billingData['address_type'], $billingData['entity_id'] ); + if (isset($shippingData['customer_address_id']) && !isset($billingData['customer_address_id'])) { + unset($shippingData['customer_address_id']); + } return $shippingData == $billingData; } diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminReorderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminReorderActionGroup.xml new file mode 100644 index 0000000000000..f4f076f25af8b --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminReorderActionGroup.xml @@ -0,0 +1,22 @@ + + + + + + Reorder existing order. Requires admin order page to be opened. + + + + + + + + + + diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml new file mode 100644 index 0000000000000..aca0c4e6a8f8a --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml @@ -0,0 +1,58 @@ + + + + + + + <stories value="MC-38113: Same shipping address is repeating multiple times in storefront checkout when Reordered"/> + <description value="Same shipping address is repeating multiple times in storefront checkout when Reordered"/> + <features value="Sales"/> + <testCaseId value="MC-38113"/> + <severity value="MAJOR"/> + <group value="Sales"/> + </annotations> + <before> + <createData entity="ApiCategory" stepKey="Category"/> + <createData entity="ApiSimpleProduct" stepKey="Product"> + <requiredEntity createDataKey="Category"/> + </createData> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="StorefrontOpenCustomerAccountCreatePageActionGroup" stepKey="openCreateAccountPage"/> + <actionGroup ref="StorefrontFillCustomerAccountCreationFormActionGroup" stepKey="fillCreateAccountForm"> + <argument name="customer" value="CustomerEntityOne"/> + </actionGroup> + <actionGroup ref="StorefrontClickCreateAnAccountCustomerAccountCreationFormActionGroup" stepKey="submitCreateAccountForm"/> + </before> + <after> + <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="customerLogout"/> + <actionGroup ref="DeleteCustomerFromAdminActionGroup" stepKey="deleteCustomer"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="adminLogout"/> + <deleteData createDataKey="Product" stepKey="deleteProduct"/> + <deleteData createDataKey="Category" stepKey="deleteCategory"/> + </after> + + <!-- Create order for registered customer --> + <actionGroup ref="AddSimpleProductToCartActionGroup" stepKey="addSimpleProductToOrder"> + <argument name="product" value="$Product$"/> + </actionGroup> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="openCheckoutPage"/> + <actionGroup ref="LoggedInUserCheckoutFillingShippingSectionActionGroup" stepKey="fillAddressForm"/> + <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickPlaceOrder"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber22}}" stepKey="grabOrderNumber"/> + + <!-- Reorder created order --> + <actionGroup ref="OpenOrderByIdActionGroup" stepKey="openOrderById"> + <argument name="orderId" value="$grabOrderNumber"/> + </actionGroup> + <actionGroup ref="AdminReorderActionGroup" stepKey="reorder"/> + + <!-- Assert no additional addresses saved --> + <actionGroup ref="AssertCustomerHasNoOtherAddressesActionGroup" stepKey="assertAddresses"/> + </test> +</tests> diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml index dc007e4801b41..12927dcf526a3 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml @@ -114,7 +114,9 @@ endif; ?> type="checkbox" id="<?= $block->escapeHtmlAttr($block->getForm()->getHtmlIdPrefix()) ?>save_in_address_book" value="1" - <?php if (!$block->getDontSaveInAddressBook()): ?> checked="checked"<?php endif; ?> + <?php if (!$block->getDontSaveInAddressBook() && !$block->getAddressId()): ?> + checked="checked" + <?php endif; ?> class="admin__control-checkbox"/> <label for="<?= $block->escapeHtmlAttr($block->getForm()->getHtmlIdPrefix()) ?>save_in_address_book" class="admin__field-label"><?= $block->escapeHtml(__('Save in address book')) ?></label> From 28bcc626117050e1306ac2e00ac190acd0e82f69 Mon Sep 17 00:00:00 2001 From: IvanPletnyov <ivan.pletnyov@transoftgroup.com> Date: Mon, 12 Oct 2020 09:05:43 +0300 Subject: [PATCH 07/41] MC-37543: Create automated test for "Add static block on a category page" --- .../Controller/Adminhtml/Category/Save/SaveCategoryTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 36641e010dfc6..155a5f255c15a 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 @@ -14,7 +14,7 @@ use Magento\Framework\Exception\NoSuchEntityException; /** - * Test cases related to save category with enabled category flat. + * Test cases for save category controller. * * @magentoAppArea adminhtml * @magentoDbIsolation disabled @@ -54,7 +54,6 @@ protected function tearDown(): void $this->createdCategoryId = null; parent::tearDown(); - } /** From d46371a645fa0e62ac37a8c456eff963406119bc Mon Sep 17 00:00:00 2001 From: IvanPletnyov <ivan.pletnyov@transoftgroup.com> Date: Mon, 12 Oct 2020 12:10:29 +0300 Subject: [PATCH 08/41] MC-37543: Create automated test for "Add static block on a category page" --- .../Catalog/Block/Category/ViewTest.php | 8 +++++- .../Category/Save/SaveCategoryTest.php | 26 ++++++++++++------- .../_files/category_with_cms_block.php | 9 ++++--- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Category/ViewTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Category/ViewTest.php index d08af2b85a67b..8ff4e29b46dde 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Category/ViewTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Category/ViewTest.php @@ -12,6 +12,7 @@ use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Registry; use Magento\Framework\View\LayoutInterface; +use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Catalog\Model\GetCategoryByName; use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; @@ -39,6 +40,9 @@ class ViewTest extends TestCase /** @var LayoutInterface */ private $layout; + /** @var StoreManagerInterface */ + private $storeManager; + /** * @inheritdoc */ @@ -51,6 +55,7 @@ protected function setUp(): void $this->getCategoryByName = $this->objectManager->get(GetCategoryByName::class); $this->categoryRepository = $this->objectManager->get(CategoryRepositoryInterface::class); $this->layout = $this->objectManager->get(LayoutInterface::class); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); } /** @@ -70,8 +75,9 @@ protected function tearDown(): void */ public function testCmsBlockDisplayedOnCategory(): void { + $storeId = (int)$this->storeManager->getStore('default')->getId(); $categoryId = $this->getCategoryByName->execute('Category with cms block')->getId(); - $category = $this->categoryRepository->get($categoryId, 1); + $category = $this->categoryRepository->get($categoryId, $storeId); $this->registerCategory($category); $block = $this->layout->createBlock(View::class)->setTemplate('Magento_Catalog::category/cms.phtml'); $this->assertStringContainsString('<h1>Fixture Block Title</h1>', $block->toHtml()); 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 155a5f255c15a..adef25f88395c 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 @@ -12,12 +12,13 @@ use Magento\Catalog\Model\Category; use Magento\Cms\Api\GetBlockByIdentifierInterface; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Store\Model\StoreManagerInterface; /** * Test cases for save category controller. * * @magentoAppArea adminhtml - * @magentoDbIsolation disabled + * @magentoDbIsolation enabled */ class SaveCategoryTest extends AbstractSaveCategoryTest { @@ -30,6 +31,9 @@ class SaveCategoryTest extends AbstractSaveCategoryTest /** @var string */ private $createdCategoryId; + /** @var StoreManagerInterface */ + private $storeManager; + /** * @inheritdoc */ @@ -39,6 +43,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); } /** @@ -46,12 +51,14 @@ protected function setUp(): void */ protected function tearDown(): void { - try { - $this->categoryRepository->deleteByIdentifier($this->createdCategoryId); - } catch (NoSuchEntityException $e) { - //Category already deleted. + if(!empty($this->createdCategoryId)) { + try { + $this->categoryRepository->deleteByIdentifier($this->createdCategoryId); + } catch (NoSuchEntityException $e) { + //Category already deleted. + } + $this->createdCategoryId = null; } - $this->createdCategoryId = null; parent::tearDown(); } @@ -63,15 +70,16 @@ protected function tearDown(): void */ public function testCreateCategoryWithCmsBlock(): void { - $blockId = $this->getBlockByIdentifier->execute('fixture_block', 1)->getId(); + $storeId = (int)$this->storeManager->getStore('default')->getId(); + $blockId = $this->getBlockByIdentifier->execute('fixture_block', $storeId)->getId(); $postData = [ CategoryInterface::KEY_NAME => 'Category with cms block', CategoryInterface::KEY_IS_ACTIVE => 1, CategoryInterface::KEY_INCLUDE_IN_MENU => 1, 'display_mode' => Category::DM_MIXED, 'landing_page' => $blockId, - 'available_sort_by' => 1, - 'default_sort_by' => 1, + CategoryInterface::KEY_AVAILABLE_SORT_BY => ['position'], + 'default_sort_by' => 'position', ]; $responseData = $this->performSaveCategoryRequest($postData); $this->assertRequestIsSuccessfullyPerformed($responseData); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block.php index 03eb767741579..417b791eb376a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_cms_block.php @@ -31,7 +31,6 @@ $getBlockByIdentifier = $objectManager->get(GetBlockByIdentifierInterface::class); $block = $getBlockByIdentifier->execute('fixture_block', $currentStoreId); -$storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); $category = $categoryFactory->create(); $category->setName('Category with cms block') ->setParentId($categoryHelper->getId()) @@ -42,5 +41,9 @@ ->setPosition(1) ->setDisplayMode(Category::DM_MIXED) ->setLandingPage($block->getId()); -$categoryRepository->save($category); -$storeManager->setCurrentStore($currentStoreId); +try { + $storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + $categoryRepository->save($category); +} finally { + $storeManager->setCurrentStore($currentStoreId); +} From 4ffbd717b999d3976839cef63f927beefd65976e Mon Sep 17 00:00:00 2001 From: IvanPletnyov <ivan.pletnyov@transoftgroup.com> Date: Mon, 12 Oct 2020 14:47:33 +0300 Subject: [PATCH 09/41] MC-37558: Create automated test for "Override Category settings on Store View level" --- .../Category/Save/UpdateCategoryTest.php | 114 +++++++++++ .../Catalog/Model/CategoryRepositoryTest.php | 180 +++++++++++------- 2 files changed, 221 insertions(+), 73 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php new file mode 100644 index 0000000000000..c3d5ed080bcf2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php @@ -0,0 +1,114 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Controller\Adminhtml\Category\Save; + +use Magento\Catalog\Api\CategoryRepositoryInterface; +use Magento\Catalog\Api\Data\CategoryInterface; +use Magento\Catalog\Model\Category; +use Magento\Store\Model\StoreManagerInterface; + +/** + * Test related to update category. + * + * @magentoAppArea adminhtml + * @magentoDbIsolation enabled + */ +class UpdateCategoryTest extends AbstractSaveCategoryTest +{ + /** @var CategoryRepositoryInterface */ + private $categoryRepository; + + /** @var StoreManagerInterface */ + private $storeManager; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->categoryRepository = $this->_objectManager->get(CategoryRepositoryInterface::class); + $this->storeManager = $this->_objectManager->get(StoreManagerInterface::class); + } + + /** + * @dataProvider categoryDataProvider + * @magentoDataFixture Magento/Store/_files/second_store.php + * @magentoDataFixture Magento/Catalog/_files/category.php + * + * @param array $postData + * @return void + */ + public function testUpdateCategoryForDefaultStoreView($postData): void + { + $storeId = (int)$this->storeManager->getStore('default')->getId(); + $postData = array_merge($postData, ['store_id' => $storeId]); + $responseData = $this->performSaveCategoryRequest($postData); + $this->assertRequestIsSuccessfullyPerformed($responseData); + $category = $this->categoryRepository->get($postData['entity_id'], $postData['store_id']); + unset($postData['use_default']); + unset($postData['use_config']); + foreach ($postData as $key => $value) { + $this->assertEquals($value, $category->getData($key)); + } + } + + /** + * @return array + */ + public function categoryDataProvider(): array + { + return [ + [ + 'post_data' => [ + 'entity_id' => 333, + CategoryInterface::KEY_IS_ACTIVE => '0', + CategoryInterface::KEY_INCLUDE_IN_MENU => '0', + CategoryInterface::KEY_NAME => 'Category default store', + 'description' => 'Description for default store', + 'landing_page' => '', + 'display_mode' => Category::DM_MIXED, + CategoryInterface::KEY_AVAILABLE_SORT_BY => ['name', 'price'], + 'default_sort_by' => 'price', + 'filter_price_range' => 5, + 'url_key' => 'default-store-category', + 'meta_title' => 'meta_title default store', + 'meta_keywords' => 'meta_keywords default store', + 'meta_description' => 'meta_description default store', + 'custom_use_parent_settings' => '0', + 'custom_design' => '2', + 'page_layout' => '2columns-right', + 'custom_apply_to_products' => '1', + 'use_default' => [ + CategoryInterface::KEY_NAME => '0', + CategoryInterface::KEY_IS_ACTIVE => '0', + CategoryInterface::KEY_INCLUDE_IN_MENU => '0', + 'url_key' => '0', + 'meta_title' => '0', + 'custom_use_parent_settings' => '0', + 'custom_apply_to_products' => '0', + 'description' => '0', + 'landing_page' => '0', + 'display_mode' => '0', + 'custom_design' => '0', + 'page_layout' => '0', + 'meta_keywords' => '0', + 'meta_description' => '0', + 'custom_layout_update' => '0', + ], + 'use_config' => [ + CategoryInterface::KEY_AVAILABLE_SORT_BY => false, + 'default_sort_by' => false, + 'filter_price_range' => false, + ], + ], + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryRepositoryTest.php index 7fd7627c738d6..6469f80ff49b8 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryRepositoryTest.php @@ -8,93 +8,82 @@ namespace Magento\Catalog\Model; use Magento\Catalog\Api\CategoryRepositoryInterface; -use Magento\Catalog\Api\CategoryRepositoryInterfaceFactory; +use Magento\Catalog\Api\Data\CategoryInterface; use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; +use Magento\Cms\Api\GetBlockByIdentifierInterface; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\ObjectManagerInterface; +use Magento\Store\Api\StoreManagementInterface; +use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Catalog\Model\CategoryLayoutUpdateManager; use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; /** * Provide tests for CategoryRepository model. + * + * @magentoDbIsolation enabled */ class CategoryRepositoryTest extends TestCase { - private const FIXTURE_CATEGORY_ID = 333; - private const FIXTURE_TWO_STORES_CATEGORY_ID = 555; - private const FIXTURE_SECOND_STORE_CODE = 'fixturestore'; - private const FIXTURE_FIRST_STORE_CODE = 'default'; + /** @var ObjectManagerInterface */ + private $objectManager; - /** - * @var CategoryLayoutUpdateManager - */ + /** @var CategoryLayoutUpdateManager */ private $layoutManager; - /** - * @var CategoryRepositoryInterfaceFactory - */ - private $repositoryFactory; + /** @var CategoryRepositoryInterface */ + private $categoryRepository; - /** - * @var CollectionFactory - */ + /** @var CollectionFactory */ private $productCollectionFactory; - /** - * @var CategoryCollectionFactory - */ + /** @var CategoryCollectionFactory */ private $categoryCollectionFactory; + /** @var StoreManagementInterface */ + private $storeManager; + + /** @var GetBlockByIdentifierInterface */ + private $getBlockByIdentifier; + /** - * Sets up common objects. - * - * @inheritDoc + * @inheritdoc */ protected function setUp(): void { - Bootstrap::getObjectManager()->configure([ + $this->objectManager = Bootstrap::getObjectManager(); + $this->objectManager->configure([ 'preferences' => [ \Magento\Catalog\Model\Category\Attribute\LayoutUpdateManager::class => \Magento\TestFramework\Catalog\Model\CategoryLayoutUpdateManager::class ] ]); - $this->repositoryFactory = Bootstrap::getObjectManager()->get(CategoryRepositoryInterfaceFactory::class); - $this->layoutManager = Bootstrap::getObjectManager()->get(CategoryLayoutUpdateManager::class); - $this->productCollectionFactory = Bootstrap::getObjectManager()->get(CollectionFactory::class); - $this->categoryCollectionFactory = Bootstrap::getObjectManager()->create(CategoryCollectionFactory::class); - } - - /** - * Create subject object. - * - * @return CategoryRepositoryInterface - */ - private function createRepo(): CategoryRepositoryInterface - { - return $this->repositoryFactory->create(); + $this->layoutManager = $this->objectManager->get(CategoryLayoutUpdateManager::class); + $this->productCollectionFactory = $this->objectManager->get(CollectionFactory::class); + $this->categoryCollectionFactory = $this->objectManager->get(CategoryCollectionFactory::class); + $this->categoryRepository = $this->objectManager->get(CategoryRepositoryInterface::class); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + $this->getBlockByIdentifier = $this->objectManager->get(GetBlockByIdentifierInterface::class); } /** * Test that custom layout file attribute is saved. * - * @return void - * @throws \Throwable * @magentoDataFixture Magento/Catalog/_files/category.php - * @magentoDbIsolation enabled * @magentoAppIsolation enabled + * + * @return void */ public function testCustomLayout(): void { - //New valid value - $repo = $this->createRepo(); - $category = $repo->get(self::FIXTURE_CATEGORY_ID); + $category = $this->categoryRepository->get(333); $newFile = 'test'; - $this->layoutManager->setCategoryFakeFiles(self::FIXTURE_CATEGORY_ID, [$newFile]); + $this->layoutManager->setCategoryFakeFiles(333, [$newFile]); $category->setCustomAttribute('custom_layout_update_file', $newFile); - $repo->save($category); - $repo = $this->createRepo(); - $category = $repo->get(self::FIXTURE_CATEGORY_ID); + $this->categoryRepository->save($category); + $category = $this->categoryRepository->get(333); $this->assertEquals($newFile, $category->getCustomAttribute('custom_layout_update_file')->getValue()); //Setting non-existent value @@ -102,7 +91,7 @@ public function testCustomLayout(): void $category->setCustomAttribute('custom_layout_update_file', $newFile); $caughtException = false; try { - $repo->save($category); + $this->categoryRepository->save($category); } catch (LocalizedException $exception) { $caughtException = true; } @@ -112,9 +101,9 @@ public function testCustomLayout(): void /** * Test removal of categories. * - * @magentoDbIsolation enabled * @magentoDataFixture Magento/Catalog/_files/categories.php * @magentoAppArea adminhtml + * * @return void */ public function testCategoryBehaviourAfterDelete(): void @@ -122,7 +111,7 @@ public function testCategoryBehaviourAfterDelete(): void $productCollection = $this->productCollectionFactory->create(); $deletedCategories = ['3', '4', '5', '13']; $categoryCollectionIds = $this->categoryCollectionFactory->create()->getAllIds(); - $this->createRepo()->deleteByIdentifier(3); + $this->categoryRepository->deleteByIdentifier(3); $this->assertEquals( 0, $productCollection->addCategoriesFilter(['in' => $deletedCategories])->getSize(), @@ -131,42 +120,87 @@ public function testCategoryBehaviourAfterDelete(): void $newCategoryCollectionIds = $this->categoryCollectionFactory->create()->getAllIds(); $difference = array_diff($categoryCollectionIds, $newCategoryCollectionIds); sort($difference); - $this->assertEquals( - $deletedCategories, - $difference, - 'Wrong categories was deleted' - ); + $this->assertEquals($deletedCategories, $difference, 'Wrong categories was deleted'); } /** * Verifies whether `get()` method `$storeId` attribute works as expected. * - * @magentoDbIsolation enabled * @magentoDataFixture Magento/Store/_files/core_fixturestore.php * @magentoDataFixture Magento/Catalog/_files/category_with_two_stores.php + * + * @return void */ - public function testGetCategoryForProvidedStore() + public function testGetCategoryForProvidedStore(): void { - $categoryRepository = $this->repositoryFactory->create(); - - $categoryDefault = $categoryRepository->get( - self::FIXTURE_TWO_STORES_CATEGORY_ID - ); - + $categoryId = 555; + $categoryDefault = $this->categoryRepository->get($categoryId); $this->assertSame('category-defaultstore', $categoryDefault->getUrlKey()); - - $categoryFirstStore = $categoryRepository->get( - self::FIXTURE_TWO_STORES_CATEGORY_ID, - self::FIXTURE_FIRST_STORE_CODE - ); - + $defaultStoreId = $this->storeManager->getStore('default')->getId(); + $categoryFirstStore = $this->categoryRepository->get($categoryId, $defaultStoreId); $this->assertSame('category-defaultstore', $categoryFirstStore->getUrlKey()); + $fixtureStoreId = $this->storeManager->getStore('fixturestore')->getId(); + $categorySecondStore = $this->categoryRepository->get($categoryId, $fixtureStoreId); + $this->assertSame('category-fixturestore', $categorySecondStore->getUrlKey()); + } - $categorySecondStore = $categoryRepository->get( - self::FIXTURE_TWO_STORES_CATEGORY_ID, - self::FIXTURE_SECOND_STORE_CODE - ); + /** + * @magentoDataFixture Magento/Store/_files/second_store.php + * @magentoDataFixture Magento/Catalog/_files/category.php + * @magentoDataFixture Magento/Cms/_files/block.php + * + * @return void + */ + public function testUpdateCategoryDefaultStoreView(): void + { + $categoryId = 333; + $defaultStoreId = (int)$this->storeManager->getStore('default')->getId(); + $secondStoreId = (int)$this->storeManager->getStore('fixture_second_store')->getId(); + $blockId = $this->getBlockByIdentifier->execute('fixture_block', $defaultStoreId)->getId(); + $origData = $this->categoryRepository->get($categoryId)->getData(); + unset($origData[CategoryInterface::KEY_UPDATED_AT]); + $category = $this->categoryRepository->get($categoryId, $defaultStoreId); + $dataForDefaultStore = [ + CategoryInterface::KEY_IS_ACTIVE => 0, + CategoryInterface::KEY_INCLUDE_IN_MENU => 0, + CategoryInterface::KEY_NAME => 'Category default store', + 'image' => 'test.png', + 'description' => 'Description for default store', + 'landing_page' => $blockId, + 'display_mode' => Category::DM_MIXED, + CategoryInterface::KEY_AVAILABLE_SORT_BY => ['name', 'price'], + 'default_sort_by' => 'price', + 'filter_price_range' => 5, + 'url_key' => 'default-store-category', + 'meta_title' => 'meta_title default store', + 'meta_keywords' => 'meta_keywords default store', + 'meta_description' => 'meta_description default store', + 'custom_use_parent_settings' => '0', + 'custom_design' => '2', + 'page_layout' => '2columns-right', + 'custom_apply_to_products' => '1', + ]; + $category->addData($dataForDefaultStore); + $updatedCategory = $this->categoryRepository->save($category); + $this->assertCategoryData($dataForDefaultStore, $updatedCategory); + $categorySecondStore = $this->categoryRepository->get($categoryId, $secondStoreId); + $this->assertCategoryData($origData, $categorySecondStore); + foreach ($dataForDefaultStore as $key => $value) { + $this->assertNotEquals($value, $categorySecondStore->getData($key)); + } + } - $this->assertSame('category-fixturestore', $categorySecondStore->getUrlKey()); + /** + * Assert category data. + * + * @param array $expectedData + * @param CategoryInterface $category + * @return void + */ + private function assertCategoryData(array $expectedData, CategoryInterface $category): void + { + foreach ($expectedData as $key => $value) { + $this->assertEquals($value, $category->getData($key)); + } } } From 732dfebe0a1ac65d264480c186984bc4c5259456 Mon Sep 17 00:00:00 2001 From: IvanPletnyov <ivan.pletnyov@transoftgroup.com> Date: Mon, 12 Oct 2020 14:54:13 +0300 Subject: [PATCH 10/41] MC-37543: Create automated test for "Add static block on a category page" --- .../Controller/Adminhtml/Category/Save/SaveCategoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 adef25f88395c..dc74a2c2cba7b 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 @@ -51,7 +51,7 @@ protected function setUp(): void */ protected function tearDown(): void { - if(!empty($this->createdCategoryId)) { + if (!empty($this->createdCategoryId)) { try { $this->categoryRepository->deleteByIdentifier($this->createdCategoryId); } catch (NoSuchEntityException $e) { From 20d7d416e252b8b27141ebdb5e2b768c85d3f84b Mon Sep 17 00:00:00 2001 From: Bohdan Shevchenko <1408sheva@gmail.com> Date: Mon, 12 Oct 2020 15:05:42 +0300 Subject: [PATCH 11/41] MC-37546: Create automated test for "Create new Category Update" --- ...rontCheckPresentSubCategoryActionGroup.xml | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml new file mode 100644 index 0000000000000..7d8113f05518b --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.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="StorefrontCheckPresentSubCategoryActionGroup"> + <annotations> + <description>Checks for a subcategory in topmenu</description> + </annotations> + <arguments> + <argument name="parenCategoryName" type="string"/> + <argument name="childCategoryName" type="string"/> + </arguments> + + <waitForElement selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(parenCategoryName)}}" stepKey="waitForTopMenuLoaded"/> + <moveMouseOver selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(parenCategoryName)}}" stepKey="moveMouseToParentCategory"/> + <seeElement selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(childCategoryName)}}" stepKey="seeCategoryUpdated"/> + </actionGroup> +</actionGroups> From a37cf33bc2a02671302f66ededb5085f6e911ea4 Mon Sep 17 00:00:00 2001 From: Your Name <mmdhudasia@gmail.com> Date: Mon, 12 Oct 2020 17:51:47 +0530 Subject: [PATCH 12/41] fixed spacing issue --- .../web/css/source/module/_cart.less | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less index e8f2d1c5eb1ed..405bc1d2af373 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less @@ -267,7 +267,7 @@ .lib-icon-font-symbol( @_icon-font-content: @icon-trash ); - + &:hover { .lib-css(text-decoration, @link__text-decoration); } @@ -574,7 +574,7 @@ .widget { float: left; - + &.block { margin-bottom: @indent__base; } @@ -728,11 +728,11 @@ } } .content { - .fieldset { - .actions-toolbar { - width: auto; + .fieldset { + .actions-toolbar { + width: auto; + } } - } } &.discount { width: auto; From 372049ac123cfc1055850358adb5e88db67cc6ce Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Mon, 12 Oct 2020 16:55:59 +0300 Subject: [PATCH 13/41] MC-38113: Same shipping address is repeating multiple times in storefront checkout when Reordered --- ...reFrontCustomerHasNoOtherAddressesActionGroup.xml} | 2 +- .../AdminReorderAddressNotSavedInAddressBookTest.xml | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) rename app/code/Magento/Customer/Test/Mftf/ActionGroup/{AssertCustomerHasNoOtherAddressesActionGroup.xml => AssertStoreFrontCustomerHasNoOtherAddressesActionGroup.xml} (89%) diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertCustomerHasNoOtherAddressesActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStoreFrontCustomerHasNoOtherAddressesActionGroup.xml similarity index 89% rename from app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertCustomerHasNoOtherAddressesActionGroup.xml rename to app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStoreFrontCustomerHasNoOtherAddressesActionGroup.xml index 58a5069403b7f..2fde4d915c99f 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertCustomerHasNoOtherAddressesActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStoreFrontCustomerHasNoOtherAddressesActionGroup.xml @@ -7,7 +7,7 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AssertCustomerHasNoOtherAddressesActionGroup"> + <actionGroup name="AssertStoreFrontCustomerHasNoOtherAddressesActionGroup"> <annotations> <description>Verifies customer no additional address in address book</description> </annotations> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml index aca0c4e6a8f8a..2b4bb43ec36cd 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml @@ -22,19 +22,18 @@ <createData entity="ApiSimpleProduct" stepKey="Product"> <requiredEntity createDataKey="Category"/> </createData> + <createData entity="Simple_Customer_Without_Address" stepKey="Customer"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> - <actionGroup ref="StorefrontOpenCustomerAccountCreatePageActionGroup" stepKey="openCreateAccountPage"/> - <actionGroup ref="StorefrontFillCustomerAccountCreationFormActionGroup" stepKey="fillCreateAccountForm"> - <argument name="customer" value="CustomerEntityOne"/> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> + <argument name="Customer" value="$Customer$"/> </actionGroup> - <actionGroup ref="StorefrontClickCreateAnAccountCustomerAccountCreationFormActionGroup" stepKey="submitCreateAccountForm"/> </before> <after> <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="customerLogout"/> - <actionGroup ref="DeleteCustomerFromAdminActionGroup" stepKey="deleteCustomer"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="adminLogout"/> <deleteData createDataKey="Product" stepKey="deleteProduct"/> <deleteData createDataKey="Category" stepKey="deleteCategory"/> + <deleteData createDataKey="Customer" stepKey="deleteCustomer"/> </after> <!-- Create order for registered customer --> @@ -53,6 +52,6 @@ <actionGroup ref="AdminReorderActionGroup" stepKey="reorder"/> <!-- Assert no additional addresses saved --> - <actionGroup ref="AssertCustomerHasNoOtherAddressesActionGroup" stepKey="assertAddresses"/> + <actionGroup ref="AssertStoreFrontCustomerHasNoOtherAddressesActionGroup" stepKey="assertAddresses"/> </test> </tests> From a8743bbf0121d2e5cceb2f1df37524031501c5ed Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Mon, 12 Oct 2020 17:27:59 +0300 Subject: [PATCH 14/41] MC-37070: Create automated test for "Import products with shared images" --- .../Product/Gallery/UpdateHandlerTest.php | 102 +++++++- .../Import/ImportWithSharedImagesTest.php | 236 ++++++++++++++++++ ...talog_import_products_with_same_images.csv | 3 + .../_files/magento_image.jpg | Bin 0 -> 13353 bytes 4 files changed, 339 insertions(+), 2 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ImportWithSharedImagesTest.php create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/catalog_import_products_with_same_images.csv create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/magento_image.jpg diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php index 7ee2c62453df5..ce36b27d51e7d 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php @@ -8,6 +8,7 @@ namespace Magento\Catalog\Model\Product\Gallery; +use Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface; use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product; @@ -351,6 +352,23 @@ public function testExecuteWithTwoImagesOnStoreView(): void } } + /** + * @magentoDataFixture Magento/Catalog/_files/product_with_image.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testDeleteSharedImage(): void + { + $product = $this->getProduct(null, 'simple'); + $this->duplicateMediaGalleryForProduct('/m/a/magento_image.jpg', 'simple2'); + $secondProduct = $this->getProduct(null, 'simple2'); + $this->updateHandler->execute($this->prepareRemoveImage($product), []); + $product = $this->getProduct(null, 'simple'); + $this->assertEmpty($product->getMediaGalleryImages()->getItems()); + $this->checkProductImageExist($secondProduct, '/m/a/magento_image.jpg'); + } + /** * @inheritdoc */ @@ -371,11 +389,13 @@ protected function tearDown(): void * Returns current product. * * @param int|null $storeId + * @param string|null $sku * @return ProductInterface|Product */ - private function getProduct(?int $storeId = null): ProductInterface + private function getProduct(?int $storeId = null, ?string $sku = null): ProductInterface { - return $this->productRepository->get('simple', false, $storeId, true); + $sku = $sku ?: 'simple'; + return $this->productRepository->get($sku, false, $storeId, true); } /** @@ -464,6 +484,84 @@ public function testDeleteWithMultiWebsites(): void $this->assertArrayNotHasKey($secondStoreId, $imageRolesPerStore); } + /** + * Check product image link and product image exist + * + * @param ProductInterface $product + * @param string $imagePath + * @return void + */ + private function checkProductImageExist(ProductInterface $product, string $imagePath): void + { + $productImageItem = $product->getMediaGalleryImages()->getFirstItem(); + $this->assertEquals($imagePath, $productImageItem->getFile()); + $productImageFile = $productImageItem->getPath(); + $this->assertNotEmpty($productImageFile); + $this->assertTrue($this->mediaDirectory->getDriver()->isExists($productImageFile)); + $this->fileName = $productImageFile; + } + + /** + * Prepare the product to remove image + * + * @param ProductInterface $product + * @return ProductInterface + */ + private function prepareRemoveImage(ProductInterface $product): ProductInterface + { + $item = $product->getMediaGalleryImages()->getFirstItem(); + $item->setRemoved('1'); + $galleryData = [ + 'images' => [ + (int)$item->getValueId() => $item->getData(), + ] + ]; + $product->setData(ProductInterface::MEDIA_GALLERY, $galleryData); + $product->setStoreId(0); + + return $product; + } + + /** + * Duplicate media gallery entries for a product + * + * @param string $imagePath + * @param string $productSku + * @return void + */ + private function duplicateMediaGalleryForProduct(string $imagePath, string $productSku): void + { + $product = $this->getProduct(null, $productSku); + $connect = $this->galleryResource->getConnection(); + $select = $connect->select()->from($this->galleryResource->getMainTable())->where('value = ?', $imagePath); + $res = $connect->fetchRow($select); + $value_id = $res['value_id']; + unset($res['value_id']); + $rows = [ + 'attribute_id' => $res['attribute_id'], + 'value' => $res['value'], + ProductAttributeMediaGalleryEntryInterface::MEDIA_TYPE => $res['media_type'], + ProductAttributeMediaGalleryEntryInterface::DISABLED => $res['disabled'], + ]; + $connect->insert($this->galleryResource->getMainTable(), $rows); + $select = $connect->select() + ->from($this->galleryResource->getTable(Gallery::GALLERY_VALUE_TABLE)) + ->where('value_id = ?', $value_id); + $res = $connect->fetchRow($select); + $newValueId = (int)$value_id + 1; + $rows = [ + 'value_id' => $newValueId, + 'store_id' => $res['store_id'], + ProductAttributeMediaGalleryEntryInterface::LABEL => $res['label'], + ProductAttributeMediaGalleryEntryInterface::POSITION => $res['position'], + ProductAttributeMediaGalleryEntryInterface::DISABLED => $res['disabled'], + 'row_id' => $product->getRowId(), + ]; + $connect->insert($this->galleryResource->getTable(Gallery::GALLERY_VALUE_TABLE), $rows); + $rows = ['value_id' => $newValueId, 'row_id' => $product->getRowId()]; + $connect->insert($this->galleryResource->getTable(Gallery::GALLERY_VALUE_TO_ENTITY_TABLE), $rows); + } + /** * @param Product $product * @param array $roles diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ImportWithSharedImagesTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ImportWithSharedImagesTest.php new file mode 100644 index 0000000000000..4c04e5a8814e5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ImportWithSharedImagesTest.php @@ -0,0 +1,236 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogImportExport\Model\Import; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product as ProductEntity; +use Magento\Catalog\Model\Product\Media\ConfigInterface; +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Driver\File; +use Magento\Framework\ObjectManagerInterface; +use Magento\ImportExport\Model\Import; +use Magento\ImportExport\Model\Import\Source\Csv; +use Magento\ImportExport\Model\Import\Source\CsvFactory; +use Magento\ImportExport\Model\ResourceModel\Import\Data; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Checks that product import with same images can be successfully done + * + * @magentoAppArea adminhtml + * @magentoDbIsolation enabled + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ImportWithSharedImagesTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var Filesystem */ + private $fileSystem; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** @var File */ + private $fileDriver; + + /** @var Import */ + private $import; + + /** @var ConfigInterface */ + private $mediaConfig; + + /** @var array */ + private $appParams; + + /** @var array */ + private $createdProductsSkus = []; + + /** @var array */ + private $filesToRemove = []; + + /** @var CsvFactory */ + private $csvFactory; + + /** @var Data */ + private $importDataResource; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->fileSystem = $this->objectManager->get(Filesystem::class); + $this->fileDriver = $this->objectManager->get(File::class); + $this->mediaConfig = $this->objectManager->get(ConfigInterface::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->import = $this->objectManager->get(ProductFactory::class)->create(); + $this->csvFactory = $this->objectManager->get(CsvFactory::class); + $this->importDataResource = $this->objectManager->get(Data::class); + $this->appParams = Bootstrap::getInstance()->getBootstrap()->getApplication() + ->getInitParams()[\Magento\Framework\App\Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]; + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + $this->removeFiles(); + $this->removeProducts(); + $this->importDataResource->cleanBunches(); + + parent::tearDown(); + } + + /** + * @return void + */ + public function testImportProductsWithSameImages(): void + { + $this->moveImages('magento_image.jpg'); + $source = $this->prepareFile('catalog_import_products_with_same_images.csv'); + $this->updateUploader(); + $errors = $this->import->setParameters([ + 'behavior' => Import::BEHAVIOR_ADD_UPDATE, + 'entity' => ProductEntity::ENTITY, + ]) + ->setSource($source)->validateData(); + $this->assertEmpty($errors->getAllErrors()); + $this->import->importData(); + $this->createdProductsSkus = ['SimpleProductForTest1', 'SimpleProductForTest2']; + $this->checkProductsImages('/m/a/magento_image.jpg', $this->createdProductsSkus); + } + + /** + * Check product images + * + * @param string $expectedImagePath + * @param array $productSkus + * @return void + */ + private function checkProductsImages(string $expectedImagePath, array $productSkus): void + { + foreach ($productSkus as $productSku) { + $product = $this->productRepository->get($productSku); + $productImageItem = $product->getMediaGalleryImages()->getFirstItem(); + $productImageFile = $productImageItem->getFile(); + $productImagePath = $productImageItem->getPath(); + $this->filesToRemove[] = $productImagePath; + $this->assertEquals($expectedImagePath, $productImageFile); + $this->assertNotEmpty($productImagePath); + $this->assertTrue($this->fileDriver->isExists($productImagePath)); + } + } + + /** + * Remove created files + * + * @return void + */ + private function removeFiles(): void + { + foreach ($this->filesToRemove as $file) { + if ($this->fileDriver->isExists($file)) { + $this->fileDriver->deleteFile($file); + } + } + } + + /** + * Remove created products + * + * @return void + */ + private function removeProducts(): void + { + foreach ($this->createdProductsSkus as $sku) { + try { + $this->productRepository->deleteById($sku); + } catch (NoSuchEntityException $e) { + //already removed + } + } + } + + /** + * Prepare file + * + * @param string $fileName + * @return Csv + */ + private function prepareFile(string $fileName): Csv + { + $tmpDirectory = $this->fileSystem->getDirectoryWrite(DirectoryList::VAR_DIR); + $fixtureDir = realpath(__DIR__ . '/../../_files'); + $filePath = $tmpDirectory->getAbsolutePath($fileName); + $this->filesToRemove[] = $filePath; + $tmpDirectory->getDriver()->copy($fixtureDir . DIRECTORY_SEPARATOR . $fileName, $filePath); + $source = $this->csvFactory->create( + [ + 'file' => $fileName, + 'directory' => $tmpDirectory + ] + ); + + return $source; + } + + /** + * Update upload to use sandbox folders + * + * @return void + */ + private function updateUploader(): void + { + $uploader = $this->import->getUploader(); + $rootDirectory = $this->fileSystem->getDirectoryWrite(DirectoryList::ROOT); + $destDir = $rootDirectory->getRelativePath( + $this->appParams[DirectoryList::MEDIA][DirectoryList::PATH] + . DS . $this->mediaConfig->getBaseMediaPath() + ); + $tmpDir = $rootDirectory->getRelativePath( + $this->appParams[DirectoryList::MEDIA][DirectoryList::PATH] + ); + $rootDirectory->create($destDir); + $rootDirectory->create($tmpDir); + $uploader->setDestDir($destDir); + $uploader->setTmpDir($tmpDir); + } + + /** + * Move images to appropriate folder + * + * @param string $fileName + * @return void + */ + private function moveImages(string $fileName): void + { + $rootDirectory = $this->fileSystem->getDirectoryWrite(DirectoryList::ROOT); + $tmpDir = $rootDirectory->getRelativePath( + $this->appParams[DirectoryList::MEDIA][DirectoryList::PATH] + ); + $fixtureDir = realpath(__DIR__ . '/../../_files'); + $tmpFilePath = $rootDirectory->getAbsolutePath($tmpDir . DS . $fileName); + $this->fileDriver->createDirectory($tmpDir); + $rootDirectory->getDriver()->copy( + $fixtureDir . DIRECTORY_SEPARATOR . $fileName, + $tmpFilePath + ); + $this->filesToRemove[] = $tmpFilePath; + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/catalog_import_products_with_same_images.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/catalog_import_products_with_same_images.csv new file mode 100644 index 0000000000000..7761ed7ac2360 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/catalog_import_products_with_same_images.csv @@ -0,0 +1,3 @@ +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,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,configurable_variations,configurable_variation_labels,associated_skus +SimpleProductForTest1,,Default,simple,Default,base,SimpleProductAfterImport1,,,1,1,Taxable Goods,"Catalog, Search",250,,,,simple-product-for-test-1,,,,magento_image.jpg,BASE magento_image.jpg,magento_image.jpg,SMALL blueshirt,magento_image.jpg,Thumb Image,,,"3/4/19, 5:53 AM","3/4/19, 4:47 PM",,,Block after Info Column,,,,,,,,,,,Use config,,,100,0,1,0,0,1,1,1,0,1,1,,1,0,1,1,0,1,0,0,0,,,,,,,,,,,,,,,,,,, +SimpleProductForTest2,,Default,simple,Default,base,SimpleProductAfterImport2,,,1,1,Taxable Goods,"Catalog, Search",300,,,,simple-product-for-test-2,,,,magento_image.jpg,BASE magento_image.jpg,magento_image.jpg,SMALL blueshirt,magento_image.jpg,Thumb Image,,,"3/4/19, 5:53 AM","3/4/19, 4:47 PM",,,Block after Info Column,,,,,,,,,,,Use config,,,100,0,1,0,0,1,1,1,0,1,1,,1,0,1,1,0,1,0,0,0,,,,,,,,,,,,,,,,,,, diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/magento_image.jpg b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/magento_image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b825a41b2101a758ee9c45b9304a6d08a90c729 GIT binary patch literal 13353 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 A%K!iX literal 0 HcmV?d00001 From df5ae12ecc26edee6bdb2c01cf5e0c6c3198f9f4 Mon Sep 17 00:00:00 2001 From: TuNa <ladiesman9x@gmail.com> Date: Mon, 12 Oct 2020 22:13:19 +0700 Subject: [PATCH 15/41] Remove incorrect use important in swatches option text up --- .../Magento_Swatches/web/css/source/_module.less | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Swatches/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Swatches/web/css/source/_module.less index 07317e1670a0b..ce1b009c24d42 100644 --- a/app/design/frontend/Magento/blank/Magento_Swatches/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Swatches/web/css/source/_module.less @@ -65,7 +65,6 @@ // _____________________________________________ & when (@media-common = true) { - .swatch { &-attribute { &-label { @@ -155,7 +154,7 @@ padding: 4px 8px; &.selected { - .lib-css(background-color, @swatch-option-text__selected__background-color) !important; + .lib-css(background-color, @swatch-option-text__selected__background-color); } } @@ -201,6 +200,7 @@ top: 0; } } + &-disabled { border: 0; cursor: default; @@ -208,6 +208,7 @@ &:after { .lib-rotate(-30deg); + .lib-css(background, @swatch-option__disabled__background); content: ''; height: 2px; left: -4px; @@ -215,7 +216,6 @@ top: 10px; width: 42px; z-index: 995; - .lib-css(background, @swatch-option__disabled__background); } } @@ -226,6 +226,7 @@ &-tooltip { .lib-css(border, @swatch-option-tooltip__border); .lib-css(color, @swatch-option-tooltip__color); + .lib-css(background, @swatch-option-tooltip__background); display: none; max-height: 100%; min-height: 20px; @@ -234,7 +235,6 @@ position: absolute; text-align: center; z-index: 999; - .lib-css(background, @swatch-option-tooltip__background); &, &-layered { @@ -278,9 +278,9 @@ } &-layered { + .lib-css(background, @swatch-option-tooltip-layered__background); .lib-css(border, @swatch-option-tooltip-layered__border); .lib-css(color, @swatch-option-tooltip-layered__color); - .lib-css(background, @swatch-option-tooltip-layered__background); display: none; left: -47px; position: absolute; @@ -326,7 +326,6 @@ margin: 2px 0; padding: 2px; position: static; - z-index: 1; } &-visual-tooltip-layered { From daf0dc67926bde5de6e05f956ff0b09756ed0123 Mon Sep 17 00:00:00 2001 From: niravkrish <niravpatel5393@gmail.com> Date: Mon, 12 Oct 2020 22:08:35 +0530 Subject: [PATCH 16/41] removed unneccesary css to resolve the issue --- lib/web/css/source/components/_modals.less | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/web/css/source/components/_modals.less b/lib/web/css/source/components/_modals.less index 58c9c0674b6ad..8513db545f1ec 100644 --- a/lib/web/css/source/components/_modals.less +++ b/lib/web/css/source/components/_modals.less @@ -103,10 +103,6 @@ &.confirm { .modal-inner-wrap { .lib-css(max-width, @modal-popup-confirm__width); - - .modal-content { - padding-right: 7rem; - } } } From 2bee5bc62a08cba4a46100e5dcb2d1e3d6abbb67 Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Tue, 13 Oct 2020 12:53:35 +0300 Subject: [PATCH 17/41] MC-38113: Same shipping address is repeating multiple times in storefront checkout when Reordered --- ...ckoutFillingShippingSectionActionGroup.xml | 2 +- ...ustomerHasNoOtherAddressesActionGroup.xml} | 4 +-- ...nStartReorderFromOrderPageActionGroup.xml} | 8 ++--- ...eorderAddressNotSavedInAddressBookTest.xml | 36 ++++++++++--------- 4 files changed, 25 insertions(+), 25 deletions(-) rename app/code/Magento/Customer/Test/Mftf/ActionGroup/{AssertStoreFrontCustomerHasNoOtherAddressesActionGroup.xml => AssertStorefrontCustomerHasNoOtherAddressesActionGroup.xml} (79%) rename app/code/Magento/Sales/Test/Mftf/ActionGroup/{AdminReorderActionGroup.xml => AdminStartReorderFromOrderPageActionGroup.xml} (66%) diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml index e1092a87e4a01..d3127362c637e 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml @@ -29,7 +29,7 @@ <waitForElement selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> <waitForLoadingMaskToDisappear stepKey="waitForShippingLoadingMask"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> - <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <waitForElementVisible selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> <seeInCurrentUrl url="{{CheckoutPage.url}}/#payment" stepKey="assertCheckoutPaymentUrl"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStoreFrontCustomerHasNoOtherAddressesActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStorefrontCustomerHasNoOtherAddressesActionGroup.xml similarity index 79% rename from app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStoreFrontCustomerHasNoOtherAddressesActionGroup.xml rename to app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStorefrontCustomerHasNoOtherAddressesActionGroup.xml index 2fde4d915c99f..8634ebb626e6d 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStoreFrontCustomerHasNoOtherAddressesActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStorefrontCustomerHasNoOtherAddressesActionGroup.xml @@ -7,9 +7,9 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AssertStoreFrontCustomerHasNoOtherAddressesActionGroup"> + <actionGroup name="AssertStorefrontCustomerHasNoOtherAddressesActionGroup"> <annotations> - <description>Verifies customer no additional address in address book</description> + <description>Verifies customer has no additional address in address book</description> </annotations> <amOnPage url="customer/address/" stepKey="goToAddressPage"/> <waitForText userInput="You have no other address entries in your address book." selector=".block-addresses-list" stepKey="assertOtherAddresses"/> diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminReorderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminStartReorderFromOrderPageActionGroup.xml similarity index 66% rename from app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminReorderActionGroup.xml rename to app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminStartReorderFromOrderPageActionGroup.xml index f4f076f25af8b..28a179faff9ac 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminReorderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminStartReorderFromOrderPageActionGroup.xml @@ -7,16 +7,14 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminReorderActionGroup"> + <actionGroup name="AdminStartReorderFromOrderPageActionGroup"> <annotations> <description>Reorder existing order. Requires admin order page to be opened.</description> </annotations> <click selector="{{AdminOrderDetailsMainActionsSection.reorder}}" stepKey="clickReorder"/> <waitForPageLoad stepKey="waitPageLoad"/> - - <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="clickSubmit"/> - <waitForPageLoad stepKey="waitOrderCreated"/> - <waitForText selector="{{AdminMessagesSection.success}}" userInput="You created the order." stepKey="seeOrderCreatedMessage"/> + <waitForElementVisible selector="{{AdminHeaderSection.pageTitle}}" stepKey="waitForPageTitle"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="Create New Order" stepKey="seeCreateNewOrderPageTitle"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml index 2b4bb43ec36cd..1c3ab70857151 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderAddressNotSavedInAddressBookTest.xml @@ -9,36 +9,37 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="AdminReorderAddressNotSavedInAddressBookTest"> <annotations> - <title value="Same shipping address is repeating multiple times in storefront checkout when Reordered"/> - <stories value="MC-38113: Same shipping address is repeating multiple times in storefront checkout when Reordered"/> - <description value="Same shipping address is repeating multiple times in storefront checkout when Reordered"/> <features value="Sales"/> - <testCaseId value="MC-38113"/> + <stories value="Reorder"/> + <title value="Same shipping address is not repeating multiple times in storefront checkout when Reordered"/> + <description value="Same shipping address is not repeating multiple times in storefront checkout when Reordered"/> + <testCaseId value="MC-38412"/> + <useCaseId value="MC-38113"/> <severity value="MAJOR"/> - <group value="Sales"/> + <group value="sales"/> </annotations> <before> - <createData entity="ApiCategory" stepKey="Category"/> - <createData entity="ApiSimpleProduct" stepKey="Product"> - <requiredEntity createDataKey="Category"/> + <createData entity="ApiCategory" stepKey="category"/> + <createData entity="ApiSimpleProduct" stepKey="product"> + <requiredEntity createDataKey="category"/> </createData> - <createData entity="Simple_Customer_Without_Address" stepKey="Customer"/> + <createData entity="Simple_Customer_Without_Address" stepKey="customer"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> - <argument name="Customer" value="$Customer$"/> + <argument name="Customer" value="$customer$"/> </actionGroup> </before> <after> + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <deleteData createDataKey="category" stepKey="deleteCategory"/> <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="customerLogout"/> + <deleteData createDataKey="customer" stepKey="deleteCustomer"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="adminLogout"/> - <deleteData createDataKey="Product" stepKey="deleteProduct"/> - <deleteData createDataKey="Category" stepKey="deleteCategory"/> - <deleteData createDataKey="Customer" stepKey="deleteCustomer"/> </after> <!-- Create order for registered customer --> <actionGroup ref="AddSimpleProductToCartActionGroup" stepKey="addSimpleProductToOrder"> - <argument name="product" value="$Product$"/> + <argument name="product" value="$product$"/> </actionGroup> <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="openCheckoutPage"/> <actionGroup ref="LoggedInUserCheckoutFillingShippingSectionActionGroup" stepKey="fillAddressForm"/> @@ -47,11 +48,12 @@ <!-- Reorder created order --> <actionGroup ref="OpenOrderByIdActionGroup" stepKey="openOrderById"> - <argument name="orderId" value="$grabOrderNumber"/> + <argument name="orderId" value="{$grabOrderNumber}"/> </actionGroup> - <actionGroup ref="AdminReorderActionGroup" stepKey="reorder"/> + <actionGroup ref="AdminStartReorderFromOrderPageActionGroup" stepKey="startReorder"/> + <actionGroup ref="AdminSubmitOrderActionGroup" stepKey="submitOrder"/> <!-- Assert no additional addresses saved --> - <actionGroup ref="AssertStoreFrontCustomerHasNoOtherAddressesActionGroup" stepKey="assertAddresses"/> + <actionGroup ref="AssertStorefrontCustomerHasNoOtherAddressesActionGroup" stepKey="assertAddresses"/> </test> </tests> From 56d8eae58d9083552c4d48de39aab94a435b3580 Mon Sep 17 00:00:00 2001 From: IvanPletnyov <ivan.pletnyov@transoftgroup.com> Date: Tue, 13 Oct 2020 13:08:21 +0300 Subject: [PATCH 18/41] MC-38243: Create automated test for "Product Categories Indexer in Update on Schedule mode" --- ...inProductCategoryIndexerInUpdateOnScheduleModeTest.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductCategoryIndexerInUpdateOnScheduleModeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductCategoryIndexerInUpdateOnScheduleModeTest.xml index eebd3472cbd95..3008e89fd9dd1 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductCategoryIndexerInUpdateOnScheduleModeTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductCategoryIndexerInUpdateOnScheduleModeTest.xml @@ -10,17 +10,15 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="AdminProductCategoryIndexerInUpdateOnScheduleModeTest"> <annotations> + <features value="Catalog"/> <stories value="Product Categories Indexer"/> <title value="Product Categories Indexer in Update on Schedule mode"/> <description value="The test verifies that in Update on Schedule mode if displaying of category products on Storefront changes due to product properties change, the changes are NOT applied immediately, but applied only after cron runs (twice)."/> - <severity value="BLOCKER"/> - <testCaseId value="MC-11146"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-26119"/> <group value="catalog"/> <group value="indexer"/> - <skip> - <issueId value="MC-20392"/> - </skip> </annotations> <before> <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> From c72589d3132aa145ae98fbac2095d0b9b3db2965 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Tue, 13 Oct 2020 13:12:38 +0300 Subject: [PATCH 19/41] MC-37070: Create automated test for "Import products with shared images" --- .../Product/Gallery/UpdateHandlerTest.php | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php index ce36b27d51e7d..1101b7291528b 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php @@ -16,6 +16,7 @@ use Magento\Catalog\Model\ResourceModel\Product as ProductResource; use Magento\Catalog\Model\ResourceModel\Product\Gallery; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Directory\WriteInterface; use Magento\Framework\ObjectManagerInterface; @@ -90,6 +91,9 @@ class UpdateHandlerTest extends \PHPUnit\Framework\TestCase */ private $currentStoreId; + /** @var MetadataPool */ + private $metadataPool; + /** * @inheritdoc */ @@ -109,6 +113,7 @@ protected function setUp(): void $this->mediaDirectory = $this->objectManager->get(Filesystem::class) ->getDirectoryWrite(DirectoryList::MEDIA); $this->mediaDirectory->writeFile($this->fileName, 'Test'); + $this->metadataPool = $this->objectManager->get(MetadataPool::class); } /** @@ -534,28 +539,30 @@ private function duplicateMediaGalleryForProduct(string $imagePath, string $prod $product = $this->getProduct(null, $productSku); $connect = $this->galleryResource->getConnection(); $select = $connect->select()->from($this->galleryResource->getMainTable())->where('value = ?', $imagePath); - $res = $connect->fetchRow($select); - $value_id = $res['value_id']; - unset($res['value_id']); + $result = $connect->fetchRow($select); + $value_id = $result['value_id']; + unset($result['value_id']); $rows = [ - 'attribute_id' => $res['attribute_id'], - 'value' => $res['value'], - ProductAttributeMediaGalleryEntryInterface::MEDIA_TYPE => $res['media_type'], - ProductAttributeMediaGalleryEntryInterface::DISABLED => $res['disabled'], + 'attribute_id' => $result['attribute_id'], + 'value' => $result['value'], + ProductAttributeMediaGalleryEntryInterface::MEDIA_TYPE => $result['media_type'], + ProductAttributeMediaGalleryEntryInterface::DISABLED => $result['disabled'], ]; $connect->insert($this->galleryResource->getMainTable(), $rows); $select = $connect->select() ->from($this->galleryResource->getTable(Gallery::GALLERY_VALUE_TABLE)) ->where('value_id = ?', $value_id); - $res = $connect->fetchRow($select); + $result = $connect->fetchRow($select); $newValueId = (int)$value_id + 1; + $metadata = $this->metadataPool->getMetadata(ProductInterface::class); + $linkField = $metadata->getLinkField(); $rows = [ 'value_id' => $newValueId, - 'store_id' => $res['store_id'], - ProductAttributeMediaGalleryEntryInterface::LABEL => $res['label'], - ProductAttributeMediaGalleryEntryInterface::POSITION => $res['position'], - ProductAttributeMediaGalleryEntryInterface::DISABLED => $res['disabled'], - 'row_id' => $product->getRowId(), + 'store_id' => $result['store_id'], + ProductAttributeMediaGalleryEntryInterface::LABEL => $result['label'], + ProductAttributeMediaGalleryEntryInterface::POSITION => $result['position'], + ProductAttributeMediaGalleryEntryInterface::DISABLED => $result['disabled'], + $linkField => $product->getData($linkField), ]; $connect->insert($this->galleryResource->getTable(Gallery::GALLERY_VALUE_TABLE), $rows); $rows = ['value_id' => $newValueId, 'row_id' => $product->getRowId()]; From 12b60201014a997a72823b5cfeaac6ee126b3857 Mon Sep 17 00:00:00 2001 From: IvanPletnyov <ivan.pletnyov@transoftgroup.com> Date: Tue, 13 Oct 2020 13:38:50 +0300 Subject: [PATCH 20/41] MC-37558: Create automated test for "Override Category settings on Store View level" --- .../Controller/Adminhtml/Category/Save/UpdateCategoryTest.php | 2 +- .../testsuite/Magento/Catalog/Model/CategoryRepositoryTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php index c3d5ed080bcf2..75b96a1af3b09 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UpdateCategoryTest.php @@ -45,7 +45,7 @@ protected function setUp(): void * @param array $postData * @return void */ - public function testUpdateCategoryForDefaultStoreView($postData): void + public function testUpdateCategoryForDefaultStoreView(array $postData): void { $storeId = (int)$this->storeManager->getStore('default')->getId(); $postData = array_merge($postData, ['store_id' => $storeId]); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryRepositoryTest.php index 6469f80ff49b8..e829801d60e1a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryRepositoryTest.php @@ -24,6 +24,7 @@ * Provide tests for CategoryRepository model. * * @magentoDbIsolation enabled + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class CategoryRepositoryTest extends TestCase { From 71b027dedf046771e334fd2a9cbf2b648e62201c Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 13 Oct 2020 14:26:30 +0300 Subject: [PATCH 21/41] MC-29411: PHPStan: "Return typehint of method has invalid type " errors --- app/code/Magento/CatalogSearch/Model/Advanced.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/CatalogSearch/Model/Advanced.php b/app/code/Magento/CatalogSearch/Model/Advanced.php index 5143762a07e08..ba58066cae917 100644 --- a/app/code/Magento/CatalogSearch/Model/Advanced.php +++ b/app/code/Magento/CatalogSearch/Model/Advanced.php @@ -359,6 +359,8 @@ protected function getPreparedSearchCriteria($attribute, $value) if (is_array($value)) { if (isset($value['from']) && isset($value['to'])) { if (!empty($value['from']) || !empty($value['to'])) { + $from = ''; + $to = ''; if (isset($value['currency'])) { /** @var $currencyModel Currency */ $currencyModel = $this->_currencyFactory->create()->load($value['currency']); From 3ffc2e809d87b45a07dbd3b439523fb30ff1636b Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Tue, 13 Oct 2020 15:17:09 +0300 Subject: [PATCH 22/41] MC-37070: Create automated test for "Import products with shared images" --- .../Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php index 1101b7291528b..c5221f1ae5e76 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php @@ -565,7 +565,7 @@ private function duplicateMediaGalleryForProduct(string $imagePath, string $prod $linkField => $product->getData($linkField), ]; $connect->insert($this->galleryResource->getTable(Gallery::GALLERY_VALUE_TABLE), $rows); - $rows = ['value_id' => $newValueId, 'row_id' => $product->getRowId()]; + $rows = ['value_id' => $newValueId, $linkField => $product->getData($linkField)]; $connect->insert($this->galleryResource->getTable(Gallery::GALLERY_VALUE_TO_ENTITY_TABLE), $rows); } From e8ad9aee3fe307fce2e0c4b0cdd0661567170ae7 Mon Sep 17 00:00:00 2001 From: Solwininfotech <stdabhoya@yahoo.com> Date: Tue, 13 Oct 2020 17:51:54 +0530 Subject: [PATCH 23/41] removed .content and .fieldset selectors --- .../web/css/source/module/_cart.less | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less index 405bc1d2af373..2c8c52bdb7af2 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less @@ -727,16 +727,14 @@ position: static; } } - .content { - .fieldset { - .actions-toolbar { - width: auto; - } - } - } + &.discount { width: auto; } + + .actions-toolbar { + width: auto; + } } } From 80e33111c3325423ea2fbced8094313a34d87cbb Mon Sep 17 00:00:00 2001 From: Bohdan Shevchenko <1408sheva@gmail.com> Date: Tue, 13 Oct 2020 15:51:36 +0300 Subject: [PATCH 24/41] MC-37546: Create automated test for "Create new Category Update" --- .../StorefrontCheckPresentSubCategoryActionGroup.xml | 2 +- .../AdminCategoryBasicFieldSection.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml index 7d8113f05518b..7cb3287614433 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml @@ -18,6 +18,6 @@ <waitForElement selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(parenCategoryName)}}" stepKey="waitForTopMenuLoaded"/> <moveMouseOver selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(parenCategoryName)}}" stepKey="moveMouseToParentCategory"/> - <seeElement selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(childCategoryName)}}" stepKey="seeCategoryUpdated"/> + <seeElement selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(childCategoryName)}}" stepKey="seeSubcategoryInTree"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryBasicFieldSection/AdminCategoryBasicFieldSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryBasicFieldSection/AdminCategoryBasicFieldSection.xml index aff7ffe4d5763..1b041c5ca306f 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryBasicFieldSection/AdminCategoryBasicFieldSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryBasicFieldSection/AdminCategoryBasicFieldSection.xml @@ -22,5 +22,6 @@ <element name="FieldError" type="text" selector=".admin__field-error[data-bind='attr: {for: {{field}}}, text: error']" parameterized="true"/> <element name="panelFieldControl" type="input" selector="//aside//div[@data-index="{{arg1}}"]/descendant::*[@name="{{arg2}}"]" parameterized="true"/> <element name="productsInCategory" type="input" selector="div[data-index='assign_products']" timeout="30"/> + <element name="scheduleDesignUpdateTab" type="block" selector="div[data-index='schedule_design_update']" timeout="15"/> </section> </sections> From 3b2ece2b3f203c67bc0117e74bf5513f26ed2f35 Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Tue, 13 Oct 2020 17:09:57 +0300 Subject: [PATCH 25/41] MC-38113: Same shipping address is repeating multiple times in storefront checkout when Reordered --- ...oggedInUserCheckoutFillingShippingSectionActionGroup.xml | 6 +++--- ...sertStorefrontCustomerHasNoOtherAddressesActionGroup.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml index d3127362c637e..4b6680442a470 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/LoggedInUserCheckoutFillingShippingSectionActionGroup.xml @@ -24,10 +24,10 @@ <selectOption selector="{{CheckoutShippingSection.region}}" userInput="{{customerAddressVar.state}}" stepKey="selectRegion"/> <fillField selector="{{CheckoutShippingSection.postcode}}" userInput="{{customerAddressVar.postcode}}" stepKey="enterPostcode"/> <fillField selector="{{CheckoutShippingSection.telephone}}" userInput="{{customerAddressVar.telephone}}" stepKey="enterTelephone"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> + <waitForPageLoad stepKey="waitForLoadingMask"/> <click selector="{{CheckoutShippingSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> - <waitForElement selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> - <waitForLoadingMaskToDisappear stepKey="waitForShippingLoadingMask"/> + <waitForElementVisible selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> + <waitForPageLoad stepKey="waitForShippingLoadingMask"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> <waitForElementVisible selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> <seeInCurrentUrl url="{{CheckoutPage.url}}/#payment" stepKey="assertCheckoutPaymentUrl"/> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStorefrontCustomerHasNoOtherAddressesActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStorefrontCustomerHasNoOtherAddressesActionGroup.xml index 8634ebb626e6d..1f56ba505128f 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStorefrontCustomerHasNoOtherAddressesActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AssertStorefrontCustomerHasNoOtherAddressesActionGroup.xml @@ -11,7 +11,7 @@ <annotations> <description>Verifies customer has no additional address in address book</description> </annotations> - <amOnPage url="customer/address/" stepKey="goToAddressPage"/> + <amOnPage url="{{StorefrontCustomerAddressesPage.url}}" stepKey="goToAddressPage"/> <waitForText userInput="You have no other address entries in your address book." selector=".block-addresses-list" stepKey="assertOtherAddresses"/> </actionGroup> </actionGroups> From 4e5ac6783aacb9e78b6cdb095ab2297723899e8d Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Tue, 13 Oct 2020 16:15:30 +0200 Subject: [PATCH 26/41] MC-37896: Create automated test for "Reset Widget" --- .../AdminSaveAndContinueWidgetActionGroup.xml | 21 ++++++ .../AdminSetInputTypeAndDesignActionGroup.xml | 22 +++++++ .../AdminSetWidgetNameAndStoreActionGroup.xml | 24 +++++++ .../Widget/Test/Mftf/Data/WidgetsData.xml | 1 + .../Mftf/Section/AdminNewWidgetSection.xml | 4 +- .../Test/Mftf/Test/AdminResetWidgetTest.xml | 65 +++++++++++++++++++ 6 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetInputTypeAndDesignActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml new file mode 100644 index 0000000000000..d480ea685736d --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml @@ -0,0 +1,21 @@ +<!-- + /** + * 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="AdminSaveAndContinueWidgetActionGroup"> + <annotations> + <description>Click on the Save an Continue button and check the success message</description> + </annotations> + <scrollToTopOfPage stepKey="scrollToTopOfPage"/> + <click selector="{{AdminNewWidgetSection.saveAndContinue}}" stepKey="clickSaveWidget"/> + <waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitForPageLoad"/> + <see selector="{{AdminMessagesSection.success}}" userInput="The widget instance has been saved" stepKey="seeSuccess"/> + </actionGroup> +</actionGroups> + + diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetInputTypeAndDesignActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetInputTypeAndDesignActionGroup.xml new file mode 100644 index 0000000000000..3071f60bbc9d6 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetInputTypeAndDesignActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminSetInputTypeAndDesignActionGroup"> + <annotations> + <description>On the widget_instance page select widget type and design</description> + </annotations> + <arguments> + <argument name="widgetType" defaultValue="{{ProductsListWidget.type}}" type="string"/> + <argument name="widgetDesign" defaultValue="{{ProductsListWidget.design_theme}}" type="string"/> + </arguments> + <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widgetType}}" stepKey="setWidgetType"/> + <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widgetDesign}}" stepKey="setWidgetDesignTheme"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml new file mode 100644 index 0000000000000..80546b9d5e6df --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminSetWidgetNameAndStoreActionGroup"> + <annotations> + <description>On the widget creation page page set widget name, store add sort order.</description> + </annotations> + <arguments> + <argument name="widgetName" defaultValue="{{ProductsListWidget.name}}" type="string"/> + <argument name="widgetStore" defaultValue="{{ProductsListWidget.store_ids}}" type="string"/> + <argument name="widgetSortOrder" defaultValue="{{ProductsListWidget.sort_order}}" type="string"/> + </arguments> + <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widgetName}}" stepKey="fillTitle"/> + <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" parameterArray="[{{widgetStore}}]" stepKey="setWidgetStoreId"/> + <fillField selector="{{AdminNewWidgetSection.widgetSortOrder}}" userInput="{{widgetSortOrder}}" stepKey="fillSortOrder"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/Data/WidgetsData.xml b/app/code/Magento/Widget/Test/Mftf/Data/WidgetsData.xml index ffd2d025548cf..0bac99731ef7b 100644 --- a/app/code/Magento/Widget/Test/Mftf/Data/WidgetsData.xml +++ b/app/code/Magento/Widget/Test/Mftf/Data/WidgetsData.xml @@ -12,6 +12,7 @@ <data key="type">Catalog Products List</data> <data key="design_theme">Magento Luma</data> <data key="name" unique="suffix">TestWidget</data> + <data key="sort_order">0</data> <array key="store_ids"> <item>All Store Views</item> </array> diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index c1ff351823823..2e455f4a3470b 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -12,6 +12,7 @@ <element name="widgetType" type="select" selector="#code"/> <element name="widgetDesignTheme" type="select" selector="#theme_id"/> <element name="continue" type="button" timeout="30" selector="#continue_button"/> + <element name="resetBtn" type="button" selector="#reset" timeout="30"/> <element name="widgetTitle" type="input" selector="#title"/> <element name="widgetStoreIds" type="select" selector="#store_ids"/> <element name="widgetSortOrder" type="input" selector="#sort_order"/> @@ -38,10 +39,11 @@ <element name="searchBlock" type="button" selector="//div[@class='admin__filter-actions']/button[@title='Search']"/> <element name="blockStatus" type="select" selector="//select[@name='chooser_is_active']"/> <element name="searchedBlock" type="button" selector="//*[@class='magento-message']//tbody/tr/td[1]"/> - <element name="saveWidget" type="select" selector="#save"/> + <element name="saveWidget" type="button" selector="#save"/> <element name="displayMode" type="select" selector="select[id*='display_mode']"/> <element name="restrictTypes" type="select" selector="select[id*='types']"/> <element name="saveAndContinue" type="button" selector="#save_and_edit_button" timeout="30"/> + <element name="widgetInstanceType" type="select" selector="#instance_code" /> <!-- Catalog Product List Widget Options --> <element name="title" type="input" selector="[name='parameters[title]']"/> <element name="displayPageControl" type="select" selector="[name='parameters[show_pager]']"/> diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml new file mode 100644 index 0000000000000..3a94871d06e1c --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.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="AdminResetWidgetTest"> + <annotations> + <features value="Widget"/> + <stories value="Reset widget"/> + <title value="[CMS Widgets] Reset Widget"/> + <description value="Check that admin user can reset widget form after filling out all information"/> + <severity value="MAJOR"/> + <testCaseId value="MC-37892"/> + <group value="widget"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <actionGroup ref="AdminDeleteWidgetActionGroup" stepKey="deleteWidget"> + <argument name="widget" value="ProductsListWidget"/> + </actionGroup> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> + </after> + <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> + <actionGroup ref="AdminSetInputTypeAndDesignActionGroup" stepKey="firstSetTypeAndDesign"> + <argument name="widgetType" value="{{ProductsListWidget.type}}"/> + <argument name="widgetDesign" value="{{ProductsListWidget.design_theme}}"/> + </actionGroup> + <click selector="{{AdminNewWidgetSection.resetBtn}}" stepKey="resetInstance"/> + <dontSeeInField userInput="{{ProductsListWidget.type}}" selector="{{AdminNewWidgetSection.widgetType}}" stepKey="dontSeeTypeAfterReset"/> + <dontSeeInField userInput="{{ProductsListWidget.design_theme}}" selector="{{AdminNewWidgetSection.widgetDesignTheme}}" stepKey="dontSeeDesignAfterReset"/> + <actionGroup ref="AdminSetInputTypeAndDesignActionGroup" stepKey="setTypeAndDesignAfterReset"> + <argument name="widgetType" value="{{ProductsListWidget.type}}"/> + <argument name="widgetDesign" value="{{ProductsListWidget.design_theme}}"/> + </actionGroup> + <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> + <actionGroup ref="AdminSetWidgetNameAndStoreActionGroup" stepKey="setNameAndStore"> + <argument name="widgetName" value="{{ProductsListWidget.name}}"/> + <argument name="widgetStore" value="{{ProductsListWidget.store_ids}}"/> + <argument name="widgetSortOrder" value="{{ProductsListWidget.sort_order}}"/> + </actionGroup> + <click selector="{{AdminNewWidgetSection.resetBtn}}" stepKey="resetNameAndStore"/> + <dontSeeInField userInput="{{ProductsListWidget.name}}" selector="{{AdminNewWidgetSection.widgetTitle}}" stepKey="dontSeeNameAfterReset"/> + <dontSeeInField userInput="{{ProductsListWidget.store_ids[0]}}" selector="{{AdminNewWidgetSection.widgetStoreIds}}" stepKey="dontSeeStoreAfterReset"/> + <dontSeeInField userInput="{{ProductsListWidget.sort_order}}" selector="{{AdminNewWidgetSection.widgetSortOrder}}" stepKey="dontSeeSortOrderAfterReset"/> + <actionGroup ref="AdminSetWidgetNameAndStoreActionGroup" stepKey="setNameAndStoreAfterReset"> + <argument name="widgetName" value="{{ProductsListWidget.name}}"/> + <argument name="widgetStore" value="{{ProductsListWidget.store_ids}}"/> + <argument name="widgetSortOrder" value="{{ProductsListWidget.sort_order}}"/> + </actionGroup> + <actionGroup ref="AdminSaveAndContinueWidgetActionGroup" stepKey="saveWidget"/> + <click selector="{{AdminNewWidgetSection.resetBtn}}" stepKey="resetWidget"/> + <seeInField userInput="{{ProductsListWidget.name}}" selector="{{AdminNewWidgetSection.widgetTitle}}" stepKey="seeNameAfterReset"/> + <seeInField userInput="{{ProductsListWidget.store_ids[0]}}" selector="{{AdminNewWidgetSection.widgetStoreIds}}" stepKey="seeStoreAfterReset"/> + <seeInField userInput="{{ProductsListWidget.sort_order}}" selector="{{AdminNewWidgetSection.widgetSortOrder}}" stepKey="seeSortOrderAfterReset"/> + <seeInField userInput="{{ProductsListWidget.type}}" selector="{{AdminNewWidgetSection.widgetInstanceType}}" stepKey="seeTypeAfterReset"/> + <seeInField userInput="{{ProductsListWidget.design_theme}}" selector="{{AdminNewWidgetSection.widgetDesignTheme}}" stepKey="seeThemeAfterReset"/> + </test> +</tests> From fceacabac975f59d29ef75271c4ad638a349810c Mon Sep 17 00:00:00 2001 From: Mykhailo Matiola <mykhailo.matiola@transoftgroup.com> Date: Tue, 13 Oct 2020 17:31:58 +0300 Subject: [PATCH 27/41] MC-36960: Create automated test for "Create product for "all" store views using API service" --- .../ProductRepositoryAllStoreViewsTest.php | 236 ++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php new file mode 100644 index 0000000000000..1d3b4ca591c08 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php @@ -0,0 +1,236 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Api; + +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\ResourceModel\Product\Website\Link; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Registry; +use Magento\Framework\Webapi\Rest\Request; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; + +/** + * Tests for products creation for all store views. + * + * @magentoAppIsolation enabled + */ +class ProductRepositoryAllStoreViewsTest extends WebapiAbstract +{ + const PRODUCT_SERVICE_NAME = 'catalogProductRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const PRODUCTS_RESOURCE_PATH = '/V1/products'; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @var Registry + */ + private $registry; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @var string + */ + private $productSku = 'simple'; + + /** + * @var Link + */ + private $productWebsiteLink; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + $this->objectManager = Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->registry = $this->objectManager->get(Registry::class); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + $this->productWebsiteLink = $this->objectManager->get(Link::class); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + $this->registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', true); + $this->productRepository->delete( + $this->productRepository->get($this->productSku) + ); + $this->registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', false); + + parent::tearDown(); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category.php + */ + public function testCreateProduct(): void + { + $productData = $this->getProductData(); + $resultData = $this->saveProduct($productData); + $this->assertProductWebsites($this->productSku, $this->getAllWebsiteIds()); + $this->assertProductData($productData, $resultData, $this->getAllWebsiteIds()); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category.php + * @magentoApiDataFixture Magento/Store/_files/second_website_with_store_group_and_store.php + */ + public function testCreateProductOnMultipleWebsites(): void + { + $productData = $this->getProductData(); + $resultData = $this->saveProduct($productData); + $this->assertProductWebsites($this->productSku, $this->getAllWebsiteIds()); + $this->assertProductData($productData, $resultData, $this->getAllWebsiteIds()); + } + + /** + * Saves Product via API. + * + * @param $product + * @return array + */ + private function saveProduct($product): array + { + $serviceInfo = [ + 'rest' => ['resourcePath' =>self::PRODUCTS_RESOURCE_PATH, 'httpMethod' => Request::HTTP_METHOD_POST], + 'soap' => [ + 'service' => self::PRODUCT_SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::PRODUCT_SERVICE_NAME . 'Save' + ] + ]; + $requestData = ['product' => $product]; + return $this->_webApiCall($serviceInfo, $requestData, null, 'all'); + } + + /** + * Returns product data. + * + * @return array + */ + private function getProductData(): array + { + return [ + 'sku' => $this->productSku, + 'name' => 'simple', + 'type_id' => Type::TYPE_SIMPLE, + 'weight' => 1, + 'attribute_set_id' => 4, + 'price' => 10, + 'status' => 1, + 'visibility' => 4, + 'extension_attributes' => [ + 'stock_item' => ['is_in_stock' => true, 'qty' => 1000] + ], + 'custom_attributes' => [ + ['attribute_code' => 'url_key', 'value' => 'simple'], + ['attribute_code' => 'tax_class_id', 'value' => 2], + ['attribute_code' => 'category_ids', 'value' => [333]] + ] + ]; + } + + /** + * Asserts that product is linked to websites in 'catalog_product_website' table. + * + * @param string $sku + * @param array $websiteIds + * @return void + */ + private function assertProductWebsites(string $sku, array $websiteIds): void + { + $productId = $this->productRepository->get($sku)->getId(); + $this->assertEquals($websiteIds, $this->productWebsiteLink->getWebsiteIdsByProductId($productId)); + } + + /** + * Asserts result after product creation. + * + * @param array $productData + * @param array $resultData + * @param array $websiteIds + * @return void + */ + private function assertProductData(array $productData, array $resultData, array $websiteIds): void + { + foreach ($productData as $key => $value) { + if ($key == 'extension_attributes' || $key == 'custom_attributes') { + continue; + } + $this->assertEquals($value, $resultData[$key]); + } + foreach ($productData['custom_attributes'] as $attribute) { + $resultAttribute = $this->getCustomAttributeByCode( + $resultData['custom_attributes'], + $attribute['attribute_code'] + ); + $this->assertEquals($attribute['value'], $resultAttribute['value']); + } + foreach ($productData['extension_attributes']['stock_item'] as $key => $value) { + $this->assertEquals($value, $resultData['extension_attributes']['stock_item'][$key]); + } + $this->assertEquals($websiteIds, $resultData['extension_attributes']['website_ids']); + } + + /** + * Get list of all websites IDs. + * + * @return array + */ + private function getAllWebsiteIds(): array + { + $websiteIds = []; + $websites = $this->storeManager->getWebsites(); + foreach ($websites as $website) { + $websiteIds[] = $website->getId(); + } + + return $websiteIds; + } + + /** + * Returns custom attribute data by given code. + * + * @param array $attributes + * @param string $attributeCode + * @return array + */ + private function getCustomAttributeByCode(array $attributes, string $attributeCode): array + { + $items = array_filter( + $attributes, + function ($attribute) use ($attributeCode) { + return $attribute['attribute_code'] == $attributeCode; + } + ); + + return reset($items); + } +} From 4c1243c56ba28eb8e68a111b34115a91993066f4 Mon Sep 17 00:00:00 2001 From: Mykhailo Matiola <mykhailo.matiola@transoftgroup.com> Date: Tue, 13 Oct 2020 17:43:50 +0300 Subject: [PATCH 28/41] MC-36960: Create automated test for "Create product for "all" store views using API service" --- .../ProductRepositoryAllStoreViewsTest.php | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php index 1d3b4ca591c08..2950dda4b3c52 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php @@ -7,8 +7,12 @@ namespace Magento\Catalog\Api; +use Magento\Catalog\Api\Data\ProductAttributeInterface; +use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Visibility; use Magento\Catalog\Model\ResourceModel\Product\Website\Link; +use Magento\Eav\Model\Config; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Registry; use Magento\Framework\Webapi\Rest\Request; @@ -48,14 +52,18 @@ class ProductRepositoryAllStoreViewsTest extends WebapiAbstract private $storeManager; /** - * @var string + * @var Link */ - private $productSku = 'simple'; + private $productWebsiteLink; + /** + * @var Config + */ + private $eavConfig; /** - * @var Link + * @var string */ - private $productWebsiteLink; + private $productSku = 'simple'; /** * @inheritdoc @@ -66,6 +74,7 @@ protected function setUp(): void $this->objectManager = Bootstrap::getObjectManager(); $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); $this->productRepository->cleanCache(); + $this->eavConfig = $this->objectManager->get(Config::class); $this->registry = $this->objectManager->get(Registry::class); $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); $this->productWebsiteLink = $this->objectManager->get(Link::class); @@ -137,15 +146,18 @@ private function saveProduct($product): array */ private function getProductData(): array { + $setId =(int)$this->eavConfig->getEntityType(ProductAttributeInterface::ENTITY_TYPE_CODE) + ->getDefaultAttributeSetId(); + return [ 'sku' => $this->productSku, 'name' => 'simple', 'type_id' => Type::TYPE_SIMPLE, 'weight' => 1, - 'attribute_set_id' => 4, + 'attribute_set_id' => $setId, 'price' => 10, - 'status' => 1, - 'visibility' => 4, + 'status' => Status::STATUS_ENABLED, + 'visibility' => Visibility::VISIBILITY_BOTH, 'extension_attributes' => [ 'stock_item' => ['is_in_stock' => true, 'qty' => 1000] ], From 1c2d999aa225cb0f06c80ca34df6b0eb561e68eb Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 13 Oct 2020 18:17:17 +0300 Subject: [PATCH 29/41] MC-29405: PHPStan: "Class does not have a constructor and must be instantiated without any parameters" errors --- .../Attribute/Backend/BillingTest.php | 5 +--- .../Attribute/Backend/ShippingTest.php | 5 +--- .../Design/Config/Edit/SaveButtonTest.php | 23 +------------------ .../Test/Unit/Topology/QueueInstallerTest.php | 3 +-- .../Module/Dependency/ServiceLocator.php | 2 +- 5 files changed, 5 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php index cd7154de14858..4f318948097cc 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php @@ -23,10 +23,7 @@ class BillingTest extends TestCase protected function setUp(): void { - $logger = $this->getMockBuilder(LoggerInterface::class) - ->getMock(); - /** @var LoggerInterface $logger */ - $this->testable = new Billing($logger); + $this->testable = new Billing(); } public function testBeforeSave() diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/ShippingTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/ShippingTest.php index 3947a01582313..6270905ca2e85 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/ShippingTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/ShippingTest.php @@ -23,10 +23,7 @@ class ShippingTest extends TestCase protected function setUp(): void { - $logger = $this->getMockBuilder(LoggerInterface::class) - ->getMock(); - /** @var LoggerInterface $logger */ - $this->testable = new Shipping($logger); + $this->testable = new Shipping(); } public function testBeforeSave() diff --git a/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/SaveButtonTest.php b/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/SaveButtonTest.php index 65e2b934741ee..0ce450df39b59 100644 --- a/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/SaveButtonTest.php +++ b/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/SaveButtonTest.php @@ -20,16 +20,9 @@ class SaveButtonTest extends TestCase */ protected $block; - /** - * @var Context|MockObject - */ - protected $context; - protected function setUp(): void { - $this->initContext(); - - $this->block = new SaveButton($this->context); + $this->block = new SaveButton(); } public function testGetButtonData() @@ -41,18 +34,4 @@ public function testGetButtonData() $this->assertArrayHasKey('data_attribute', $result); $this->assertIsArray($result['data_attribute']); } - - protected function initContext() - { - $this->urlBuilder = $this->getMockBuilder(UrlInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->context = $this->getMockBuilder(Context::class) - ->disableOriginalConstructor() - ->getMock(); - $this->context->expects($this->any()) - ->method('getUrlBuilder') - ->willReturn($this->urlBuilder); - } } diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/QueueInstallerTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/QueueInstallerTest.php index 7493d1691699a..44d33362ae26e 100644 --- a/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/QueueInstallerTest.php +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/QueueInstallerTest.php @@ -16,8 +16,7 @@ class QueueInstallerTest extends TestCase { public function testInstall() { - $bindingInstaller = $this->getMockForAbstractClass(QueueConfigItemInterface::class); - $model = new QueueInstaller($bindingInstaller); + $model = new QueueInstaller(); $channel = $this->createMock(AMQPChannel::class); $queue = $this->getMockForAbstractClass(QueueConfigItemInterface::class); diff --git a/setup/src/Magento/Setup/Module/Dependency/ServiceLocator.php b/setup/src/Magento/Setup/Module/Dependency/ServiceLocator.php index 27f0c7e8e616f..d162d07b38cf8 100644 --- a/setup/src/Magento/Setup/Module/Dependency/ServiceLocator.php +++ b/setup/src/Magento/Setup/Module/Dependency/ServiceLocator.php @@ -95,7 +95,7 @@ public static function getCircularDependenciesReportBuilder() self::$circularDependenciesReportBuilder = new CircularReport\Builder( self::getComposerJsonParser(), new CircularReport\Writer(self::getCsvWriter()), - new CircularTool([], null) + new CircularTool() ); } return self::$circularDependenciesReportBuilder; From 19da476f971c476909713ac6425f454b7ac4cc79 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Tue, 13 Oct 2020 17:21:26 +0200 Subject: [PATCH 30/41] MC-37896: Create automated test for "Reset Widget" --- .../ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml | 2 -- .../ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml | 4 ++-- .../Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml index d480ea685736d..cd9774f3b13ba 100644 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml @@ -17,5 +17,3 @@ <see selector="{{AdminMessagesSection.success}}" userInput="The widget instance has been saved" stepKey="seeSuccess"/> </actionGroup> </actionGroups> - - diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml index 80546b9d5e6df..f1faadb1e434e 100644 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml @@ -14,11 +14,11 @@ </annotations> <arguments> <argument name="widgetName" defaultValue="{{ProductsListWidget.name}}" type="string"/> - <argument name="widgetStore" defaultValue="{{ProductsListWidget.store_ids}}" type="string"/> + <argument name="widgetStoreIds" defaultValue="{{ProductsListWidget.store_ids}}" type="string"/> <argument name="widgetSortOrder" defaultValue="{{ProductsListWidget.sort_order}}" type="string"/> </arguments> <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widgetName}}" stepKey="fillTitle"/> - <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" parameterArray="[{{widgetStore}}]" stepKey="setWidgetStoreId"/> + <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" parameterArray="{{widgetStoreIds}}" stepKey="setWidgetStoreId"/> <fillField selector="{{AdminNewWidgetSection.widgetSortOrder}}" userInput="{{widgetSortOrder}}" stepKey="fillSortOrder"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml index 3a94871d06e1c..88610d9143bb4 100644 --- a/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml @@ -42,7 +42,7 @@ <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> <actionGroup ref="AdminSetWidgetNameAndStoreActionGroup" stepKey="setNameAndStore"> <argument name="widgetName" value="{{ProductsListWidget.name}}"/> - <argument name="widgetStore" value="{{ProductsListWidget.store_ids}}"/> + <argument name="widgetStoreIds" value="{{ProductsListWidget.store_ids}}"/> <argument name="widgetSortOrder" value="{{ProductsListWidget.sort_order}}"/> </actionGroup> <click selector="{{AdminNewWidgetSection.resetBtn}}" stepKey="resetNameAndStore"/> @@ -51,7 +51,7 @@ <dontSeeInField userInput="{{ProductsListWidget.sort_order}}" selector="{{AdminNewWidgetSection.widgetSortOrder}}" stepKey="dontSeeSortOrderAfterReset"/> <actionGroup ref="AdminSetWidgetNameAndStoreActionGroup" stepKey="setNameAndStoreAfterReset"> <argument name="widgetName" value="{{ProductsListWidget.name}}"/> - <argument name="widgetStore" value="{{ProductsListWidget.store_ids}}"/> + <argument name="widgetStoreIds" value="{{ProductsListWidget.store_ids}}"/> <argument name="widgetSortOrder" value="{{ProductsListWidget.sort_order}}"/> </actionGroup> <actionGroup ref="AdminSaveAndContinueWidgetActionGroup" stepKey="saveWidget"/> From e4c227d3caf825c787d4d84dc1e25f55177d4656 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Thu, 15 Oct 2020 11:44:07 +0300 Subject: [PATCH 31/41] MC-37070: Create automated test for "Import products with shared images" --- .../Catalog/Model/Product/Gallery/UpdateHandlerTest.php | 5 ++++- .../Model/Import/ImportWithSharedImagesTest.php | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php index c5221f1ae5e76..2d94466939dbe 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php @@ -86,12 +86,15 @@ class UpdateHandlerTest extends \PHPUnit\Framework\TestCase * @var StoreManagerInterface */ private $storeManager; + /** * @var int */ private $currentStoreId; - /** @var MetadataPool */ + /** + * @var MetadataPool + */ private $metadataPool; /** diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ImportWithSharedImagesTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ImportWithSharedImagesTest.php index 4c04e5a8814e5..35d4cceb50845 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ImportWithSharedImagesTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ImportWithSharedImagesTest.php @@ -10,6 +10,7 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product as ProductEntity; use Magento\Catalog\Model\Product\Media\ConfigInterface; +use Magento\Framework\App\Bootstrap as AppBootstrap; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Filesystem; @@ -82,7 +83,7 @@ protected function setUp(): void $this->csvFactory = $this->objectManager->get(CsvFactory::class); $this->importDataResource = $this->objectManager->get(Data::class); $this->appParams = Bootstrap::getInstance()->getBootstrap()->getApplication() - ->getInitParams()[\Magento\Framework\App\Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]; + ->getInitParams()[AppBootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]; } /** From 43e5b5c901f27478134fe6b2203648684498bb79 Mon Sep 17 00:00:00 2001 From: Mykhailo Matiola <mykhailo.matiola@transoftgroup.com> Date: Thu, 15 Oct 2020 11:50:32 +0300 Subject: [PATCH 32/41] MC-36960: Create automated test for "Create product for "all" store views using API service" --- .../ProductRepositoryAllStoreViewsTest.php | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php index 2950dda4b3c52..2814a6ab05321 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php @@ -8,11 +8,13 @@ namespace Magento\Catalog\Api; use Magento\Catalog\Api\Data\ProductAttributeInterface; +use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\Product\Type; use Magento\Catalog\Model\Product\Visibility; use Magento\Catalog\Model\ResourceModel\Product\Website\Link; use Magento\Eav\Model\Config; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Registry; use Magento\Framework\Webapi\Rest\Request; @@ -24,6 +26,7 @@ * Tests for products creation for all store views. * * @magentoAppIsolation enabled + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ProductRepositoryAllStoreViewsTest extends WebapiAbstract { @@ -55,6 +58,7 @@ class ProductRepositoryAllStoreViewsTest extends WebapiAbstract * @var Link */ private $productWebsiteLink; + /** * @var Config */ @@ -87,9 +91,11 @@ protected function tearDown(): void { $this->registry->unregister('isSecureArea'); $this->registry->register('isSecureArea', true); - $this->productRepository->delete( - $this->productRepository->get($this->productSku) - ); + try { + $this->productRepository->deleteById($this->productSku); + } catch (NoSuchEntityException $e) { + //already deleted + } $this->registry->unregister('isSecureArea'); $this->registry->register('isSecureArea', false); @@ -98,6 +104,7 @@ protected function tearDown(): void /** * @magentoApiDataFixture Magento/Catalog/_files/category.php + * @return void */ public function testCreateProduct(): void { @@ -110,6 +117,7 @@ public function testCreateProduct(): void /** * @magentoApiDataFixture Magento/Catalog/_files/category.php * @magentoApiDataFixture Magento/Store/_files/second_website_with_store_group_and_store.php + * @return void */ public function testCreateProductOnMultipleWebsites(): void { @@ -120,12 +128,12 @@ public function testCreateProductOnMultipleWebsites(): void } /** - * Saves Product via API. + * Saves product via API. * - * @param $product + * @param array $product * @return array */ - private function saveProduct($product): array + private function saveProduct(array $product): array { $serviceInfo = [ 'rest' => ['resourcePath' =>self::PRODUCTS_RESOURCE_PATH, 'httpMethod' => Request::HTTP_METHOD_POST], @@ -146,22 +154,22 @@ private function saveProduct($product): array */ private function getProductData(): array { - $setId =(int)$this->eavConfig->getEntityType(ProductAttributeInterface::ENTITY_TYPE_CODE) + $setId = (int)$this->eavConfig->getEntityType(ProductAttributeInterface::ENTITY_TYPE_CODE) ->getDefaultAttributeSetId(); return [ - 'sku' => $this->productSku, - 'name' => 'simple', - 'type_id' => Type::TYPE_SIMPLE, - 'weight' => 1, - 'attribute_set_id' => $setId, - 'price' => 10, - 'status' => Status::STATUS_ENABLED, - 'visibility' => Visibility::VISIBILITY_BOTH, - 'extension_attributes' => [ + ProductInterface::SKU => $this->productSku, + ProductInterface::NAME => 'simple', + ProductInterface::TYPE_ID => Type::TYPE_SIMPLE, + ProductInterface::WEIGHT => 1, + ProductInterface::ATTRIBUTE_SET_ID => $setId, + ProductInterface::PRICE => 10, + ProductInterface::STATUS => Status::STATUS_ENABLED, + ProductInterface::VISIBILITY => Visibility::VISIBILITY_BOTH, + ProductInterface::EXTENSION_ATTRIBUTES_KEY => [ 'stock_item' => ['is_in_stock' => true, 'qty' => 1000] ], - 'custom_attributes' => [ + ProductInterface::CUSTOM_ATTRIBUTES => [ ['attribute_code' => 'url_key', 'value' => 'simple'], ['attribute_code' => 'tax_class_id', 'value' => 2], ['attribute_code' => 'category_ids', 'value' => [333]] @@ -219,8 +227,7 @@ private function assertProductData(array $productData, array $resultData, array private function getAllWebsiteIds(): array { $websiteIds = []; - $websites = $this->storeManager->getWebsites(); - foreach ($websites as $website) { + foreach ($this->storeManager->getWebsites() as $website) { $websiteIds[] = $website->getId(); } From 3bacacefdd32ea4665e7d185689ecd345e43c50f Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Thu, 15 Oct 2020 15:27:46 +0300 Subject: [PATCH 33/41] MC-29402: PHPStan: "Anonymous function has an unused use" errors --- .../ProductRepository/TransactionWrapperTest.php | 2 +- .../Model/Resolver/TierPrices.php | 2 +- .../Magento/Customer/Controller/Adminhtml/Index.php | 2 +- .../CustomerRepository/TransactionWrapperTest.php | 2 +- .../Magento/Swatches/Model/AttributeCreateTest.php | 4 ++-- .../Swatches/Model/SwatchAttributeOptionAddTest.php | 2 +- .../Magento/Framework/Setup/ExternalFKSetup.php | 6 +++--- .../Setup/Console/Command/AdminUserCreateCommand.php | 7 ++++--- .../Setup/Console/Command/RollbackCommand.php | 6 +++--- .../Fixtures/AttributeSet/SwatchesGenerator.php | 3 ++- .../Magento/Setup/Fixtures/EavVariationsFixture.php | 12 ++++++++---- 11 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Plugin/ProductRepository/TransactionWrapperTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Plugin/ProductRepository/TransactionWrapperTest.php index c60ef266b7ebb..89243ea30c9dc 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Plugin/ProductRepository/TransactionWrapperTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Plugin/ProductRepository/TransactionWrapperTest.php @@ -62,7 +62,7 @@ protected function setUp(): void $this->closureMock = function () use ($productMock) { return $productMock; }; - $this->rollbackClosureMock = function () use ($productMock) { + $this->rollbackClosureMock = function () { throw new \Exception(self::ERROR_MSG); }; diff --git a/app/code/Magento/CatalogCustomerGraphQl/Model/Resolver/TierPrices.php b/app/code/Magento/CatalogCustomerGraphQl/Model/Resolver/TierPrices.php index c449d0a2ba30b..675bdaa5f1db0 100644 --- a/app/code/Magento/CatalogCustomerGraphQl/Model/Resolver/TierPrices.php +++ b/app/code/Magento/CatalogCustomerGraphQl/Model/Resolver/TierPrices.php @@ -87,7 +87,7 @@ public function resolve( $this->tiers->addProductFilter($productId); return $this->valueFactory->create( - function () use ($productId, $context) { + function () use ($productId) { $tierPrices = $this->tiers->getProductTierPrices($productId); return $tierPrices ?? []; diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index.php b/app/code/Magento/Customer/Controller/Adminhtml/Index.php index 51dc39a2fc658..f03f55b16e0c7 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index.php @@ -291,7 +291,7 @@ protected function _addSessionErrorMessages($messages) $messages = (array)$messages; $session = $this->_getSession(); - $callback = function ($error) use ($session) { + $callback = function ($error) { if (!$error instanceof Error) { $error = new Error($error); } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerRepository/TransactionWrapperTest.php b/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerRepository/TransactionWrapperTest.php index c00b5cce02146..634b0d73219db 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerRepository/TransactionWrapperTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerRepository/TransactionWrapperTest.php @@ -62,7 +62,7 @@ protected function setUp(): void $this->closureMock = function () use ($customerMock) { return $customerMock; }; - $this->rollbackClosureMock = function () use ($customerMock) { + $this->rollbackClosureMock = function () { throw new \Exception(self::ERROR_MSG); }; diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeCreateTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeCreateTest.php index 98297cd43041f..b9ec091003267 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeCreateTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeCreateTest.php @@ -52,7 +52,7 @@ function ($values, $index) use ($optionsPerAttribute) { ); $data['optionvisual']['value'] = array_reduce( range(1, $optionsPerAttribute), - function ($values, $index) use ($optionsPerAttribute) { + function ($values, $index) { $values['option_' . $index] = ['option ' . $index]; return $values; }, @@ -61,7 +61,7 @@ function ($values, $index) use ($optionsPerAttribute) { $data['options']['option'] = array_reduce( range(1, $optionsPerAttribute), - function ($values, $index) use ($optionsPerAttribute) { + function ($values, $index) { $values[] = [ 'label' => 'option ' . $index, 'value' => 'option_' . $index diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php index ccf25fd15c529..06ba28932eeb5 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeOptionAddTest.php @@ -40,7 +40,7 @@ public function testSwatchOptionAdd() $data['options']['option'] = array_reduce( range(10, $optionsPerAttribute), - function ($values, $index) use ($optionsPerAttribute) { + function ($values, $index) { $values[] = [ 'label' => 'option ' . $index, 'value' => 'option_' . $index diff --git a/lib/internal/Magento/Framework/Setup/ExternalFKSetup.php b/lib/internal/Magento/Framework/Setup/ExternalFKSetup.php index 4247b7b1aab2f..3d3bb5b6578a9 100644 --- a/lib/internal/Magento/Framework/Setup/ExternalFKSetup.php +++ b/lib/internal/Magento/Framework/Setup/ExternalFKSetup.php @@ -92,10 +92,10 @@ protected function execute() /** * Get foreign keys for tables and columns * - * @param string $refTable - * @param string $refColumn * @param string $targetTable * @param string $targetColumn + * @param string $refTable + * @param string $refColumn * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -110,7 +110,7 @@ protected function getForeignKeys( ); $foreignKeys = array_filter( $foreignKeys, - function ($key) use ($targetColumn, $refTable, $refColumn) { + function ($key) use ($targetColumn, $refTable) { return $key['COLUMN_NAME'] == $targetColumn && $key['REF_TABLE_NAME'] == $refTable; } diff --git a/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php b/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php index 173ea9e49a8a4..8e64aae20573c 100644 --- a/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php +++ b/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php @@ -7,6 +7,7 @@ namespace Magento\Setup\Console\Command; use Magento\Framework\Setup\ConsoleLogger; +use Magento\Framework\Validation\ValidationException; use Magento\Setup\Model\AdminAccount; use Magento\Setup\Model\InstallerFactory; use Magento\User\Model\UserValidationRules; @@ -81,7 +82,7 @@ protected function interact(InputInterface $input, OutputInterface $output) $question = new Question('<question>Admin password:</question> ', ''); $question->setHidden(true); - $question->setValidator(function ($value) use ($output) { + $question->setValidator(function ($value) { $user = new \Magento\Framework\DataObject(); $user->setPassword($value); @@ -90,7 +91,7 @@ protected function interact(InputInterface $input, OutputInterface $output) $validator->isValid($user); foreach ($validator->getMessages() as $message) { - throw new \Exception($message); + throw new ValidationException(__($message)); } return $value; @@ -143,7 +144,7 @@ private function addNotEmptyValidator(Question $question) { $question->setValidator(function ($value) { if (trim($value) == '') { - throw new \Exception('The value cannot be empty'); + throw new ValidationException(__('The value cannot be empty')); } return $value; diff --git a/setup/src/Magento/Setup/Console/Command/RollbackCommand.php b/setup/src/Magento/Setup/Console/Command/RollbackCommand.php index a9138b9faefa1..e4616ae5e271b 100644 --- a/setup/src/Magento/Setup/Console/Command/RollbackCommand.php +++ b/setup/src/Magento/Setup/Console/Command/RollbackCommand.php @@ -80,7 +80,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritDoc */ protected function configure() { @@ -111,7 +111,7 @@ protected function configure() } /** - * {@inheritdoc} + * @inheritDoc */ protected function execute(InputInterface $input, OutputInterface $output) { @@ -123,7 +123,7 @@ protected function execute(InputInterface $input, OutputInterface $output) return \Magento\Framework\Console\Cli::RETURN_FAILURE; } $returnValue = $this->maintenanceModeEnabler->executeInMaintenanceMode( - function () use ($input, $output, &$returnValue) { + function () use ($input, $output) { try { $helper = $this->getHelper('question'); $question = new ConfirmationQuestion( diff --git a/setup/src/Magento/Setup/Fixtures/AttributeSet/SwatchesGenerator.php b/setup/src/Magento/Setup/Fixtures/AttributeSet/SwatchesGenerator.php index 26e7857703b4f..56263d0ec0adb 100644 --- a/setup/src/Magento/Setup/Fixtures/AttributeSet/SwatchesGenerator.php +++ b/setup/src/Magento/Setup/Fixtures/AttributeSet/SwatchesGenerator.php @@ -91,7 +91,7 @@ function ($values, $index) use ($optionCount, $data, $type) { ); $attribute['optionvisual']['value'] = array_reduce( range(1, $optionCount), - function ($values, $index) use ($optionCount) { + function ($values, $index) { $values['option_' . $index] = ['option ' . $index]; return $values; }, @@ -129,6 +129,7 @@ private function generateSwatchImage($data) $this->imagesGenerator = $this->imagesGeneratorFactory->create(); } + // phpcs:ignore Magento2.Security.InsecureFunction $imageName = md5($data) . '.jpg'; $this->imagesGenerator->generate([ 'image-width' => self::GENERATED_SWATCH_WIDTH, diff --git a/setup/src/Magento/Setup/Fixtures/EavVariationsFixture.php b/setup/src/Magento/Setup/Fixtures/EavVariationsFixture.php index f143685f1903d..671627bcea8a9 100644 --- a/setup/src/Magento/Setup/Fixtures/EavVariationsFixture.php +++ b/setup/src/Magento/Setup/Fixtures/EavVariationsFixture.php @@ -77,7 +77,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritDoc */ public function execute() { @@ -93,7 +93,7 @@ public function execute() } /** - * {@inheritdoc} + * @inheritDoc */ public function getActionTitle() { @@ -101,7 +101,7 @@ public function getActionTitle() } /** - * {@inheritdoc} + * @inheritDoc */ public function introduceParamLabels() { @@ -109,6 +109,8 @@ public function introduceParamLabels() } /** + * Generate Attribute + * * @param int $optionCount * @return void */ @@ -169,7 +171,7 @@ function ($values, $index) use ($optionCount) { ); $data['optionvisual']['value'] = array_reduce( range(1, $optionCount), - function ($values, $index) use ($optionCount) { + function ($values, $index) { $values['option_' . $index] = ['option ' . $index]; return $values; }, @@ -194,6 +196,8 @@ function ($values, $index) use ($optionCount) { } /** + * Get attribute code + * * @return string */ private function getAttributeCode() From 64978b41efdaf05ef59961278b0c882ac87c209b Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Thu, 15 Oct 2020 15:12:27 +0200 Subject: [PATCH 34/41] MC-37896: Create automated test for "Reset Widget" --- .../AdminSaveAndContinueWidgetActionGroup.xml | 2 +- .../AdminSetWidgetNameAndStoreActionGroup.xml | 7 ++++--- ...AdminSetWidgetTypeAndDesignActionGroup.xml} | 5 +++-- .../Mftf/Section/AdminNewWidgetSection.xml | 6 +++--- .../Test/Mftf/Test/AdminResetWidgetTest.xml | 18 +++++++++--------- 5 files changed, 20 insertions(+), 18 deletions(-) rename app/code/Magento/Widget/Test/Mftf/ActionGroup/{AdminSetInputTypeAndDesignActionGroup.xml => AdminSetWidgetTypeAndDesignActionGroup.xml} (77%) diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml index cd9774f3b13ba..6d17a5c687b1a 100644 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSaveAndContinueWidgetActionGroup.xml @@ -13,7 +13,7 @@ </annotations> <scrollToTopOfPage stepKey="scrollToTopOfPage"/> <click selector="{{AdminNewWidgetSection.saveAndContinue}}" stepKey="clickSaveWidget"/> - <waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitForPageLoad"/> + <waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitForSuccessMessageAppeared"/> <see selector="{{AdminMessagesSection.success}}" userInput="The widget instance has been saved" stepKey="seeSuccess"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml index f1faadb1e434e..ce19c1b086328 100644 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetNameAndStoreActionGroup.xml @@ -10,14 +10,15 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminSetWidgetNameAndStoreActionGroup"> <annotations> - <description>On the widget creation page page set widget name, store add sort order.</description> + <description>Set widget name, store IDs and sort order on Widget edit page</description> </annotations> <arguments> - <argument name="widgetName" defaultValue="{{ProductsListWidget.name}}" type="string"/> + <argument name="widgetTitle" defaultValue="{{ProductsListWidget.name}}" type="string"/> <argument name="widgetStoreIds" defaultValue="{{ProductsListWidget.store_ids}}" type="string"/> <argument name="widgetSortOrder" defaultValue="{{ProductsListWidget.sort_order}}" type="string"/> </arguments> - <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widgetName}}" stepKey="fillTitle"/> + <waitForElementVisible selector="{{AdminNewWidgetSection.widgetTitle}}" stepKey="waitForWidgetTitleInputVisible"/> + <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widgetTitle}}" stepKey="fillTitle"/> <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" parameterArray="{{widgetStoreIds}}" stepKey="setWidgetStoreId"/> <fillField selector="{{AdminNewWidgetSection.widgetSortOrder}}" userInput="{{widgetSortOrder}}" stepKey="fillSortOrder"/> </actionGroup> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetInputTypeAndDesignActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetTypeAndDesignActionGroup.xml similarity index 77% rename from app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetInputTypeAndDesignActionGroup.xml rename to app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetTypeAndDesignActionGroup.xml index 3071f60bbc9d6..3a9b4c53572c7 100644 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetInputTypeAndDesignActionGroup.xml +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminSetWidgetTypeAndDesignActionGroup.xml @@ -8,14 +8,15 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminSetInputTypeAndDesignActionGroup"> + <actionGroup name="AdminSetWidgetTypeAndDesignActionGroup"> <annotations> - <description>On the widget_instance page select widget type and design</description> + <description>Select type and design on Widget edit page</description> </annotations> <arguments> <argument name="widgetType" defaultValue="{{ProductsListWidget.type}}" type="string"/> <argument name="widgetDesign" defaultValue="{{ProductsListWidget.design_theme}}" type="string"/> </arguments> + <waitForElementVisible selector="{{AdminNewWidgetSection.widgetType}}" stepKey="waitForTypeInputVisible"/> <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widgetType}}" stepKey="setWidgetType"/> <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widgetDesign}}" stepKey="setWidgetDesignTheme"/> </actionGroup> diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index 2e455f4a3470b..805c55f34ce9a 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -12,7 +12,7 @@ <element name="widgetType" type="select" selector="#code"/> <element name="widgetDesignTheme" type="select" selector="#theme_id"/> <element name="continue" type="button" timeout="30" selector="#continue_button"/> - <element name="resetBtn" type="button" selector="#reset" timeout="30"/> + <element name="resetBtn" type="button" selector="//*[@class='page-actions-buttons']/button[@id='reset']" timeout="30"/> <element name="widgetTitle" type="input" selector="#title"/> <element name="widgetStoreIds" type="select" selector="#store_ids"/> <element name="widgetSortOrder" type="input" selector="#sort_order"/> @@ -39,11 +39,11 @@ <element name="searchBlock" type="button" selector="//div[@class='admin__filter-actions']/button[@title='Search']"/> <element name="blockStatus" type="select" selector="//select[@name='chooser_is_active']"/> <element name="searchedBlock" type="button" selector="//*[@class='magento-message']//tbody/tr/td[1]"/> - <element name="saveWidget" type="button" selector="#save"/> + <element name="saveWidget" type="button" selector="#save" timeout="30"/> <element name="displayMode" type="select" selector="select[id*='display_mode']"/> <element name="restrictTypes" type="select" selector="select[id*='types']"/> <element name="saveAndContinue" type="button" selector="#save_and_edit_button" timeout="30"/> - <element name="widgetInstanceType" type="select" selector="#instance_code" /> + <element name="widgetInstanceType" type="select" selector="//*[@class='admin__field-control control']/select[@id='instance_code']" /> <!-- Catalog Product List Widget Options --> <element name="title" type="input" selector="[name='parameters[title]']"/> <element name="displayPageControl" type="select" selector="[name='parameters[show_pager]']"/> diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml index 88610d9143bb4..fd9ce8f3c37e9 100644 --- a/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml @@ -11,8 +11,8 @@ <test name="AdminResetWidgetTest"> <annotations> <features value="Widget"/> - <stories value="Reset widget"/> - <title value="[CMS Widgets] Reset Widget"/> + <stories value="CMS Widgets"/> + <title value="Reset Widget"/> <description value="Check that admin user can reset widget form after filling out all information"/> <severity value="MAJOR"/> <testCaseId value="MC-37892"/> @@ -23,25 +23,25 @@ </before> <after> <actionGroup ref="AdminDeleteWidgetActionGroup" stepKey="deleteWidget"> - <argument name="widget" value="ProductsListWidget"/> + <argument name="widget" value="{{ProductsListWidget}}"/> </actionGroup> <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </after> <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> - <actionGroup ref="AdminSetInputTypeAndDesignActionGroup" stepKey="firstSetTypeAndDesign"> + <actionGroup ref="AdminSetWidgetTypeAndDesignActionGroup" stepKey="firstSetTypeAndDesign"> <argument name="widgetType" value="{{ProductsListWidget.type}}"/> <argument name="widgetDesign" value="{{ProductsListWidget.design_theme}}"/> </actionGroup> <click selector="{{AdminNewWidgetSection.resetBtn}}" stepKey="resetInstance"/> <dontSeeInField userInput="{{ProductsListWidget.type}}" selector="{{AdminNewWidgetSection.widgetType}}" stepKey="dontSeeTypeAfterReset"/> <dontSeeInField userInput="{{ProductsListWidget.design_theme}}" selector="{{AdminNewWidgetSection.widgetDesignTheme}}" stepKey="dontSeeDesignAfterReset"/> - <actionGroup ref="AdminSetInputTypeAndDesignActionGroup" stepKey="setTypeAndDesignAfterReset"> + <actionGroup ref="AdminSetWidgetTypeAndDesignActionGroup" stepKey="setTypeAndDesignAfterReset"> <argument name="widgetType" value="{{ProductsListWidget.type}}"/> <argument name="widgetDesign" value="{{ProductsListWidget.design_theme}}"/> </actionGroup> <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> <actionGroup ref="AdminSetWidgetNameAndStoreActionGroup" stepKey="setNameAndStore"> - <argument name="widgetName" value="{{ProductsListWidget.name}}"/> + <argument name="widgetTitle" value="{{ProductsListWidget.name}}"/> <argument name="widgetStoreIds" value="{{ProductsListWidget.store_ids}}"/> <argument name="widgetSortOrder" value="{{ProductsListWidget.sort_order}}"/> </actionGroup> @@ -50,12 +50,12 @@ <dontSeeInField userInput="{{ProductsListWidget.store_ids[0]}}" selector="{{AdminNewWidgetSection.widgetStoreIds}}" stepKey="dontSeeStoreAfterReset"/> <dontSeeInField userInput="{{ProductsListWidget.sort_order}}" selector="{{AdminNewWidgetSection.widgetSortOrder}}" stepKey="dontSeeSortOrderAfterReset"/> <actionGroup ref="AdminSetWidgetNameAndStoreActionGroup" stepKey="setNameAndStoreAfterReset"> - <argument name="widgetName" value="{{ProductsListWidget.name}}"/> + <argument name="widgetTitle" value="{{ProductsListWidget.name}}"/> <argument name="widgetStoreIds" value="{{ProductsListWidget.store_ids}}"/> <argument name="widgetSortOrder" value="{{ProductsListWidget.sort_order}}"/> </actionGroup> - <actionGroup ref="AdminSaveAndContinueWidgetActionGroup" stepKey="saveWidget"/> - <click selector="{{AdminNewWidgetSection.resetBtn}}" stepKey="resetWidget"/> + <actionGroup ref="AdminSaveAndContinueWidgetActionGroup" stepKey="saveWidgetAndContinue"/> + <click selector="{{AdminNewWidgetSection.resetBtn}}" stepKey="resetWidgetForm"/> <seeInField userInput="{{ProductsListWidget.name}}" selector="{{AdminNewWidgetSection.widgetTitle}}" stepKey="seeNameAfterReset"/> <seeInField userInput="{{ProductsListWidget.store_ids[0]}}" selector="{{AdminNewWidgetSection.widgetStoreIds}}" stepKey="seeStoreAfterReset"/> <seeInField userInput="{{ProductsListWidget.sort_order}}" selector="{{AdminNewWidgetSection.widgetSortOrder}}" stepKey="seeSortOrderAfterReset"/> From e133e1f5ae6ba3dcc660da8fe823dfef46f69f33 Mon Sep 17 00:00:00 2001 From: Mykhailo Matiola <mykhailo.matiola@transoftgroup.com> Date: Thu, 15 Oct 2020 17:52:32 +0300 Subject: [PATCH 35/41] MC-36960: Create automated test for "Create product for "all" store views using API service" --- .../ProductRepositoryAllStoreViewsTest.php | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php index 2814a6ab05321..fd815c6d2241b 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryAllStoreViewsTest.php @@ -13,6 +13,7 @@ use Magento\Catalog\Model\Product\Type; use Magento\Catalog\Model\Product\Visibility; use Magento\Catalog\Model\ResourceModel\Product\Website\Link; +use Magento\CatalogInventory\Api\Data\StockItemInterface; use Magento\Eav\Model\Config; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\ObjectManagerInterface; @@ -167,7 +168,31 @@ private function getProductData(): array ProductInterface::STATUS => Status::STATUS_ENABLED, ProductInterface::VISIBILITY => Visibility::VISIBILITY_BOTH, ProductInterface::EXTENSION_ATTRIBUTES_KEY => [ - 'stock_item' => ['is_in_stock' => true, 'qty' => 1000] + 'stock_item' => [ + StockItemInterface::IS_IN_STOCK => 1, + StockItemInterface::QTY => 1000, + StockItemInterface::IS_QTY_DECIMAL => 0, + StockItemInterface::SHOW_DEFAULT_NOTIFICATION_MESSAGE => 0, + StockItemInterface::USE_CONFIG_MIN_QTY => 0, + StockItemInterface::USE_CONFIG_MIN_SALE_QTY => 0, + StockItemInterface::MIN_QTY => 1, + StockItemInterface::MIN_SALE_QTY => 1, + StockItemInterface::MAX_SALE_QTY => 100, + StockItemInterface::USE_CONFIG_MAX_SALE_QTY => 0, + StockItemInterface::USE_CONFIG_BACKORDERS => 0, + StockItemInterface::BACKORDERS => 0, + StockItemInterface::USE_CONFIG_NOTIFY_STOCK_QTY => 0, + StockItemInterface::NOTIFY_STOCK_QTY => 0, + StockItemInterface::USE_CONFIG_QTY_INCREMENTS => 0, + StockItemInterface::QTY_INCREMENTS => 0, + StockItemInterface::USE_CONFIG_ENABLE_QTY_INC => 0, + StockItemInterface::ENABLE_QTY_INCREMENTS => 0, + StockItemInterface::USE_CONFIG_MANAGE_STOCK => 1, + StockItemInterface::MANAGE_STOCK => 1, + StockItemInterface::LOW_STOCK_DATE => null, + StockItemInterface::IS_DECIMAL_DIVIDED => 0, + StockItemInterface::STOCK_STATUS_CHANGED_AUTO => 0, + ], ], ProductInterface::CUSTOM_ATTRIBUTES => [ ['attribute_code' => 'url_key', 'value' => 'simple'], @@ -211,6 +236,10 @@ private function assertProductData(array $productData, array $resultData, array $resultData['custom_attributes'], $attribute['attribute_code'] ); + if ($attribute['attribute_code'] == 'category_ids') { + $this->assertEquals(array_values($attribute['value']), array_values($resultAttribute['value'])); + continue; + } $this->assertEquals($attribute['value'], $resultAttribute['value']); } foreach ($productData['extension_attributes']['stock_item'] as $key => $value) { From 5cec5498d29d23e1a19d66f69e085eed9896e935 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Thu, 15 Oct 2020 17:13:46 +0200 Subject: [PATCH 36/41] MC-37896: Create automated test for "Reset Widget" --- .../Widget/Test/Mftf/Section/AdminNewWidgetSection.xml | 5 +++-- .../Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index 805c55f34ce9a..49eaf6b377859 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -12,7 +12,7 @@ <element name="widgetType" type="select" selector="#code"/> <element name="widgetDesignTheme" type="select" selector="#theme_id"/> <element name="continue" type="button" timeout="30" selector="#continue_button"/> - <element name="resetBtn" type="button" selector="//*[@class='page-actions-buttons']/button[@id='reset']" timeout="30"/> + <element name="resetBtn" type="button" selector=".page-actions-buttons .reset" timeout="30"/> <element name="widgetTitle" type="input" selector="#title"/> <element name="widgetStoreIds" type="select" selector="#store_ids"/> <element name="widgetSortOrder" type="input" selector="#sort_order"/> @@ -43,7 +43,7 @@ <element name="displayMode" type="select" selector="select[id*='display_mode']"/> <element name="restrictTypes" type="select" selector="select[id*='types']"/> <element name="saveAndContinue" type="button" selector="#save_and_edit_button" timeout="30"/> - <element name="widgetInstanceType" type="select" selector="//*[@class='admin__field-control control']/select[@id='instance_code']" /> + <element name="widgetInstanceType" type="select" selector=".admin__field-control .admin__control-select" /> <!-- Catalog Product List Widget Options --> <element name="title" type="input" selector="[name='parameters[title]']"/> <element name="displayPageControl" type="select" selector="[name='parameters[show_pager]']"/> @@ -51,3 +51,4 @@ <element name="cacheLifetime" type="input" selector="[name='parameters[cache_lifetime]']"/> </section> </sections> + diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml index fd9ce8f3c37e9..5e053778fe7ed 100644 --- a/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminResetWidgetTest.xml @@ -23,7 +23,7 @@ </before> <after> <actionGroup ref="AdminDeleteWidgetActionGroup" stepKey="deleteWidget"> - <argument name="widget" value="{{ProductsListWidget}}"/> + <argument name="widget" value="ProductsListWidget"/> </actionGroup> <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </after> From 1ff20ba12e960d937b7ebe49592a9b5619cb4035 Mon Sep 17 00:00:00 2001 From: Bohdan Shevchenko <1408sheva@gmail.com> Date: Thu, 15 Oct 2020 18:27:31 +0300 Subject: [PATCH 37/41] MC-37546: Create automated test for "Create new Category Update" --- ...torefrontCheckPresentSubCategoryActionGroup.xml | 6 +++--- .../Test/Mftf/Page/AdminCategoryEditPage.xml | 1 + .../AdminCategoryScheduleDesingUpdateSection.xml | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesingUpdateSection.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml index 7cb3287614433..1799f6339a84d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCheckPresentSubCategoryActionGroup.xml @@ -16,8 +16,8 @@ <argument name="childCategoryName" type="string"/> </arguments> - <waitForElement selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(parenCategoryName)}}" stepKey="waitForTopMenuLoaded"/> - <moveMouseOver selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(parenCategoryName)}}" stepKey="moveMouseToParentCategory"/> - <seeElement selector="{{AdminCategorySidebarTreeSection.categoryHighlighted(childCategoryName)}}" stepKey="seeSubcategoryInTree"/> + <waitForElementVisible selector="{{StorefrontHeaderSection.NavigationCategoryByName(parenCategoryName)}}" stepKey="waitForTopMenuLoaded"/> + <moveMouseOver selector="{{StorefrontHeaderSection.NavigationCategoryByName(parenCategoryName)}}" stepKey="moveMouseToParentCategory"/> + <seeElement selector="{{StorefrontHeaderSection.NavigationCategoryByName(childCategoryName)}}" stepKey="seeSubcategoryInTree"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml index e1c8e5c75e9ac..5c5dfe8901563 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml @@ -19,5 +19,6 @@ <section name="AdminCategoryModalSection"/> <section name="AdminCategoryMessagesSection"/> <section name="AdminCategoryContentSection"/> + <section name="AdminCategoryScheduleDesingUpdateSection"/> </page> </pages> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesingUpdateSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesingUpdateSection.xml new file mode 100644 index 0000000000000..e1b66b3c18260 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesingUpdateSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCategoryScheduleDesingUpdateSection"> + <element name="sectionHeader" type="button" selector="div[data-index='schedule_design_update'] .fieldset-wrapper-title" timeout="30"/> + <element name="sectionBody" type="text" selector="div[data-index='schedule_design_update'] .admin__fieldset-wrapper-content"/> + </section> +</sections> From ab41eb8864b6c2980d71b4ee8b3d8e2c4ed93fd8 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Fri, 16 Oct 2020 09:04:54 +0200 Subject: [PATCH 38/41] MC-37896: Create automated test for "Reset Widget" --- .../Widget/Test/Mftf/Section/AdminNewWidgetSection.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index 49eaf6b377859..4064f8eb394ca 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -12,7 +12,7 @@ <element name="widgetType" type="select" selector="#code"/> <element name="widgetDesignTheme" type="select" selector="#theme_id"/> <element name="continue" type="button" timeout="30" selector="#continue_button"/> - <element name="resetBtn" type="button" selector=".page-actions-buttons .reset" timeout="30"/> + <element name="resetBtn" type="button" selector=".page-actions-buttons button#reset" timeout="30"/> <element name="widgetTitle" type="input" selector="#title"/> <element name="widgetStoreIds" type="select" selector="#store_ids"/> <element name="widgetSortOrder" type="input" selector="#sort_order"/> @@ -43,7 +43,7 @@ <element name="displayMode" type="select" selector="select[id*='display_mode']"/> <element name="restrictTypes" type="select" selector="select[id*='types']"/> <element name="saveAndContinue" type="button" selector="#save_and_edit_button" timeout="30"/> - <element name="widgetInstanceType" type="select" selector=".admin__field-control .admin__control-select" /> + <element name="widgetInstanceType" type="select" selector=".admin__field-control select#instance_code" /> <!-- Catalog Product List Widget Options --> <element name="title" type="input" selector="[name='parameters[title]']"/> <element name="displayPageControl" type="select" selector="[name='parameters[show_pager]']"/> From be5dbb9c032daa38628fafbbe3600af6cb4641e2 Mon Sep 17 00:00:00 2001 From: Bohdan Shevchenko <1408sheva@gmail.com> Date: Fri, 16 Oct 2020 10:55:38 +0300 Subject: [PATCH 39/41] MC-37546: Create automated test for "Create new Category Update" --- .../Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml | 2 +- ...Section.xml => AdminCategoryScheduleDesignUpdateSection.xml} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/code/Magento/Catalog/Test/Mftf/Section/{AdminCategoryScheduleDesingUpdateSection.xml => AdminCategoryScheduleDesignUpdateSection.xml} (90%) diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml index 5c5dfe8901563..15fcf5f7d4000 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml @@ -19,6 +19,6 @@ <section name="AdminCategoryModalSection"/> <section name="AdminCategoryMessagesSection"/> <section name="AdminCategoryContentSection"/> - <section name="AdminCategoryScheduleDesingUpdateSection"/> + <section name="AdminCategoryScheduleDesignUpdateSection"/> </page> </pages> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesingUpdateSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesignUpdateSection.xml similarity index 90% rename from app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesingUpdateSection.xml rename to app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesignUpdateSection.xml index e1b66b3c18260..a65d2c9e63bef 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesingUpdateSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryScheduleDesignUpdateSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> - <section name="AdminCategoryScheduleDesingUpdateSection"> + <section name="AdminCategoryScheduleDesignUpdateSection"> <element name="sectionHeader" type="button" selector="div[data-index='schedule_design_update'] .fieldset-wrapper-title" timeout="30"/> <element name="sectionBody" type="text" selector="div[data-index='schedule_design_update'] .admin__fieldset-wrapper-content"/> </section> From 56fff4c5a8cf90c0d8914590fde7bd315b504c75 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Fri, 16 Oct 2020 11:22:37 +0300 Subject: [PATCH 40/41] MC-29405: PHPStan: "Class does not have a constructor and must be instantiated without any parameters" errors --- .../Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php | 1 - .../Unit/Model/Customer/Attribute/Backend/ShippingTest.php | 1 - .../Unit/Block/Adminhtml/Design/Config/Edit/SaveButtonTest.php | 3 --- 3 files changed, 5 deletions(-) diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php index 4f318948097cc..65f9b62b426c0 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php @@ -12,7 +12,6 @@ use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; use Magento\Framework\DataObject; use PHPUnit\Framework\TestCase; -use Psr\Log\LoggerInterface; class BillingTest extends TestCase { diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/ShippingTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/ShippingTest.php index 6270905ca2e85..1f5485309cc19 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/ShippingTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/ShippingTest.php @@ -12,7 +12,6 @@ use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; use Magento\Framework\DataObject; use PHPUnit\Framework\TestCase; -use Psr\Log\LoggerInterface; class ShippingTest extends TestCase { diff --git a/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/SaveButtonTest.php b/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/SaveButtonTest.php index 0ce450df39b59..b7f2def1c0fbd 100644 --- a/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/SaveButtonTest.php +++ b/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/SaveButtonTest.php @@ -7,10 +7,7 @@ namespace Magento\Theme\Test\Unit\Block\Adminhtml\Design\Config\Edit; -use Magento\Backend\Block\Widget\Context; -use Magento\Framework\UrlInterface; use Magento\Theme\Block\Adminhtml\Design\Config\Edit\SaveButton; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class SaveButtonTest extends TestCase From 8d97104395928f7e328be329c46188992a616a2c Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Fri, 16 Oct 2020 14:43:20 +0300 Subject: [PATCH 41/41] MC-29402: PHPStan: "Anonymous function has an unused use" errors --- app/code/Magento/Customer/Controller/Adminhtml/Index.php | 1 - setup/src/Magento/Setup/Console/Command/RollbackCommand.php | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index.php b/app/code/Magento/Customer/Controller/Adminhtml/Index.php index f03f55b16e0c7..9595e473c1869 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index.php @@ -289,7 +289,6 @@ protected function prepareDefaultCustomerTitle(\Magento\Backend\Model\View\Resul protected function _addSessionErrorMessages($messages) { $messages = (array)$messages; - $session = $this->_getSession(); $callback = function ($error) { if (!$error instanceof Error) { diff --git a/setup/src/Magento/Setup/Console/Command/RollbackCommand.php b/setup/src/Magento/Setup/Console/Command/RollbackCommand.php index e4616ae5e271b..e114c84ba79bc 100644 --- a/setup/src/Magento/Setup/Console/Command/RollbackCommand.php +++ b/setup/src/Magento/Setup/Console/Command/RollbackCommand.php @@ -122,7 +122,8 @@ protected function execute(InputInterface $input, OutputInterface $output) // we must have an exit code higher than zero to indicate something was wrong return \Magento\Framework\Console\Cli::RETURN_FAILURE; } - $returnValue = $this->maintenanceModeEnabler->executeInMaintenanceMode( + + return $this->maintenanceModeEnabler->executeInMaintenanceMode( function () use ($input, $output) { try { $helper = $this->getHelper('question'); @@ -152,7 +153,6 @@ function () use ($input, $output) { $output, false ); - return $returnValue; } /**