diff --git a/app/code/Magento/AdvancedSearch/Test/Unit/Model/Recommendations/DataProviderTest.php b/app/code/Magento/AdvancedSearch/Test/Unit/Model/Recommendations/DataProviderTest.php new file mode 100644 index 0000000000000..c62c906914fd7 --- /dev/null +++ b/app/code/Magento/AdvancedSearch/Test/Unit/Model/Recommendations/DataProviderTest.php @@ -0,0 +1,189 @@ +scopeConfigMock = $this->createMock(ScopeConfigInterface::class); + $this->layerResolverMock = $this->getMockBuilder(Resolver::class) + ->disableOriginalConstructor() + ->setMethods(['get']) + ->getMock(); + + $this->searchLayerMock = $this->createMock(SearchLayer::class); + + $this->layerResolverMock->expects($this->any()) + ->method('get') + ->will($this->returnValue($this->searchLayerMock)); + + $this->recommendationsFactoryMock = $this->getMockBuilder(RecommendationsFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->recommendationsMock = $this->createMock(Recommendations::class); + + $this->queryResultFactory = $this->getMockBuilder(QueryResultFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->model = $this->objectManagerHelper->getObject( + DataProvider::class, + [ + 'scopeConfig' => $this->scopeConfigMock, + 'layerResolver' => $this->layerResolverMock, + 'recommendationsFactory' => $this->recommendationsFactoryMock, + 'queryResultFactory' => $this->queryResultFactory + ] + ); + } + + /** + * Test testGetItems() when Search Recommendations disabled. + * + * @return void + */ + public function testGetItemsWhenDisabledSearchRecommendations() + { + $isEnabledSearchRecommendations = false; + + /** @var $queryInterfaceMock QueryInterface */ + $queryInterfaceMock = $this->createMock(QueryInterface::class); + + $this->scopeConfigMock->expects($this->any()) + ->method('isSetFlag') + ->with('catalog/search/search_recommendations_enabled', ScopeInterface::SCOPE_STORE) + ->willReturn($isEnabledSearchRecommendations); + + $result = $this->model->getItems($queryInterfaceMock); + $this->assertEquals([], $result); + } + + /** + * Test testGetItems() when Search Recommendations enabled. + * + * @return void + */ + public function testGetItemsWhenEnabledSearchRecommendations() + { + $storeId = 1; + $searchRecommendationsCountConfig = 2; + $isEnabledSearchRecommendations = true; + $queryText = 'test'; + + /** @var $queryInterfaceMock QueryInterface */ + $queryInterfaceMock = $this->createMock(QueryInterface::class); + $queryInterfaceMock->expects($this->any())->method('getQueryText')->willReturn($queryText); + + $this->scopeConfigMock->expects($this->any()) + ->method('isSetFlag') + ->with('catalog/search/search_recommendations_enabled', ScopeInterface::SCOPE_STORE) + ->willReturn($isEnabledSearchRecommendations); + + $this->scopeConfigMock->expects($this->any()) + ->method('getValue') + ->with('catalog/search/search_recommendations_count', ScopeInterface::SCOPE_STORE) + ->willReturn($searchRecommendationsCountConfig); + + $productCollectionMock = $this->createMock(ProductCollection::class); + $productCollectionMock->expects($this->any())->method('getStoreId')->willReturn($storeId); + + $this->searchLayerMock->expects($this->any())->method('getProductCollection') + ->willReturn($productCollectionMock); + + $this->recommendationsFactoryMock->expects($this->any())->method('create') + ->willReturn($this->recommendationsMock); + + $this->recommendationsMock->expects($this->any())->method('getRecommendationsByQuery') + ->with($queryText, ['store_id' => $storeId], $searchRecommendationsCountConfig) + ->willReturn( + [ + [ + 'query_text' => 'a', + 'num_results' => 3 + ], + [ + 'query_text' => 'b', + 'num_results' => 2 + ] + ] + ); + $queryResultMock = $this->createMock(QueryResult::class); + $this->queryResultFactory->expects($this->any())->method('create')->willReturn($queryResultMock); + + $result = $this->model->getItems($queryInterfaceMock); + $this->assertEquals(2, count($result)); + } +} diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminCheckLocaleAndDeveloperConfigInDeveloperModeTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminCheckLocaleAndDeveloperConfigInDeveloperModeTest.xml index 59a6a7e261b87..47b8715b5541c 100644 --- a/app/code/Magento/Backend/Test/Mftf/Test/AdminCheckLocaleAndDeveloperConfigInDeveloperModeTest.xml +++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminCheckLocaleAndDeveloperConfigInDeveloperModeTest.xml @@ -11,6 +11,7 @@ + <description value="Check locale dropdown and developer configuration page are available in developer mode"/> <group value="backend"/> diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminCheckLocaleAndDeveloperConfigInProductionModeTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminCheckLocaleAndDeveloperConfigInProductionModeTest.xml index 2dade727ca411..ae7722b225cdd 100644 --- a/app/code/Magento/Backend/Test/Mftf/Test/AdminCheckLocaleAndDeveloperConfigInProductionModeTest.xml +++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminCheckLocaleAndDeveloperConfigInProductionModeTest.xml @@ -11,6 +11,7 @@ <test name="AdminCheckLocaleAndDeveloperConfigInProductionModeTest"> <annotations> <features value="Backend"/> + <stories value="Menu Navigation"/> <title value="Check locale dropdown and developer configuration page are not available in production mode"/> <description value="Check locale dropdown and developer configuration page are not available in production mode"/> <testCaseId value="MC-14106" /> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml index d27cd0df88239..9ea0480e540ba 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml @@ -39,7 +39,7 @@ <requiredEntity createDataKey="fixedBundleOption"/> <requiredEntity createDataKey="createSimpleProductTwo"/> </createData> - <magentoCLI command="indexer:reindex" arguments="cataloginventory_stock catalogsearch_fulltext" stepKey="reindex"/> + <magentoCLI command="indexer:reindex" stepKey="reindex"/> </before> <after> <deleteData createDataKey="createDynamicBundle" stepKey="deleteDynamicBundleProduct"/> diff --git a/app/code/Magento/CardinalCommerce/Test/Unit/Model/Response/JwtParserTest.php b/app/code/Magento/CardinalCommerce/Test/Unit/Model/Response/JwtParserTest.php new file mode 100644 index 0000000000000..7c17c4e2e87d5 --- /dev/null +++ b/app/code/Magento/CardinalCommerce/Test/Unit/Model/Response/JwtParserTest.php @@ -0,0 +1,131 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CardinalCommerce\Test\Unit\Model\Response; + +use Magento\CardinalCommerce\Model\Response\JwtParser; +use Magento\CardinalCommerce\Model\Config; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\CardinalCommerce\Model\JwtManagement; +use Magento\CardinalCommerce\Model\Response\JwtPayloadValidatorInterface; +use Magento\Framework\Exception\LocalizedException; + +/** + * Class \Magento\CardinalCommerce\Test\Unit\Model\Response\JwtParserTest + */ +class JwtParserTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var JwtParser + */ + private $model; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | Config + */ + private $configMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | JwtManagement + */ + private $jwtManagementMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | JwtPayloadValidatorInterface + */ + private $jwtPayloadValidatorMock; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + + $this->configMock = $this->getMockBuilder(Config::class) + ->setMethods(['getApiKey', 'isDebugModeEnabled']) + ->disableOriginalConstructor() + ->getMock(); + + $this->jwtManagementMock = $this->getMockBuilder(JwtManagement::class) + ->setMethods(['decode']) + ->disableOriginalConstructor() + ->getMock(); + + $this->jwtPayloadValidatorMock = $this->getMockBuilder(JwtPayloadValidatorInterface::class) + ->setMethods(['validate']) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = $this->objectManager->getObject( + JwtParser::class, + [ + 'jwtManagement' => $this->jwtManagementMock, + 'config' => $this->configMock, + 'tokenValidator' => $this->jwtPayloadValidatorMock + ] + ); + + $this->configMock->expects($this->any()) + ->method('getApiKey') + ->willReturn('API Key'); + + $this->configMock->expects($this->any()) + ->method('isDebugModeEnabled') + ->willReturn(false); + + $this->jwtManagementMock->expects($this->any()) + ->method('decode') + ->with('string_to_test', 'API Key') + ->willReturn(['mockResult' => 'jwtPayload']); + } + + /** + * Tests Jwt Parser execute with the result and no exception. + */ + public function testExecuteWithNoException() + { + /* Validate Success */ + $this->jwtPayloadValidatorMock->expects($this->any()) + ->method('validate') + ->with(['mockResult' => 'jwtPayload']) + ->willReturn(true); + + /* Assert the result of function */ + $jwtPayload = $this->model->execute('string_to_test'); + $this->assertEquals( + ['mockResult' => 'jwtPayload'], + $jwtPayload + ); + } + + /** + * Tests Jwt Parser execute with exception and no result. + */ + public function testExecuteWithException() + { + /* Validate Fail */ + $this->jwtPayloadValidatorMock->expects($this->any()) + ->method('validate') + ->with(['mockResult' => 'jwtPayload']) + ->willReturn(false); + + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage( + 'Authentication Failed. Your card issuer cannot authenticate this card. ' . + 'Please select another card or form of payment to complete your purchase.' + ); + + /* Execute function */ + $this->model->execute('string_to_test'); + } +} diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/DisplayRefreshCacheAfterChangingCategoryPageLayoutTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/DisplayRefreshCacheAfterChangingCategoryPageLayoutTest.xml index d5b1e8569d560..02df8db5c2121 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/DisplayRefreshCacheAfterChangingCategoryPageLayoutTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/DisplayRefreshCacheAfterChangingCategoryPageLayoutTest.xml @@ -11,6 +11,7 @@ <test name="DisplayRefreshCacheAfterChangingCategoryPageLayoutTest"> <annotations> <features value="Catalog"/> + <stories value="Category Layout Change"/> <title value="'Refresh cache' admin notification is displayed when changing category page layout"/> <description value="'Refresh cache' message is not displayed when changing category page layout"/> <severity value="MAJOR"/> diff --git a/app/code/Magento/CmsUrlRewrite/Test/Unit/Model/CmsPageUrlPathGeneratorTest.php b/app/code/Magento/CmsUrlRewrite/Test/Unit/Model/CmsPageUrlPathGeneratorTest.php new file mode 100644 index 0000000000000..6b57254dd0ec1 --- /dev/null +++ b/app/code/Magento/CmsUrlRewrite/Test/Unit/Model/CmsPageUrlPathGeneratorTest.php @@ -0,0 +1,156 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\CmsUrlRewrite\Test\Unit\Model; + +use Magento\CmsUrlRewrite\Model\CmsPageUrlPathGenerator; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\Filter\FilterManager; +use Magento\Cms\Api\Data\PageInterface; + +/** + * Class \Magento\CmsUrlRewrite\Test\Unit\Model\CmsPageUrlPathGeneratorTest + */ +class CmsPageUrlPathGeneratorTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ObjectManagerHelper + */ + private $objectManager; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|FilterManager + */ + private $filterManagerMock; + + /** + * @var CmsPageUrlPathGenerator + */ + private $model; + + /** + * Setup environment for test + */ + protected function setUp() + { + $this->objectManager = new ObjectManagerHelper($this); + $this->filterManagerMock = $this->getMockBuilder(FilterManager::class) + ->disableOriginalConstructor() + ->setMethods(['translitUrl']) + ->getMock(); + + $this->model = $this->objectManager->getObject( + CmsPageUrlPathGenerator::class, + [ + 'filterManager' => $this->filterManagerMock + ] + ); + } + + /** + * Test getUrlPath with page has identifier = cms-cookie + */ + public function testGetUrlPath() + { + /* @var PageInterface $cmsPageMock*/ + $cmsPageMock = $this->getMockBuilder(PageInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $cmsPageMock->expects($this->any()) + ->method('getIdentifier') + ->willReturn('cms-cookie'); + + $this->assertEquals('cms-cookie', $this->model->getUrlPath($cmsPageMock)); + } + + /** + * Test getCanonicalUrlPath() with page has id = 1 + */ + public function testGetCanonicalUrlPath() + { + /* @var PageInterface $cmsPageMock*/ + $cmsPageMock = $this->getMockBuilder(PageInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $cmsPageMock->expects($this->any()) + ->method('getId') + ->willReturn('1'); + + $this->assertEquals('cms/page/view/page_id/1', $this->model->getCanonicalUrlPath($cmsPageMock)); + } + + /** + * Test generateUrlKey() with page has no identifier + */ + public function testGenerateUrlKeyWithNullIdentifier() + { + /** + * Data set + */ + $page = [ + 'identifier' => null, + 'title' => 'CMS Cookie' + ]; + + /* @var PageInterface $cmsPageMock*/ + $cmsPageMock = $this->getMockBuilder(PageInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $cmsPageMock->expects($this->any()) + ->method('getIdentifier') + ->willReturn($page['identifier']); + + $cmsPageMock->expects($this->any()) + ->method('getTitle') + ->willReturn($page['title']); + + $this->filterManagerMock->expects($this->any()) + ->method('translitUrl') + ->with($page['title']) + ->willReturn('cms-cookie'); + + $this->assertEquals('cms-cookie', $this->model->generateUrlKey($cmsPageMock)); + } + + /** + * Test generateUrlKey() with page has identifier + */ + public function testGenerateUrlKeyWithIdentifier() + { + /** + * Data set + */ + $page = [ + 'identifier' => 'home', + 'title' => 'Home Page' + ]; + + /* @var PageInterface $cmsPageMock*/ + $cmsPageMock = $this->getMockBuilder(PageInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $cmsPageMock->expects($this->any()) + ->method('getIdentifier') + ->willReturn($page['identifier']); + + $cmsPageMock->expects($this->any()) + ->method('getTitle') + ->willReturn($page['title']); + + $this->filterManagerMock->expects($this->any()) + ->method('translitUrl') + ->with($page['identifier']) + ->willReturn('home'); + + $this->assertEquals('home', $this->model->generateUrlKey($cmsPageMock)); + } +} diff --git a/app/code/Magento/Customer/Model/Address/Validator/General.php b/app/code/Magento/Customer/Model/Address/Validator/General.php index 679f288712b4b..7cbb6ef1ab623 100644 --- a/app/code/Magento/Customer/Model/Address/Validator/General.php +++ b/app/code/Magento/Customer/Model/Address/Validator/General.php @@ -41,7 +41,7 @@ public function __construct( public function validate(AbstractAddress $address) { $errors = array_merge( - $this->checkRequredFields($address), + $this->checkRequiredFields($address), $this->checkOptionalFields($address) ); @@ -55,7 +55,7 @@ public function validate(AbstractAddress $address) * @return array * @throws \Zend_Validate_Exception */ - private function checkRequredFields(AbstractAddress $address) + private function checkRequiredFields(AbstractAddress $address) { $errors = []; if (!\Zend_Validate::is($address->getFirstname(), 'NotEmpty')) { diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminProductBackRedirectNavigateFromCustomerViewCartProduct.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminProductBackRedirectNavigateFromCustomerViewCartProduct.xml index 9de2339f2e217..b5db354d54371 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminProductBackRedirectNavigateFromCustomerViewCartProduct.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminProductBackRedirectNavigateFromCustomerViewCartProduct.xml @@ -11,6 +11,7 @@ <test name="AdminProductBackRedirectNavigateFromCustomerViewCartProduct"> <annotations> <features value="Customer"/> + <stories value="Product Back Button"/> <title value="Product back redirect navigate from customer view cart product"/> <description value="Back button on product page is redirecting to customer page if opened form shopping cart"/> <severity value="MINOR"/> diff --git a/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Client/Elasticsearch.php b/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Client/Elasticsearch.php index 93f4caa10adf9..b9102bc5e00c4 100644 --- a/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Client/Elasticsearch.php +++ b/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Client/Elasticsearch.php @@ -108,21 +108,28 @@ public function testConnection() */ private function buildConfig($options = []) { - $host = preg_replace('/http[s]?:\/\//i', '', $options['hostname']); + $hostname = preg_replace('/http[s]?:\/\//i', '', $options['hostname']); // @codingStandardsIgnoreStart $protocol = parse_url($options['hostname'], PHP_URL_SCHEME); // @codingStandardsIgnoreEnd if (!$protocol) { $protocol = 'http'; } - if (!empty($options['port'])) { - $host .= ':' . $options['port']; + + $authString = ''; + if (!empty($options['enableAuth']) && (int)$options['enableAuth'] === 1) { + $authString = "{$options['username']}:{$options['password']}@"; } - if (!empty($options['enableAuth']) && ($options['enableAuth'] == 1)) { - $host = sprintf('%s://%s:%s@%s', $protocol, $options['username'], $options['password'], $host); + + $portString = ''; + if (!empty($options['port'])) { + $portString = ':' . $options['port']; } + $host = $protocol . '://' . $authString . $hostname . $portString; + $options['hosts'] = [$host]; + return $options; } diff --git a/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php b/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php index f9b827304446d..d933d8bb5d0b5 100644 --- a/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php +++ b/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php @@ -103,21 +103,28 @@ public function testConnection() */ private function buildConfig($options = []) { - $host = preg_replace('/http[s]?:\/\//i', '', $options['hostname']); + $hostname = preg_replace('/http[s]?:\/\//i', '', $options['hostname']); // @codingStandardsIgnoreStart $protocol = parse_url($options['hostname'], PHP_URL_SCHEME); // @codingStandardsIgnoreEnd if (!$protocol) { $protocol = 'http'; } - if (!empty($options['port'])) { - $host .= ':' . $options['port']; + + $authString = ''; + if (!empty($options['enableAuth']) && (int)$options['enableAuth'] === 1) { + $authString = "{$options['username']}:{$options['password']}@"; } - if (!empty($options['enableAuth']) && ($options['enableAuth'] == 1)) { - $host = sprintf('%s://%s:%s@%s', $protocol, $options['username'], $options['password'], $host); + + $portString = ''; + if (!empty($options['port'])) { + $portString = ':' . $options['port']; } + $host = $protocol . '://' . $authString . $hostname . $portString; + $options['hosts'] = [$host]; + return $options; } diff --git a/app/code/Magento/Elasticsearch/Test/Unit/Elasticsearch5/Model/Client/ElasticsearchTest.php b/app/code/Magento/Elasticsearch/Test/Unit/Elasticsearch5/Model/Client/ElasticsearchTest.php index 5f5807e212961..99fd416b5cd3e 100644 --- a/app/code/Magento/Elasticsearch/Test/Unit/Elasticsearch5/Model/Client/ElasticsearchTest.php +++ b/app/code/Magento/Elasticsearch/Test/Unit/Elasticsearch5/Model/Client/ElasticsearchTest.php @@ -3,8 +3,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Elasticsearch\Test\Unit\Elasticsearch5\Model\Client; +use Magento\Elasticsearch\Elasticsearch5\Model\Client\Elasticsearch; use Magento\Elasticsearch\Model\Client\Elasticsearch as ElasticsearchClient; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; @@ -38,7 +40,7 @@ class ElasticsearchTest extends \PHPUnit\Framework\TestCase * * @return void */ - protected function setUp() + protected function setUp(): void { $this->elasticsearchClientMock = $this->getMockBuilder(\Elasticsearch\Client::class) ->setMethods( @@ -497,6 +499,40 @@ public function testDeleteMapping() ); } + /** + * Ensure that configuration returns correct url. + * + * @param array $options + * @param string $expectedResult + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \ReflectionException + * @dataProvider getOptionsDataProvider + */ + public function testBuildConfig(array $options, $expectedResult): void + { + $buildConfig = new Elasticsearch($options); + $config = $this->getPrivateMethod(Elasticsearch::class, 'buildConfig'); + $result = $config->invoke($buildConfig, $options); + $this->assertEquals($expectedResult, $result['hosts'][0]); + } + + /** + * Return private method for elastic search class. + * + * @param $className + * @param $methodName + * @return \ReflectionMethod + * @throws \ReflectionException + */ + private function getPrivateMethod($className, $methodName) + { + $reflector = new \ReflectionClass($className); + $method = $reflector->getMethod($methodName); + $method->setAccessible(true); + + return $method; + } + /** * Test deleteMapping() method * @expectedException \Exception @@ -545,6 +581,35 @@ public function testSuggest() $this->assertEquals([], $this->model->suggest($query)); } + /** + * Get options data provider. + */ + public function getOptionsDataProvider() + { + return [ + [ + 'without_protocol' => [ + 'hostname' => 'localhost', + 'port' => '9200', + 'timeout' => 15, + 'index' => 'magento2', + 'enableAuth' => 0, + ], + 'expected_result' => 'http://localhost:9200' + ], + [ + 'with_protocol' => [ + 'hostname' => 'https://localhost', + 'port' => '9200', + 'timeout' => 15, + 'index' => 'magento2', + 'enableAuth' => 0, + ], + 'expected_result' => 'https://localhost:9200' + ] + ]; + } + /** * Get elasticsearch client options * diff --git a/app/code/Magento/Elasticsearch6/Model/Client/Elasticsearch.php b/app/code/Magento/Elasticsearch6/Model/Client/Elasticsearch.php index 34129a5af0012..e4018196c845d 100644 --- a/app/code/Magento/Elasticsearch6/Model/Client/Elasticsearch.php +++ b/app/code/Magento/Elasticsearch6/Model/Client/Elasticsearch.php @@ -103,21 +103,28 @@ public function testConnection() */ private function buildConfig($options = []) { - $host = preg_replace('/http[s]?:\/\//i', '', $options['hostname']); + $hostname = preg_replace('/http[s]?:\/\//i', '', $options['hostname']); // @codingStandardsIgnoreStart $protocol = parse_url($options['hostname'], PHP_URL_SCHEME); // @codingStandardsIgnoreEnd if (!$protocol) { $protocol = 'http'; } - if (!empty($options['port'])) { - $host .= ':' . $options['port']; + + $authString = ''; + if (!empty($options['enableAuth']) && (int)$options['enableAuth'] === 1) { + $authString = "{$options['username']}:{$options['password']}@"; } - if (!empty($options['enableAuth']) && ($options['enableAuth'] == 1)) { - $host = sprintf('%s://%s:%s@%s', $protocol, $options['username'], $options['password'], $host); + + $portString = ''; + if (!empty($options['port'])) { + $portString = ':' . $options['port']; } + $host = $protocol . '://' . $authString . $hostname . $portString; + $options['hosts'] = [$host]; + return $options; } diff --git a/app/code/Magento/Elasticsearch6/Test/Unit/Model/Client/ElasticsearchTest.php b/app/code/Magento/Elasticsearch6/Test/Unit/Model/Client/ElasticsearchTest.php index 487a5a886f951..3ed6721821164 100644 --- a/app/code/Magento/Elasticsearch6/Test/Unit/Model/Client/ElasticsearchTest.php +++ b/app/code/Magento/Elasticsearch6/Test/Unit/Model/Client/ElasticsearchTest.php @@ -3,10 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Elasticsearch6\Test\Unit\Model\Client; use Magento\Elasticsearch\Model\Client\Elasticsearch as ElasticsearchClient; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Elasticsearch6\Model\Client\Elasticsearch; /** * Class ElasticsearchTest @@ -83,7 +85,7 @@ protected function setUp() $this->objectManager = new ObjectManagerHelper($this); $this->model = $this->objectManager->getObject( - \Magento\Elasticsearch6\Model\Client\Elasticsearch::class, + Elasticsearch::class, [ 'options' => $this->getOptions(), 'elasticsearchClient' => $this->elasticsearchClientMock @@ -97,7 +99,7 @@ protected function setUp() public function testConstructorOptionsException() { $result = $this->objectManager->getObject( - \Magento\Elasticsearch6\Model\Client\Elasticsearch::class, + Elasticsearch::class, [ 'options' => [] ] @@ -119,6 +121,69 @@ public function testConstructorWithOptions() $this->assertNotNull($result); } + /** + * Ensure that configuration returns correct url. + * + * @param array $options + * @param string $expectedResult + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \ReflectionException + * @dataProvider getOptionsDataProvider + */ + public function testBuildConfig(array $options, $expectedResult): void + { + $buildConfig = new Elasticsearch($options); + $config = $this->getPrivateMethod(Elasticsearch::class, 'buildConfig'); + $result = $config->invoke($buildConfig, $options); + $this->assertEquals($expectedResult, $result['hosts'][0]); + } + + /** + * Return private method for elastic search class. + * + * @param $className + * @param $methodName + * @return \ReflectionMethod + * @throws \ReflectionException + */ + private function getPrivateMethod($className, $methodName) + { + $reflector = new \ReflectionClass($className); + $method = $reflector->getMethod($methodName); + $method->setAccessible(true); + + return $method; + } + + /** + * Get options data provider. + */ + public function getOptionsDataProvider() + { + return [ + [ + 'without_protocol' => [ + 'hostname' => 'localhost', + 'port' => '9200', + 'timeout' => 15, + 'index' => 'magento2', + 'enableAuth' => 0, + ], + 'expected_result' => 'http://localhost:9200' + ], + [ + 'with_protocol' => [ + 'hostname' => 'https://localhost', + 'port' => '9200', + 'timeout' => 15, + 'index' => 'magento2', + 'enableAuth' => 0, + ], + 'expected_result' => 'https://localhost:9200' + ] + ]; + } + /** * Test ping functionality */ diff --git a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php index af5377a6227ca..55992c92226af 100644 --- a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php +++ b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php @@ -242,9 +242,13 @@ protected function _prepareForm() 'class' => 'input-text', 'note' => __( $this->escapeHtml( - 'For Type "Local Server" use relative path to <Magento installation>/' + 'For Type "Local Server" use relative path to <Magento root directory>/' .$this->imagesDirectoryProvider->getDirectoryRelativePath() - .', e.g. product_images, import_images/batch1' + .', e.g. <i>product_images</i>, <i>import_images/batch1</i>.<br><br>' + .'For example, in case <i>product_images</i>, files should be placed into ' + .'<i><Magento root directory>/' + .$this->imagesDirectoryProvider->getDirectoryRelativePath() . '/product_images</i> folder.', + ['i', 'br'] ) ), ] diff --git a/app/code/Magento/ImportExport/Files/Sample/catalog_product.csv b/app/code/Magento/ImportExport/Files/Sample/catalog_product.csv index 7ffd5b1dfb57c..c5d8df36b441c 100644 --- a/app/code/Magento/ImportExport/Files/Sample/catalog_product.csv +++ b/app/code/Magento/ImportExport/Files/Sample/catalog_product.csv @@ -1,7 +1,7 @@ -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,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,deferred_stock_update,use_config_deferred_stock_update,related_skus,crosssell_skus,upsell_skus,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus -24-WG085,,Default,simple,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap 6 foot,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and urable under strain.</p><ul><li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1,1,Taxable Goods,"Catalog, Search",14,,,,sprite-yoga-strap-6-foot,Meta Title,"meta1, meta2, meta3",meta description,"2015-10-25 03:34:20","2015-10-25 03:34:20",,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=1,quantity_and_stock_status=In Stock,required_options=0",100,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,"24-WG087,24-WG086","24-WG087,24-WG086","24-WG087,24-WG086",,"name=Custom Yoga Option,type=drop_down,required=0,price=10.0000,price_type=fixed,sku=,option_title=Gold|name=Custom Yoga Option,type=drop_down,required=0,price=10.0000,price_type=fixed,sku=,option_title=Silver|name=Custom Yoga Option,type=drop_down,required=0,price=10.0000,price_type=fixed,sku=yoga3sku,option_title=Platinum",,,,,, -24-WG086,,Default,simple,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap 8 foot,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and durable under strain.</p><ul><li>8' long x 1.0"" wide.<li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1,1,Taxable Goods,"Catalog, Search",17,,,,sprite-yoga-strap-8-foot,Meta Title,"meta1, meta2, meta4",meta description,"2015-10-25 03:34:20","2015-10-25 03:34:20",,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=0,quantity_and_stock_status=In Stock,required_options=0",100,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,24-WG087,24-WG087,24-WG087,,,,,,,, -24-WG087,,Default,simple,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap 10 foot,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and durable under strain.</p><ul><li>10' long x 1.0"" wide.<li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1,1,Taxable Goods,"Catalog, Search",21,,,,sprite-yoga-strap-10-foot,Meta Title,"meta1, meta2, meta5",meta description,"2015-10-25 03:34:20","2015-10-25 03:34:20",,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=0,quantity_and_stock_status=In Stock,required_options=0",100,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,24-WG086,24-WG086,24-WG086,,,,,,,, -24-WG085_Group,,Default,grouped,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Set of Sprite Yoga Straps,"<p>Great set of Sprite Yoga Straps for every stretch and hold you need. There are three straps in this set: 6', 8' and 10'.</p><ul><li>100% soft and durable cotton.</li><li>Plastic cinch buckle is easy to use.</li><li>Choice of three natural colors made from phthalate and heavy metal free dyes.</li></ul>",,,1,,"Catalog, Search",,,,,set-of-sprite-yoga-straps,Meta Title,"meta1, meta2, meta6",meta description,"2015-10-25 03:34:20","2015-10-25 03:34:20",,,Block after Info Column,,,,,,,,,,,,,"has_options=0,quantity_and_stock_status=In Stock,required_options=0",0,0,1,0,0,1,1,0,0,1,1,,1,1,1,1,0,1,0,0,1,0,1,"24-WG087,24-WG086","24-WG087,24-WG086","24-WG087,24-WG086",,,,,,,,"24-WG085=5.0000,24-WG086=5.0000" -24-WG085-bundle-dynamic,,Default,bundle,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap Dynamic Bundle,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and durable under strain.</p><ul><li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1,1,Taxable Goods,"Catalog, Search",14,,,,sprite-yoga-strap2,Meta Title,"meta1, meta2, meta8",meta description,"2015-10-25 03:34:20","2015-10-25 03:34:20",,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=1,shipment_type=together,quantity_and_stock_status=In Stock,required_options=0",0,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,"24-WG087,24-WG086","24-WG087,24-WG086","24-WG087,24-WG086",,,dynamic,dynamic,Price range,fixed,"name=Bundle Option One1,type=select,required=1,sku=24-WG085,price=15.0000,default=0,default_qty=1.0000,price_type=fixed|name=Bundle Option One1,type=select,required=1,sku=24-WG086,price=10.0000,default=1,default_qty=1.0000,price_type=fixed", -24-WG085-bundle-fixed,,Default,bundle,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap Fixed Bundle,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and durable under strain.</p><ul><li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1,1,Taxable Goods,"Catalog, Search",14,,,,sprite-yoga-strap3,Meta Title,"meta1, meta2, meta9",meta description,"2015-10-25 03:34:20","2015-10-25 03:34:20",,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=1,shipment_type=together,quantity_and_stock_status=In Stock,required_options=0",0,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,"24-WG087,24-WG086","24-WG087,24-WG086","24-WG087,24-WG086",,,fixed,fixed,Price range,fixed,"name=Yoga Strap,type=radio,required=1,sku=24-WG086,price=0.0000,default=1,default_qty=3.0000,price_type=percent|name=Yoga Strap,type=radio,required=1,sku=24-WG085,price=0.0000,default=0,default_qty=3.0000,price_type=percent", \ No newline at end of file +sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,deferred_stock_update,use_config_deferred_stock_update,related_skus,crosssell_skus,upsell_skus,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus +24-WG085,,Default,simple,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap 6 foot,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and urable under strain.</p><ul><li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1.23,1,Taxable Goods,"Catalog, Search",14,,,,sprite-yoga-strap-6-foot,Meta Title,"meta1, meta2, meta3",meta description,2015-10-25 3:34:20,2015-10-25 3:34:20,,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=1,quantity_and_stock_status=In Stock,required_options=0",100,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,"24-WG087,24-WG086","24-WG087,24-WG086","24-WG087,24-WG086",,"name=Custom Yoga Option,type=drop_down,required=0,price=10.0000,price_type=fixed,sku=,option_title=Gold|name=Custom Yoga Option,type=drop_down,required=0,price=10.0000,price_type=fixed,sku=,option_title=Silver|name=Custom Yoga Option,type=drop_down,required=0,price=10.0000,price_type=fixed,sku=yoga3sku,option_title=Platinum",,,,,, +24-WG086,,Default,simple,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap 8 foot,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and durable under strain.</p><ul><li>8' long x 1.0"" wide.<li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1,1,Taxable Goods,"Catalog, Search",17,,,,sprite-yoga-strap-8-foot,Meta Title,"meta1, meta2, meta4",meta description,2015-10-25 3:34:20,2015-10-25 3:34:20,,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=0,quantity_and_stock_status=In Stock,required_options=0",100,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,24-WG087,24-WG087,24-WG087,,,,,,,, +24-WG087,,Default,simple,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap 10 foot,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and durable under strain.</p><ul><li>10' long x 1.0"" wide.<li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1,1,Taxable Goods,"Catalog, Search",21,,,,sprite-yoga-strap-10-foot,Meta Title,"meta1, meta2, meta5",meta description,2015-10-25 3:34:20,2015-10-25 3:34:20,,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=0,quantity_and_stock_status=In Stock,required_options=0",100,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,24-WG086,24-WG086,24-WG086,,,,,,,, +24-WG085_Group,,Default,grouped,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Set of Sprite Yoga Straps,"<p>Great set of Sprite Yoga Straps for every stretch and hold you need. There are three straps in this set: 6', 8' and 10'.</p><ul><li>100% soft and durable cotton.</li><li>Plastic cinch buckle is easy to use.</li><li>Choice of three natural colors made from phthalate and heavy metal free dyes.</li></ul>",,,1,,"Catalog, Search",,,,,set-of-sprite-yoga-straps,Meta Title,"meta1, meta2, meta6",meta description,2015-10-25 3:34:20,2015-10-25 3:34:20,,,Block after Info Column,,,,,,,,,,,,,"has_options=0,quantity_and_stock_status=In Stock,required_options=0",0,0,1,0,0,1,1,0,0,1,1,,1,1,1,1,0,1,0,0,1,0,1,"24-WG087,24-WG086","24-WG087,24-WG086","24-WG087,24-WG086",,,,,,,,"24-WG085=5.0000,24-WG086=5.0000" +24-WG085-bundle-dynamic,,Default,bundle,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap Dynamic Bundle,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and durable under strain.</p><ul><li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1.12,1,Taxable Goods,"Catalog, Search",14,,,,sprite-yoga-strap2,Meta Title,"meta1, meta2, meta8",meta description,2015-10-25 3:34:20,2015-10-25 3:34:20,,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=1,shipment_type=together,quantity_and_stock_status=In Stock,required_options=0",0,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,"24-WG087,24-WG086","24-WG087,24-WG086","24-WG087,24-WG086",,,dynamic,dynamic,Price range,fixed,"name=Bundle Option One1,type=select,required=1,sku=24-WG085,price=15.0000,default=0,default_qty=1.0000,price_type=fixed|name=Bundle Option One1,type=select,required=1,sku=24-WG086,price=10.0000,default=1,default_qty=1.0000,price_type=fixed", +24-WG085-bundle-fixed,,Default,bundle,"Default Category/Gear,Default Category/Gear/Fitness Equipment",base,Sprite Yoga Strap Fixed Bundle,"<p>The Sprite Yoga Strap is your untiring partner in demanding stretches, holds and alignment routines. The strap's 100% organic cotton fabric is woven tightly to form a soft, textured yet non-slip surface. The plastic clasp buckle is easily adjustable, lightweight and durable under strain.</p><ul><li>100% soft and durable cotton.<li>Plastic cinch buckle is easy to use.<li>Three natural colors made from phthalate and heavy metal free dyes.</ul>",,1,1,Taxable Goods,"Catalog, Search",14,,,,sprite-yoga-strap3,Meta Title,"meta1, meta2, meta9",meta description,2015-10-25 3:34:20,2015-10-25 3:34:20,,,Block after Info Column,,,,,,,,,,,Use config,,"has_options=1,shipment_type=together,quantity_and_stock_status=In Stock,required_options=0",0,0,1,0,0,1,1,0,0,1,1,,1,0,1,1,0,1,0,0,1,0,1,"24-WG087,24-WG086","24-WG087,24-WG086","24-WG087,24-WG086",,,fixed,fixed,Price range,fixed,"name=Yoga Strap,type=radio,required=1,sku=24-WG086,price=0.0000,default=1,default_qty=3.0000,price_type=percent|name=Yoga Strap,type=radio,required=1,sku=24-WG085,price=0.0000,default=0,default_qty=3.0000,price_type=percent", \ No newline at end of file diff --git a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminProductImportCSVFileCorrectDifferentFilesTest.xml b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminProductImportCSVFileCorrectDifferentFilesTest.xml index eb84929ec8d93..56c1c43bc28d2 100644 --- a/app/code/Magento/ImportExport/Test/Mftf/Test/AdminProductImportCSVFileCorrectDifferentFilesTest.xml +++ b/app/code/Magento/ImportExport/Test/Mftf/Test/AdminProductImportCSVFileCorrectDifferentFilesTest.xml @@ -12,6 +12,7 @@ <annotations> <description value="Product import from CSV file correct from different files."/> <features value="Import/Export"/> + <stories value="Product Import"/> <title value="Product import from CSV file correct from different files."/> <severity value="MAJOR"/> <testCaseId value="MC-17104"/> diff --git a/app/code/Magento/ImportExport/i18n/en_US.csv b/app/code/Magento/ImportExport/i18n/en_US.csv index 5787d6f7d02b6..d23edb5db53a1 100644 --- a/app/code/Magento/ImportExport/i18n/en_US.csv +++ b/app/code/Magento/ImportExport/i18n/en_US.csv @@ -29,9 +29,7 @@ Import,Import "File to Import","File to Import" "Select File to Import","Select File to Import" "Images File Directory","Images File Directory" -"For Type ""Local Server"" use relative path to Magento installation, - e.g. var/export, var/import, var/export/some/dir","For Type ""Local Server"" use relative path to Magento installation, - e.g. var/export, var/import, var/export/some/dir" +"For Type ""Local Server"" use relative path to <Magento root directory>/var/import/images, e.g. <i>product_images</i>, <i>import_images/batch1</i>.<br><br>For example, in case <i>product_images</i>, files should be placed into <i><Magento root directory>/var/import/images/product_images</i> folder.","For Type ""Local Server"" use relative path to <Magento root directory>/var/import/images, e.g. <i>product_images</i>, <i>import_images/batch1</i>.<br><br>For example, in case <i>product_images</i>, files should be placed into <i><Magento root directory>/var/import/images/product_images</i> folder." "Download Sample File","Download Sample File" "Please correct the data sent value.","Please correct the data sent value." Import/Export,Import/Export diff --git a/app/code/Magento/Quote/Test/Unit/Model/ChangeQuoteControlTest.php b/app/code/Magento/Quote/Test/Unit/Model/ChangeQuoteControlTest.php new file mode 100644 index 0000000000000..dc62c57c84941 --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/ChangeQuoteControlTest.php @@ -0,0 +1,144 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Quote\Test\Unit\Model; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Authorization\Model\UserContextInterface; +use Magento\Quote\Model\ChangeQuoteControl; +use Magento\Quote\Api\Data\CartInterface; + +/** + * Unit test for \Magento\Quote\Model\ChangeQuoteControl + * + * Class \Magento\Quote\Test\Unit\Model\ChangeQuoteControlTest + */ +class ChangeQuoteControlTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + */ + protected $objectManager; + + /** + * @var \Magento\Quote\Model\ChangeQuoteControl + */ + protected $model; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $userContextMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $quoteMock; + + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->userContextMock = $this->createMock(UserContextInterface::class); + + $this->model = $this->objectManager->getObject( + ChangeQuoteControl::class, + [ + 'userContext' => $this->userContextMock + ] + ); + + $this->quoteMock = $this->getMockForAbstractClass( + CartInterface::class, + [], + '', + false, + true, + true, + ['getCustomerId'] + ); + } + + /** + * Test if the quote is belonged to customer + */ + public function testIsAllowedIfTheQuoteIsBelongedToCustomer() + { + $quoteCustomerId = 1; + $this->quoteMock->expects($this->any())->method('getCustomerId') + ->will($this->returnValue($quoteCustomerId)); + $this->userContextMock->expects($this->any())->method('getUserType') + ->will($this->returnValue(UserContextInterface::USER_TYPE_CUSTOMER)); + $this->userContextMock->expects($this->any())->method('getUserId') + ->will($this->returnValue($quoteCustomerId)); + + $this->assertEquals(true, $this->model->isAllowed($this->quoteMock)); + } + + /** + * Test if the quote is not belonged to customer + */ + public function testIsAllowedIfTheQuoteIsNotBelongedToCustomer() + { + $currentCustomerId = 1; + $quoteCustomerId = 2; + + $this->quoteMock->expects($this->any())->method('getCustomerId') + ->will($this->returnValue($quoteCustomerId)); + $this->userContextMock->expects($this->any())->method('getUserType') + ->will($this->returnValue(UserContextInterface::USER_TYPE_CUSTOMER)); + $this->userContextMock->expects($this->any())->method('getUserId') + ->will($this->returnValue($currentCustomerId)); + + $this->assertEquals(false, $this->model->isAllowed($this->quoteMock)); + } + + /** + * Test if the quote is belonged to guest and the context is guest + */ + public function testIsAllowedIfQuoteIsBelongedToGuestAndContextIsGuest() + { + $quoteCustomerId = null; + $this->quoteMock->expects($this->any())->method('getCustomerId') + ->will($this->returnValue($quoteCustomerId)); + $this->userContextMock->expects($this->any())->method('getUserType') + ->will($this->returnValue(UserContextInterface::USER_TYPE_GUEST)); + $this->assertEquals(true, $this->model->isAllowed($this->quoteMock)); + } + + /** + * Test if the quote is belonged to customer and the context is guest + */ + public function testIsAllowedIfQuoteIsBelongedToCustomerAndContextIsGuest() + { + $quoteCustomerId = 1; + $this->quoteMock->expects($this->any())->method('getCustomerId') + ->will($this->returnValue($quoteCustomerId)); + $this->userContextMock->expects($this->any())->method('getUserType') + ->will($this->returnValue(UserContextInterface::USER_TYPE_GUEST)); + $this->assertEquals(false, $this->model->isAllowed($this->quoteMock)); + } + + /** + * Test if the context is admin + */ + public function testIsAllowedIfContextIsAdmin() + { + $this->userContextMock->expects($this->any())->method('getUserType') + ->will($this->returnValue(UserContextInterface::USER_TYPE_ADMIN)); + $this->assertEquals(true, $this->model->isAllowed($this->quoteMock)); + } + + /** + * Test if the context is integration + */ + public function testIsAllowedIfContextIsIntegration() + { + $this->userContextMock->expects($this->any())->method('getUserType') + ->will($this->returnValue(UserContextInterface::USER_TYPE_INTEGRATION)); + $this->assertEquals(true, $this->model->isAllowed($this->quoteMock)); + } +} diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Quote/Address/Total/ShippingDiscountTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Quote/Address/Total/ShippingDiscountTest.php new file mode 100644 index 0000000000000..b5b6d047c3af2 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Quote/Address/Total/ShippingDiscountTest.php @@ -0,0 +1,228 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\SalesRule\Test\Unit\Model\Quote\Address\Total; + +use Magento\SalesRule\Model\Quote\Address\Total\ShippingDiscount; +use Magento\SalesRule\Model\Validator; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\Address; +use Magento\Quote\Api\Data\ShippingAssignmentInterface; +use Magento\Quote\Api\Data\ShippingInterface; +use Magento\Quote\Model\Quote\Address\Total; + +/** + * Class \Magento\SalesRule\Test\Unit\Model\Quote\Address\Total\ShippingDiscountTest + */ +class ShippingDiscountTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject | Validator + */ + protected $validatorMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | Quote + */ + private $quoteMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | Total + */ + private $totalMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | Address + */ + private $addressMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | ShippingAssignmentInterface + */ + private $shippingAssignmentMock; + + /** + * @var ShippingDiscount + */ + private $discount; + + protected function setUp() + { + $this->validatorMock = $this->getMockBuilder(\Magento\SalesRule\Model\Validator::class) + ->disableOriginalConstructor() + ->setMethods( + [ + 'reset', + 'processShippingAmount', + '__wakeup', + ] + ) + ->getMock(); + $this->quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class); + $this->totalMock = $this->createPartialMock( + \Magento\Quote\Model\Quote\Address\Total::class, + [ + 'getDiscountAmount', + 'getDiscountDescription', + 'addTotalAmount', + 'addBaseTotalAmount', + 'setShippingDiscountAmount', + 'setBaseShippingDiscountAmount', + 'getSubtotal', + 'setSubtotalWithDiscount', + 'setBaseSubtotalWithDiscount', + 'getBaseSubtotal', + 'getBaseDiscountAmount', + 'setDiscountDescription' + ] + ); + + $this->addressMock = $this->createPartialMock( + Address::class, + [ + 'getQuote', + 'getShippingAmount', + 'getShippingDiscountAmount', + 'getBaseShippingDiscountAmount', + 'setShippingDiscountAmount', + 'setBaseShippingDiscountAmount', + 'getDiscountDescription', + 'setDiscountAmount', + 'setBaseDiscountAmount', + '__wakeup' + ] + ); + + $shipping = $this->createMock(ShippingInterface::class); + $shipping->expects($this->any())->method('getAddress')->willReturn($this->addressMock); + $this->shippingAssignmentMock = $this->createMock(ShippingAssignmentInterface::class); + $this->shippingAssignmentMock->expects($this->any())->method('getShipping')->willReturn($shipping); + + $this->discount = new ShippingDiscount( + $this->validatorMock + ); + } + + /** + * Test collect with the quote has no shipping amount discount + */ + public function testCollectNoShippingAmount() + { + $itemNoDiscount = $this->createMock(\Magento\Quote\Model\Quote\Item::class); + + $this->addressMock->expects($this->any())->method('getQuote')->willReturn($this->quoteMock); + + $this->addressMock->expects($this->any())->method('getShippingAmount')->willReturn(0); + + $this->shippingAssignmentMock->expects($this->any())->method('getItems') + ->willReturn([$itemNoDiscount]); + + $this->addressMock->expects($this->once())->method('setShippingDiscountAmount') + ->with(0) + ->willReturnSelf(); + $this->addressMock->expects($this->once())->method('setBaseShippingDiscountAmount') + ->with(0) + ->willReturnSelf(); + + /* Assert Collect function */ + $this->assertInstanceOf( + ShippingDiscount::class, + $this->discount->collect($this->quoteMock, $this->shippingAssignmentMock, $this->totalMock) + ); + } + + /** + * Test collect with the quote has shipping amount discount + */ + public function testCollectWithShippingAmountDiscount() + { + $shippingAmount = 100; + $shippingDiscountAmount = 50; + $baseShippingDiscountAmount = 50; + $discountDescription = 'Discount $50'; + $subTotal = 200; + $discountAmount = -100; + $baseSubTotal = 200; + $baseDiscountAmount = -100; + + $itemNoDiscount = $this->createMock(\Magento\Quote\Model\Quote\Item::class); + + $this->addressMock->expects($this->any())->method('getQuote')->willReturn($this->quoteMock); + + $this->addressMock->expects($this->any())->method('getShippingAmount')->willReturn($shippingAmount); + + $this->addressMock->expects($this->any())->method('getShippingDiscountAmount') + ->willReturn($shippingDiscountAmount); + $this->addressMock->expects($this->any())->method('getBaseShippingDiscountAmount') + ->willReturn($baseShippingDiscountAmount); + + $this->addressMock->expects($this->any())->method('getDiscountDescription') + ->willReturn($discountDescription); + + $this->shippingAssignmentMock->expects($this->any())->method('getItems') + ->willReturn([$itemNoDiscount]); + + $this->totalMock->expects($this->once())->method('addTotalAmount') + ->with('discount', -$shippingDiscountAmount)->willReturnSelf(); + $this->totalMock->expects($this->once())->method('addBaseTotalAmount') + ->with('discount', -$baseShippingDiscountAmount)->willReturnSelf(); + + $this->totalMock->expects($this->once())->method('setShippingDiscountAmount') + ->with($shippingDiscountAmount)->willReturnSelf(); + $this->totalMock->expects($this->once())->method('setBaseShippingDiscountAmount') + ->with($baseShippingDiscountAmount)->willReturnSelf(); + + $this->totalMock->expects($this->any())->method('getSubtotal') + ->willReturn($subTotal); + $this->totalMock->expects($this->any())->method('getDiscountAmount') + ->willReturn($discountAmount); + + $this->totalMock->expects($this->any())->method('getBaseSubtotal') + ->willReturn($baseSubTotal); + $this->totalMock->expects($this->any())->method('getBaseDiscountAmount') + ->willReturn($baseDiscountAmount); + + $this->totalMock->expects($this->once())->method('setDiscountDescription') + ->with($discountDescription)->willReturnSelf(); + + $this->totalMock->expects($this->once())->method('setSubtotalWithDiscount') + ->with(100)->willReturnSelf(); + $this->totalMock->expects($this->once())->method('setBaseSubtotalWithDiscount') + ->with(100)->willReturnSelf(); + + $this->addressMock->expects($this->once())->method('setDiscountAmount') + ->with($discountAmount)->willReturnSelf(); + + $this->addressMock->expects($this->once())->method('setBaseDiscountAmount') + ->with($baseDiscountAmount)->willReturnSelf(); + + /* Assert Collect function */ + $this->assertInstanceOf( + ShippingDiscount::class, + $this->discount->collect($this->quoteMock, $this->shippingAssignmentMock, $this->totalMock) + ); + } + + /** + * Test fetch function with discount = 100 + */ + public function testFetch() + { + $discountAmount = 100; + $discountDescription = 100; + $expectedResult = [ + 'code' => 'discount', + 'value' => 100, + 'title' => __('Discount (%1)', $discountDescription) + ]; + $this->totalMock->expects($this->once())->method('getDiscountAmount') + ->willReturn($discountAmount); + $this->totalMock->expects($this->once())->method('getDiscountDescription') + ->willReturn($discountDescription); + $this->assertEquals($expectedResult, $this->discount->fetch($this->quoteMock, $this->totalMock)); + } +} diff --git a/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AdminMarketingSiteDeleteByNameActionGroup.xml b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AdminMarketingSiteDeleteByNameActionGroup.xml new file mode 100644 index 0000000000000..16bf43da2e690 --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AdminMarketingSiteDeleteByNameActionGroup.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminMarketingSiteDeleteByNameActionGroup"> + <annotations> + <description>Go to the Site map page. Delete a site map based on the provided Name.</description> + </annotations> + <arguments> + <argument name="filename" type="string"/> + </arguments> + + <amOnPage url="{{AdminMarketingSiteMapGridPage.url}}" stepKey="amOnSiteMapGridPage"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <click selector="{{AdminMarketingSiteMapGridSection.resetButton}}" stepKey="resetSearchFilter"/> + <fillField selector="{{AdminMarketingSiteMapGridSection.fileNameTextField}}" userInput="{{filename}}" stepKey="fillFileNameField"/> + <click selector="{{AdminMarketingSiteMapGridSection.searchButton}}" stepKey="clickSearchButton"/> + <see userInput="{{filename}}" selector="{{AdminMarketingSiteMapGridSection.firstSearchResult}}" stepKey="verifyThatCorrectStoreGroupFound"/> + <click selector="{{AdminMarketingSiteMapGridSection.firstSearchResult}}" stepKey="clickEditExistingRow"/> + <waitForPageLoad stepKey="waitForSiteMapToLoad"/> + <click selector="{{AdminMarketingSiteMapEditActionSection.delete}}" stepKey="deleteSiteMap"/> + <waitForAjaxLoad stepKey="waitForAjaxLoad"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmDelete"/> + <waitForPageLoad stepKey="waitForDeleteLoad"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AdminMarketingSiteMapFillFormActionGroup.xml b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AdminMarketingSiteMapFillFormActionGroup.xml new file mode 100644 index 0000000000000..06e992736bf06 --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AdminMarketingSiteMapFillFormActionGroup.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="AdminMarketingSiteMapFillFormActionGroup"> + <annotations> + <description>Fill data to Site map form</description> + </annotations> + <arguments> + <argument name="sitemap" type="entity" defaultValue="DefaultSiteMap"/> + </arguments> + <fillField selector="{{AdminMarketingSiteMapEditActionSection.filename}}" userInput="{{sitemap.filename}}" stepKey="fillFilename"/> + <fillField selector="{{AdminMarketingSiteMapEditActionSection.path}}" userInput="{{sitemap.path}}" stepKey="fillPath"/> + <click selector="{{AdminMarketingSiteMapEditActionSection.save}}" stepKey="saveSiteMap"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AdminMarketingSiteMapNavigateNewActionGroup.xml b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AdminMarketingSiteMapNavigateNewActionGroup.xml new file mode 100644 index 0000000000000..78cfeab66f1c4 --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AdminMarketingSiteMapNavigateNewActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminMarketingSiteMapNavigateNewActionGroup"> + <annotations> + <description>Navigate to New Site Map</description> + </annotations> + <amOnPage url="{{AdminMarketingSiteMapNewPage.url}}" stepKey="openNewSiteMapPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AssertSiteMapCreateSuccessActionGroup.xml b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AssertSiteMapCreateSuccessActionGroup.xml new file mode 100644 index 0000000000000..77f26063e8034 --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AssertSiteMapCreateSuccessActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertSiteMapCreateSuccessActionGroup"> + <annotations> + <description>Validate the success message after creating site map.</description> + </annotations> + + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the sitemap." stepKey="seeSuccess"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AssertSiteMapDeleteSuccessActionGroup.xml b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AssertSiteMapDeleteSuccessActionGroup.xml new file mode 100644 index 0000000000000..15df8aa2f25f1 --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/ActionGroup/AssertSiteMapDeleteSuccessActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertSiteMapDeleteSuccessActionGroup"> + <annotations> + <description>Validate the success message after delete site map.</description> + </annotations> + + <see selector="{{AdminMessagesSection.success}}" userInput="You deleted the sitemap." stepKey="seeSuccess"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sitemap/Test/Mftf/Data/SitemapData.xml b/app/code/Magento/Sitemap/Test/Mftf/Data/SitemapData.xml new file mode 100644 index 0000000000000..0b5d5d3dcdefe --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/Data/SitemapData.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="DefaultSiteMap"> + <data key="filename">sitemap.xml</data> + <data key="path">/</data> + </entity> +</entities> diff --git a/app/code/Magento/Sitemap/Test/Mftf/Page/AdminMarketingSiteMapGridPage.xml b/app/code/Magento/Sitemap/Test/Mftf/Page/AdminMarketingSiteMapGridPage.xml new file mode 100644 index 0000000000000..b15a16bf134ad --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/Page/AdminMarketingSiteMapGridPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminMarketingSiteMapGridPage" url="admin/sitemap/" area="admin" module="Sitemap"> + <section name="AdminMarketingSiteMapGridSection"/> + </page> +</pages> diff --git a/app/code/Magento/Sitemap/Test/Mftf/Page/AdminMarketingSiteMapNewPage.xml b/app/code/Magento/Sitemap/Test/Mftf/Page/AdminMarketingSiteMapNewPage.xml new file mode 100644 index 0000000000000..5450ece5bb3c2 --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/Page/AdminMarketingSiteMapNewPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminMarketingSiteMapNewPage" url="admin/sitemap/new/" area="admin" module="Sitemap"> + <section name="AdminMarketingSiteMapEditActionSection"/> + </page> +</pages> diff --git a/app/code/Magento/Sitemap/Test/Mftf/Section/AdminMarketingSiteMapEditActionSection.xml b/app/code/Magento/Sitemap/Test/Mftf/Section/AdminMarketingSiteMapEditActionSection.xml new file mode 100644 index 0000000000000..841071350526a --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/Section/AdminMarketingSiteMapEditActionSection.xml @@ -0,0 +1,20 @@ +<?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="AdminMarketingSiteMapEditActionSection"> + <element name="save" type="button" selector="#save" timeout="10"/> + <element name="delete" type="button" selector="#delete" timeout="10"/> + <element name="saveAndGenerate" type="button" selector="#generate" timeout="10"/> + <element name="reset" type="button" selector="#reset"/> + <element name="back" type="button" selector="#back"/> + <element name="filename" type="input" selector="input[name='sitemap_filename']"/> + <element name="path" type="input" selector="input[name='sitemap_path']"/> + </section> +</sections> diff --git a/app/code/Magento/Sitemap/Test/Mftf/Section/AdminMarketingSiteMapGridSection.xml b/app/code/Magento/Sitemap/Test/Mftf/Section/AdminMarketingSiteMapGridSection.xml new file mode 100644 index 0000000000000..50c96ae6748ce --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/Section/AdminMarketingSiteMapGridSection.xml @@ -0,0 +1,17 @@ +<?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="AdminMarketingSiteMapGridSection"> + <element name="resetButton" type="button" selector="button[title='Reset Filter']"/> + <element name="searchButton" type="button" selector=".admin__filter-actions [title='Search']"/> + <element name="firstSearchResult" type="text" selector="#sitemapGrid_table>tbody>tr:nth-child(1)"/> + <element name="fileNameTextField" type="input" selector="#sitemapGrid_filter_sitemap_filename" timeout="90"/> + </section> +</sections> diff --git a/app/code/Magento/Sitemap/Test/Mftf/Test/AdminMarketingSiteMapCreateNewTest.xml b/app/code/Magento/Sitemap/Test/Mftf/Test/AdminMarketingSiteMapCreateNewTest.xml new file mode 100644 index 0000000000000..57d8f8c75d23d --- /dev/null +++ b/app/code/Magento/Sitemap/Test/Mftf/Test/AdminMarketingSiteMapCreateNewTest.xml @@ -0,0 +1,36 @@ +<?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="AdminMarketingSiteMapCreateNewTest"> + <annotations> + <features value="Sitemap"/> + <stories value="Create Site Map"/> + <title value="Create New Site Map with valid data"/> + <description value="Create New Site Map with valid data"/> + <severity value="CRITICAL"/> + <group value="sitemap"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="LoginAsAdmin"/> + </before> + <after> + <actionGroup ref="AdminMarketingSiteDeleteByNameActionGroup" stepKey="deleteSiteMap"> + <argument name="filename" value="{{DefaultSiteMap.filename}}" /> + </actionGroup> + <actionGroup ref="AssertSiteMapDeleteSuccessActionGroup" stepKey="assertDeleteSuccessMessage"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <actionGroup ref="AdminMarketingSiteMapNavigateNewActionGroup" stepKey="navigateNewSiteMap"/> + <actionGroup ref="AdminMarketingSiteMapFillFormActionGroup" stepKey="fillSiteMapForm"> + <argument name="sitemap" value="DefaultSiteMap" /> + </actionGroup> + <actionGroup ref="AssertSiteMapCreateSuccessActionGroup" stepKey="seeSuccessMessage"/> + </test> +</tests> diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminDisablingSwatchTooltipsTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminDisablingSwatchTooltipsTest.xml index 3d69895b0c895..2ffc61614bd1d 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Test/AdminDisablingSwatchTooltipsTest.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminDisablingSwatchTooltipsTest.xml @@ -11,6 +11,7 @@ <test name="AdminDisablingSwatchTooltipsTest"> <annotations> <features value="Swatches"/> + <stories value="Swatch Tooltip Status Change"/> <title value="Admin disabling swatch tooltips test."/> <description value="Verify possibility to disable/enable swatch tooltips."/> <severity value="AVERAGE"/> diff --git a/app/code/Magento/Weee/Test/Mftf/Test/AdminFixedTaxValSavedForSpecificWebsiteTest.xml b/app/code/Magento/Weee/Test/Mftf/Test/AdminFixedTaxValSavedForSpecificWebsiteTest.xml index 85ed044644d5c..aeb8537313fae 100644 --- a/app/code/Magento/Weee/Test/Mftf/Test/AdminFixedTaxValSavedForSpecificWebsiteTest.xml +++ b/app/code/Magento/Weee/Test/Mftf/Test/AdminFixedTaxValSavedForSpecificWebsiteTest.xml @@ -11,6 +11,7 @@ <test name="AdminFixedTaxValSavedForSpecificWebsiteTest"> <annotations> <features value="Tax"/> + <stories value="Website Specific Fixed Product Tax"/> <title value="Fixed Product Tax value is saved correctly for Specific Website"/> <description value="Fixed Product Tax value is saved correctly for Specific Website"/> <severity value="MAJOR"/> diff --git a/app/design/frontend/Magento/blank/Magento_Newsletter/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Newsletter/web/css/source/_module.less index f22a325debc9c..09759d95c4b10 100644 --- a/app/design/frontend/Magento/blank/Magento_Newsletter/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Newsletter/web/css/source/_module.less @@ -44,7 +44,8 @@ } input { - padding-left: 35px; + margin-right: 35px; + padding: 0 0 0 35px; // Reset some default Safari padding values. } .title { @@ -75,7 +76,8 @@ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .block.newsletter { - width: 32%; + max-width: 44%; + width: max-content; .field { margin-right: 5px; diff --git a/app/design/frontend/Magento/luma/Magento_Newsletter/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Newsletter/web/css/source/_module.less index d7ee1319c9a43..5d44a32b9391b 100644 --- a/app/design/frontend/Magento/luma/Magento_Newsletter/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Newsletter/web/css/source/_module.less @@ -46,7 +46,8 @@ } input { - padding-left: 35px; + margin-right: 35px; + padding: 0 0 0 35px; // Reset some default Safari padding values. } .title { @@ -78,7 +79,8 @@ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .block.newsletter { - width: 34%; + max-width: 44%; + width: max-content; } } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php index cf7a0cb310ddd..876944e0027b4 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php @@ -45,13 +45,17 @@ public static function setUpBeforeClass() } else { //get current minor branch name preg_match('|^(\d+\.\d+)|', $branchName, $minorBranch); - $branchName = $minorBranch[0]; + if (isset($minorBranch[0])) { + $branchName = $minorBranch[0]; - //get all version branches - preg_match_all('|^(\d+\.\d+)|m', file_get_contents($branchesFile), $matches); + //get all version branches + preg_match_all('|^(\d+\.\d+)|m', file_get_contents($branchesFile), $matches); - //check is this a latest release branch - self::$actualBranch = ($branchName == max($matches[0])); + //check is this a latest release branch + self::$actualBranch = ($branchName == max($matches[0])); + } else { + self::$actualBranch = true; + } } }