diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index f6c8b354f42cc..12ad4e452b1c7 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -28,8 +28,8 @@ ### Expected result -1. [Screenshot, logs] +1. [Screenshots, logs or description] ### Actual result -1. [Screenshot, logs] +1. [Screenshots, logs or description] diff --git a/app/code/Magento/Backend/etc/adminhtml/di.xml b/app/code/Magento/Backend/etc/adminhtml/di.xml index 1276033b33056..e886e21ef4313 100644 --- a/app/code/Magento/Backend/etc/adminhtml/di.xml +++ b/app/code/Magento/Backend/etc/adminhtml/di.xml @@ -145,9 +145,6 @@ Magento\Config\Model\Config\Structure\ElementVisibilityInterface::HIDDEN Magento\Config\Model\Config\Structure\ElementVisibilityInterface::DISABLED - - - diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Response/PayPal/VaultDetailsHandlerTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Response/PayPal/VaultDetailsHandlerTest.php index ebadc1703ecad..b3a7f8b9ee76a 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Response/PayPal/VaultDetailsHandlerTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Response/PayPal/VaultDetailsHandlerTest.php @@ -88,7 +88,7 @@ protected function setUp() $this->paymentInfoMock = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() - ->setMethods(['__wakeup']) + ->setMethods(['__wakeup', 'getExtensionAttributes']) ->getMock(); $this->paymentTokenMock = $objectManager->getObject(PaymentToken::class); @@ -107,6 +107,10 @@ protected function setUp() ->setMethods(['create']) ->getMock(); + $this->paymentInfoMock->expects(self::any()) + ->method('getExtensionAttributes') + ->willReturn($this->paymentExtensionMock); + $this->subject = [ 'payment' => $this->paymentDataObjectMock, ]; @@ -184,7 +188,7 @@ public function testHandleWithoutToken() ->method('create'); $this->handler->handle($this->subject, $response); - self::assertNull($this->paymentInfoMock->getExtensionAttributes()); + self::assertNotNull($this->paymentInfoMock->getExtensionAttributes()); } /** diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Response/VaultDetailsHandlerTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Response/VaultDetailsHandlerTest.php index 74592c6869ed3..c8ec52560be29 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Response/VaultDetailsHandlerTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Response/VaultDetailsHandlerTest.php @@ -80,9 +80,11 @@ protected function setUp() $this->payment = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() - ->setMethods(['__wakeup']) + ->setMethods(['__wakeup', 'getExtensionAttributes']) ->getMock(); + $this->payment->expects(self::any())->method('getExtensionAttributes')->willReturn($this->paymentExtension); + $config = $this->getConfigMock(); $this->paymentHandler = new VaultDetailsHandler( diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php index 39863e6561c43..76bf5b659bda3 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php @@ -13,6 +13,7 @@ use Magento\Braintree\Observer\DataAssignObserver; use Magento\Braintree\Gateway\Config\PayPal\Config; use Magento\Braintree\Model\Paypal\Helper\QuoteUpdater; +use Magento\Quote\Api\Data\CartExtensionInterface; /** * Class QuoteUpdaterTest @@ -281,7 +282,7 @@ private function updateQuoteStep(\PHPUnit_Framework_MockObject_MockObject $quote */ private function getQuoteMock() { - return $this->getMockBuilder(Quote::class) + $quoteMock = $this->getMockBuilder(Quote::class) ->setMethods( [ 'getIsVirtual', @@ -291,9 +292,21 @@ private function getQuoteMock() 'collectTotals', 'getShippingAddress', 'getBillingAddress', + 'getExtensionAttributes' ] )->disableOriginalConstructor() ->getMock(); + + $cartExtensionMock = $this->getMockBuilder(CartExtensionInterface::class) + ->setMethods(['setShippingAssignments']) + ->disableOriginalConstructor() + ->getMock(); + + $quoteMock->expects(self::any()) + ->method('getExtensionAttributes') + ->willReturn($cartExtensionMock); + + return $quoteMock; } /** diff --git a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php index c0624be8e7a97..98fd96c52ccd9 100644 --- a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php +++ b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php @@ -314,7 +314,8 @@ protected function getBundleOptions() 'template' => 'ui/dynamic-rows/templates/collapsible', 'additionalClasses' => 'admin__field-wide', 'dataScope' => 'data.bundle_options', - 'bundleSelectionsName' => 'product_bundle_container.bundle_selections' + 'isDefaultFieldScope' => 'is_default', + 'bundleSelectionsName' => 'product_bundle_container.bundle_selections', ], ], ], @@ -378,7 +379,10 @@ protected function getBundleOptions() 'selection_qty' => '', ], 'links' => ['insertData' => '${ $.provider }:${ $.dataProvider }'], - 'source' => 'product' + 'imports' => [ + 'inputType' => '${$.provider}:${$.dataScope}.type', + ], + 'source' => 'product', ], ], ], @@ -594,11 +598,14 @@ protected function getBundleSelections() 'config' => [ 'componentType' => Container::NAME, 'isTemplate' => true, - 'component' => 'Magento_Bundle/js/components/bundle-record', + 'component' => 'Magento_Ui/js/dynamic-rows/record', 'is_collection' => true, 'imports' => [ - 'onTypeChanged' => '${ $.provider }:${ $.bundleOptionsDataScope }.type' - ] + 'inputType' => '${$.parentName}:inputType', + ], + 'exports' => [ + 'isDefaultValue' => '${$.parentName}:isDefaultValue.${$.index}', + ], ], ], ], @@ -691,11 +698,15 @@ protected function getBundleSelections() 'componentType' => Form\Field::NAME, 'formElement' => Form\Element\Checkbox::NAME, 'dataType' => Form\Element\DataType\Price::NAME, + 'component' => 'Magento_Bundle/js/components/bundle-user-defined-checkbox', 'label' => __('User Defined'), 'dataScope' => 'selection_can_change_qty', 'value' => '1', 'valueMap' => ['true' => '1', 'false' => '0'], 'sortOrder' => 110, + 'imports' => [ + 'inputType' => '${$.parentName}:inputType', + ], ], ], ], diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-checkbox.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-checkbox.js index b608cff85b067..09331d37bb3b6 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-checkbox.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-checkbox.js @@ -14,7 +14,10 @@ define([ clearing: false, parentContainer: '', parentSelections: '', - changer: '' + changer: '', + exports: { + value: '${$.parentName}:isDefaultValue' + } }, /** @@ -58,10 +61,6 @@ define([ this.prefer = typeMap[type]; this.elementTmpl(this.templates[typeMap[type]]); - - if (this.prefer === 'radio' && this.checked()) { - this.clearValues(); - } }, /** diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js index 428361f459544..a6fc84765cc65 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js @@ -14,7 +14,57 @@ define([ label: '', columnsHeader: false, columnsHeaderAfterRender: true, - addButton: false + addButton: false, + isDefaultFieldScope: 'is_default', + defaultRecords: { + use: [], + moreThanOne: false, + state: {} + }, + listens: { + inputType: 'onInputTypeChange', + isDefaultValue: 'onIsDefaultValue' + } + }, + + /** + * Handler for type select. + * + * @param {String} inputType - changed. + */ + onInputTypeChange: function (inputType) { + if (this.defaultRecords.moreThanOne && (inputType === 'radio' || inputType === 'select')) { + _.each(this.defaultRecords.use, function (index, counter) { + this.source.set( + this.dataScope + '.bundle_selections.' + index + '.' + this.isDefaultFieldScope, + counter ? '0' : '1' + ); + }.bind(this)); + } + }, + + /** + * Handler for is_default field. + * + * @param {Object} data - changed data. + */ + onIsDefaultValue: function (data) { + var cb, + use = 0; + + this.defaultRecords.use = []; + + cb = function (elem, key) { + + if (~~elem) { + this.defaultRecords.use.push(key); + use++; + } + + this.defaultRecords.moreThanOne = use > 1; + }.bind(this); + + _.each(data, cb); }, /** @@ -29,7 +79,6 @@ define([ recordIndex; this.parsePagesData(data); - this.templates.record.bundleOptionsDataScope = this.dataScope; if (newData.length) { if (this.insertData().length) { diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-user-defined-checkbox.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-user-defined-checkbox.js new file mode 100644 index 0000000000000..a7ceded02d0c3 --- /dev/null +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-user-defined-checkbox.js @@ -0,0 +1,30 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/element/single-checkbox' +], function (Checkbox) { + 'use strict'; + + return Checkbox.extend({ + defaults: { + listens: { + inputType: 'onInputTypeChange' + } + }, + + /** + * Handler for "inputType" property + * + * @param {String} data + */ + onInputTypeChange: function (data) { + data === 'checkbox' || data === 'multi' ? + this.clear() + .visible(false) : + this.visible(true); + } + }); +}); diff --git a/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php b/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php index c561913dee4d3..6c54aa4e171ef 100644 --- a/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php +++ b/app/code/Magento/Catalog/Block/Product/Compare/ListCompare.php @@ -213,6 +213,22 @@ public function getProductAttributeValue($product, $attribute) return (string)$value == '' ? __('No') : $value; } + /** + * Check if any of the products has a value set for the attribute + * + * @param \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute + * @return bool + */ + public function hasAttributeValueForProducts($attribute) + { + foreach ($this->getItems() as $item) { + if ($item->hasData($attribute->getAttributeCode())) { + return true; + } + } + return false; + } + /** * Retrieve Print URL * diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php index 6a2642a8568f4..b6206f96b91e0 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php @@ -5,6 +5,8 @@ */ namespace Magento\Catalog\Model\Indexer\Product\Eav; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav; + /** * Abstract action reindex class */ @@ -51,7 +53,7 @@ abstract public function execute($ids); /** * Retrieve array of EAV type indexers * - * @return \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav[] + * @return AbstractEav[] */ public function getIndexers() { @@ -69,7 +71,7 @@ public function getIndexers() * Retrieve indexer instance by type * * @param string $type - * @return \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav + * @return AbstractEav * @throws \Magento\Framework\Exception\LocalizedException */ public function getIndexer($type) @@ -108,7 +110,7 @@ public function reindex($ids = null) /** * Synchronize data between index storage and original storage * - * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav $indexer + * @param AbstractEav $indexer * @param string $destinationTable * @param array $ids * @throws \Exception @@ -134,16 +136,17 @@ protected function syncData($indexer, $destinationTable, $ids) /** * Retrieve product relations by children and parent * - * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav $indexer + * @param AbstractEav $indexer * @param array $ids - * * @param bool $onlyParents * @return array $ids */ - protected function processRelations($indexer, $ids, $onlyParents = false) + protected function processRelations(AbstractEav $indexer, array $ids, bool $onlyParents = false) { $parentIds = $indexer->getRelationsByChild($ids); + $parentIds = array_unique(array_merge($parentIds, $ids)); $childIds = $onlyParents ? [] : $indexer->getRelationsByParent($parentIds); + return array_unique(array_merge($ids, $childIds, $parentIds)); } } diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index e58c9aab77665..39f6dceed5460 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -2108,6 +2108,8 @@ public function reset() /** * Get cache tags associated with object id * + * @deprecated + * @see \Magento\Catalog\Model\Product::getIdentities * @return string[] */ public function getCacheIdTags() @@ -2533,13 +2535,7 @@ public function setTypeId($typeId) */ public function getExtensionAttributes() { - $extensionAttributes = $this->_getExtensionAttributes(); - if (null === $extensionAttributes) { - /** @var \Magento\Catalog\Api\Data\ProductExtensionInterface $extensionAttributes */ - $extensionAttributes = $this->extensionAttributesFactory->create(ProductInterface::class); - $this->setExtensionAttributes($extensionAttributes); - } - return $extensionAttributes; + return $this->_getExtensionAttributes(); } /** diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php index 0ce67a96a99cc..9b87515450a12 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php @@ -1570,7 +1570,7 @@ protected function getEntityPkName(\Magento\Eav\Model\Entity\AbstractEntity $ent } /** - * Add requere tax percent flag for product collection + * Add require tax percent flag for product collection * * @return $this */ diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php index c4e3fb1bf1e70..c33ea7c781aa3 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php @@ -82,6 +82,7 @@ public function reindexEntities($processIds) $this->_prepareIndex($processIds); $this->_prepareRelationIndex($processIds); $this->_removeNotVisibleEntityFromIndex(); + return $this; } @@ -159,11 +160,12 @@ protected function _removeNotVisibleEntityFromIndex() * @param array $parentIds the parent entity ids limitation * @return \Magento\Framework\DB\Select */ - protected function _prepareRelationIndexSelect($parentIds = null) + protected function _prepareRelationIndexSelect(array $parentIds = null) { $connection = $this->getConnection(); $idxTable = $this->getIdxTable(); $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField(); + $select = $connection->select()->from( ['l' => $this->getTable('catalog_product_relation')], [] @@ -179,6 +181,14 @@ protected function _prepareRelationIndexSelect($parentIds = null) ['i' => $idxTable], 'l.child_id = i.entity_id AND cs.store_id = i.store_id', [] + )->join( + ['sw' => $this->getTable('store_website')], + "cs.website_id = sw.website_id", + [] + )->join( + ['cpw' => $this->getTable('catalog_product_website')], + 'i.entity_id = cpw.product_id AND sw.website_id = cpw.website_id', + [] )->group( ['parent_id', 'i.attribute_id', 'i.store_id', 'i.value', 'l.child_id'] )->columns( diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionTest.php index 33b7892462f4c..fb90eaaaf1ec5 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionTest.php @@ -7,6 +7,8 @@ use Magento\Catalog\Model\CustomOptions\CustomOption; use Magento\Catalog\Model\Webapi\Product\Option\Type\File\Processor as FileProcessor; +use Magento\Framework\Api\ExtensionAttributesFactory; +use Magento\Catalog\Api\Data\CustomOptionExtensionInterface; class CustomOptionTest extends \PHPUnit\Framework\TestCase { @@ -15,6 +17,12 @@ class CustomOptionTest extends \PHPUnit\Framework\TestCase */ protected $model; + /** @var \Magento\Framework\Api\ExtensionAttributesFactory | \PHPUnit_Framework_MockObject_MockObject */ + private $extensionAttributesFactoryMock; + + /** @var \Magento\Catalog\Api\Data\CustomOptionExtensionInterface | \PHPUnit_Framework_MockObject_MockObject */ + private $extensionMock; + /** * @var FileProcessor | \PHPUnit_Framework_MockObject_MockObject */ @@ -30,7 +38,7 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $extensionAttributesFactory = $this->getMockBuilder(\Magento\Framework\Api\ExtensionAttributesFactory::class) + $this->extensionAttributesFactoryMock = $this->getMockBuilder(ExtensionAttributesFactory::class) ->disableOriginalConstructor() ->getMock(); @@ -52,10 +60,17 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); + $this->extensionMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\CustomOptionExtensionInterface::class) + ->setMethods(['getFileInfo']) + ->getMockForAbstractClass(); + + $this->extensionAttributesFactoryMock->expects(self::any()) + ->method('create')->willReturn($this->extensionMock); + $this->model = new CustomOption( $context, $registry, - $extensionAttributesFactory, + $this->extensionAttributesFactoryMock, $attributeValueFactory, $this->fileProcessor, $resource, @@ -84,14 +99,10 @@ public function testGetOptionValue() public function testGetOptionValueWithFileInfo() { - $customOption = $this->getMockBuilder(\Magento\Catalog\Api\Data\CustomOptionExtensionInterface::class) - ->setMethods(['getFileInfo']) - ->getMockForAbstractClass(); - $imageContent = $this->getMockBuilder(\Magento\Framework\Api\Data\ImageContentInterface::class) ->getMockForAbstractClass(); - $customOption->expects($this->once()) + $this->extensionMock->expects($this->once()) ->method('getFileInfo') ->willReturn($imageContent); @@ -112,7 +123,6 @@ public function testGetOptionValueWithFileInfo() ->with($imageContent) ->willReturn($imageResult); - $this->model->setExtensionAttributes($customOption); $this->model->setData(\Magento\Catalog\Api\Data\CustomOptionInterface::OPTION_VALUE, 'file'); $this->assertEquals($imageResult, $this->model->getOptionValue()); } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php index 58654136ab5a8..9d58822fb6073 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php @@ -113,11 +113,20 @@ public function testReindexWithoutArgumentsExecutesReindexAll() $this->_model->reindex(); } - public function testReindexWithNotNullArgumentExecutesReindexEntities() - { - $childIds = [1, 2, 3]; - $parentIds = [4]; - $reindexIds = array_merge($childIds, $parentIds); + /** + * @param array $ids + * @param array $parentIds + * @param array $childIds + * @return void + * @dataProvider reindexEntitiesDataProvider + */ + public function testReindexWithNotNullArgumentExecutesReindexEntities( + array $ids, + array $parentIds, + array $childIds + ) : void { + $reindexIds = array_unique(array_merge($ids, $parentIds, $childIds)); + $connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) ->getMockForAbstractClass(); @@ -129,11 +138,23 @@ public function testReindexWithNotNullArgumentExecutesReindexEntities() ->disableOriginalConstructor() ->getMock(); - $eavSource->expects($this->once())->method('getRelationsByChild')->with($childIds)->willReturn($childIds); - $eavSource->expects($this->once())->method('getRelationsByParent')->with($childIds)->willReturn($parentIds); + $eavSource->expects($this->once()) + ->method('getRelationsByChild') + ->with($ids) + ->willReturn($parentIds); + $eavSource->expects($this->once()) + ->method('getRelationsByParent') + ->with(array_unique(array_merge($parentIds, $ids))) + ->willReturn($childIds); - $eavDecimal->expects($this->once())->method('getRelationsByChild')->with($reindexIds)->willReturn($reindexIds); - $eavDecimal->expects($this->once())->method('getRelationsByParent')->with($reindexIds)->willReturn([]); + $eavDecimal->expects($this->once()) + ->method('getRelationsByChild') + ->with($reindexIds) + ->willReturn($parentIds); + $eavDecimal->expects($this->once()) + ->method('getRelationsByParent') + ->with(array_unique(array_merge($parentIds, $reindexIds))) + ->willReturn($childIds); $eavSource->expects($this->once())->method('getConnection')->willReturn($connectionMock); $eavDecimal->expects($this->once())->method('getConnection')->willReturn($connectionMock); @@ -153,6 +174,18 @@ public function testReindexWithNotNullArgumentExecutesReindexEntities() ->method('create') ->will($this->returnValue($eavDecimal)); - $this->_model->reindex($childIds); + $this->_model->reindex($ids); + } + + /** + * @return array + */ + public function reindexEntitiesDataProvider() : array + { + return [ + [[4], [], [1, 2, 3]], + [[3], [4], []], + [[5], [], []], + ]; } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php index 8d65153d7ba20..a370cbea13c2b 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php @@ -1336,7 +1336,6 @@ public function testSaveExistingWithMediaGalleryEntries() $expectedResult = [ [ - 'value_id' => 5, 'value_id' => 5, "label" => "new_label_text", 'file' => 'filename1', diff --git a/app/code/Magento/Catalog/etc/widget.xml b/app/code/Magento/Catalog/etc/widget.xml index ef9009549da24..a11d206e2ce42 100644 --- a/app/code/Magento/Catalog/etc/widget.xml +++ b/app/code/Magento/Catalog/etc/widget.xml @@ -64,7 +64,11 @@ - 86400 by default, if not set. To refresh instantly, clear the Blocks HTML Output cache. + + If not set, equals to 86400 seconds (24 hours). To update widget instantly, go to Cache Management and clear Blocks HTML Output cache. +
Widget will not show products that begin to match the specified conditions until cache is refreshed.]]> +
diff --git a/app/code/Magento/Catalog/i18n/en_US.csv b/app/code/Magento/Catalog/i18n/en_US.csv index b9012c030dace..0727d03df1340 100644 --- a/app/code/Magento/Catalog/i18n/en_US.csv +++ b/app/code/Magento/Catalog/i18n/en_US.csv @@ -705,7 +705,13 @@ Template,Template "New Products Names Only Template","New Products Names Only Template" "New Products Images Only Template","New Products Images Only Template" "Cache Lifetime (Seconds)","Cache Lifetime (Seconds)" -"86400 by default, if not set. To refresh instantly, clear the Blocks HTML Output cache.","86400 by default, if not set. To refresh instantly, clear the Blocks HTML Output cache." +"Time in seconds between the widget updates. +
If not set, equals to 86400 seconds (24 hours). To update widget instantly, go to Cache Management and clear Blocks HTML Output cache. +
Widget will not show products that begin to match the specified conditions until cache is refreshed." +, +"Time in seconds between the widget updates. +
If not set, equals to 86400 seconds (24 hours). To update widget instantly, go to Cache Management and clear Blocks HTML Output cache. +
Widget will not show products that begin to match the specified conditions until cache is refreshed." "Catalog Product Link","Catalog Product Link" "Link to a Specified Product","Link to a Specified Product" "Select Product...","Select Product..." diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/compare/list.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/compare/list.phtml index f1d4b32031e49..949d365e7899a 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/compare/list.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/compare/list.phtml @@ -8,8 +8,8 @@ /* @var $block \Magento\Catalog\Block\Product\Compare\ListCompare */ ?> -getItems()->getSize() ?> - +getItems()->getSize() ?> + @@ -24,14 +24,14 @@ - - getItems() as $_item): ?> - + + getItems() as $item): ?> + helper('Magento\Catalog\Helper\Product\Compare');?> - @@ -41,35 +41,35 @@ - - helper('Magento\Catalog\Helper\Output'); ?> - - getItems() as $_item): ?> - + + helper('Magento\Catalog\Helper\Output'); ?> + + getItems() as $item): ?> + - - getImage($_item, 'product_comparison_list')->toHtml() ?> + + getImage($item, 'product_comparison_list')->toHtml() ?> - - productAttribute($_item, $_item->getName(), 'name') ?> + + productAttribute($item, $item->getName(), 'name') ?> - getReviewsSummaryHtml($_item, 'short') ?> - getProductPrice($_item, '-compare-list-top') ?> + getReviewsSummaryHtml($item, 'short') ?> + getProductPrice($item, '-compare-list-top') ?>
- isSaleable()): ?> -
+ isSaleable()): ?> + getBlockHtml('formkey') ?>
- getIsSalable()): ?> + getIsSalable()): ?>
@@ -78,7 +78,7 @@
helper('Magento\Wishlist\Helper\Data')->isAllow()) : ?> @@ -89,39 +89,41 @@ - getAttributes() as $_attribute): ?> - - - getItems() as $_item): ?> - - - - escapeHtml($_attribute->getStoreLabel() ? $_attribute->getStoreLabel() : __($_attribute->getFrontendLabel())) ?> - - - - -
- getAttributeCode()) { - case "price": ?> - getProductPrice( - $_item, - '-compare-list-' . $_attribute->getCode() - ) - ?> - - getImage($_item, 'product_small_image')->toHtml(); ?> + getAttributes() as $attribute): ?> + + hasAttributeValueForProducts($attribute)): ?> + + getItems() as $item): ?> + + + + escapeHtml($attribute->getStoreLabel() ? $attribute->getStoreLabel() : __($attribute->getFrontendLabel())) ?> + + + + +
+ getAttributeCode()) { + case "price": ?> + getProductPrice( + $item, + '-compare-list-' . $attribute->getCode() + ) + ?> + + getImage($item, 'product_small_image')->toHtml(); ?> + + productAttribute($item, $block->getProductAttributeValue($item, $attribute), $attribute->getAttributeCode()) ?> - productAttribute($_item, $block->getProductAttributeValue($_item, $_attribute), $_attribute->getAttributeCode()) ?> - -
- - - + } ?> +
+ + + + diff --git a/app/code/Magento/CatalogWidget/etc/widget.xml b/app/code/Magento/CatalogWidget/etc/widget.xml index 3d54c314c6622..bcc1b623da02e 100644 --- a/app/code/Magento/CatalogWidget/etc/widget.xml +++ b/app/code/Magento/CatalogWidget/etc/widget.xml @@ -40,7 +40,11 @@ - 86400 by default, if not set. To refresh instantly, clear the Blocks HTML Output cache. + + If not set, equals to 86400 seconds (24 hours). To update widget instantly, go to Cache Management and clear Blocks HTML Output cache. +
Widget will not show products that begin to match the specified conditions until cache is refreshed.]]> +
diff --git a/app/code/Magento/CatalogWidget/i18n/en_US.csv b/app/code/Magento/CatalogWidget/i18n/en_US.csv index 9ecde5cb1a062..4cccbdd926282 100644 --- a/app/code/Magento/CatalogWidget/i18n/en_US.csv +++ b/app/code/Magento/CatalogWidget/i18n/en_US.csv @@ -16,5 +16,11 @@ Title,Title Template,Template "Products Grid Template","Products Grid Template" "Cache Lifetime (Seconds)","Cache Lifetime (Seconds)" -"86400 by default, if not set. To refresh instantly, clear the Blocks HTML Output cache.","86400 by default, if not set. To refresh instantly, clear the Blocks HTML Output cache." +"Time in seconds between the widget updates. +
If not set, equals to 86400 seconds (24 hours). To update widget instantly, go to Cache Management and clear Blocks HTML Output cache. +
Widget will not show products that begin to match the specified conditions until cache is refreshed." +, +"Time in seconds between the widget updates. +
If not set, equals to 86400 seconds (24 hours). To update widget instantly, go to Cache Management and clear Blocks HTML Output cache. +
Widget will not show products that begin to match the specified conditions until cache is refreshed." Conditions,Conditions diff --git a/app/code/Magento/Checkout/Api/Data/PaymentDetailsInterface.php b/app/code/Magento/Checkout/Api/Data/PaymentDetailsInterface.php index 45e885d0dbd46..cad1c100c7e5b 100644 --- a/app/code/Magento/Checkout/Api/Data/PaymentDetailsInterface.php +++ b/app/code/Magento/Checkout/Api/Data/PaymentDetailsInterface.php @@ -9,7 +9,7 @@ * Interface PaymentDetailsInterface * @api */ -interface PaymentDetailsInterface +interface PaymentDetailsInterface extends \Magento\Framework\Api\ExtensibleDataInterface { /**#@+ * Constants defined for keys of array, makes typos less likely diff --git a/app/code/Magento/Checkout/Block/Registration.php b/app/code/Magento/Checkout/Block/Registration.php index 91ec85c1db0ed..e880230f50a74 100644 --- a/app/code/Magento/Checkout/Block/Registration.php +++ b/app/code/Magento/Checkout/Block/Registration.php @@ -91,7 +91,7 @@ public function getEmailAddress() */ public function getCreateAccountUrl() { - return $this->getUrl('checkout/account/create'); + return $this->getUrl('checkout/account/delegateCreate'); } /** diff --git a/app/code/Magento/Checkout/Controller/Account/Create.php b/app/code/Magento/Checkout/Controller/Account/Create.php index 2ee5d6d5528c3..dae0bb98be453 100644 --- a/app/code/Magento/Checkout/Controller/Account/Create.php +++ b/app/code/Magento/Checkout/Controller/Account/Create.php @@ -9,6 +9,10 @@ use Magento\Framework\Exception\AlreadyExistsException; use Magento\Framework\Exception\NoSuchEntityException; +/** + * @deprecated + * @see DelegateCreate + */ class Create extends \Magento\Framework\App\Action\Action { /** diff --git a/app/code/Magento/Checkout/Controller/Account/DelegateCreate.php b/app/code/Magento/Checkout/Controller/Account/DelegateCreate.php new file mode 100644 index 0000000000000..6c4c8b053e2ae --- /dev/null +++ b/app/code/Magento/Checkout/Controller/Account/DelegateCreate.php @@ -0,0 +1,58 @@ +delegateService = $customerDelegation; + $this->session = $session; + } + + /** + * {@inheritdoc} + */ + public function execute() + { + /** @var string|null $orderId */ + $orderId = $this->session->getLastOrderId(); + if (!$orderId) { + return $this->resultRedirectFactory->create()->setPath('/'); + } + + return $this->delegateService->delegateNew((int)$orderId); + } +} diff --git a/app/code/Magento/Checkout/etc/adminhtml/routes.xml b/app/code/Magento/Checkout/etc/adminhtml/routes.xml new file mode 100644 index 0000000000000..e537861059870 --- /dev/null +++ b/app/code/Magento/Checkout/etc/adminhtml/routes.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/registration.js b/app/code/Magento/Checkout/view/frontend/web/js/view/registration.js index c715b5c4d45ce..a7b3e18c06088 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/registration.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/registration.js @@ -38,7 +38,16 @@ define([ }, /** - * Create new user account + * @return String + */ + getUrl: function () { + return this.registrationUrl; + }, + + /** + * Create new user account. + * + * @deprecated */ createAccount: function () { this.creationStarted(true); diff --git a/app/code/Magento/Checkout/view/frontend/web/template/registration.html b/app/code/Magento/Checkout/view/frontend/web/template/registration.html index 256fc1968abfc..ea94726e5443e 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/registration.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/registration.html @@ -11,11 +11,8 @@

:

-
- + +
- - -

- +
diff --git a/app/code/Magento/CheckoutAgreements/etc/adminhtml/routes.xml b/app/code/Magento/CheckoutAgreements/etc/adminhtml/routes.xml index 1249ea44b991e..5a708f49a7034 100644 --- a/app/code/Magento/CheckoutAgreements/etc/adminhtml/routes.xml +++ b/app/code/Magento/CheckoutAgreements/etc/adminhtml/routes.xml @@ -7,7 +7,7 @@ --> - + diff --git a/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php b/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php index 0c8ff7d0b2b78..4b7cd239a66f5 100644 --- a/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php +++ b/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php @@ -739,7 +739,7 @@ protected function _validatePath($path) */ protected function _sanitizePath($path) { - return rtrim(preg_replace('~[/\\\]+~', '/', $this->_directory->getDriver()->getRealPath($path)), '/'); + return rtrim(preg_replace('~[/\\\]+~', '/', $this->_directory->getDriver()->getRealPathSafety($path)), '/'); } /** diff --git a/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php b/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php index 2fb9649fc61de..25134451d5a56 100644 --- a/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php +++ b/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php @@ -114,16 +114,9 @@ class StorageTest extends \PHPUnit\Framework\TestCase protected function setUp() { $this->filesystemMock = $this->createMock(\Magento\Framework\Filesystem::class); - $this->driverMock = $this->getMockForAbstractClass( - \Magento\Framework\Filesystem\DriverInterface::class, - [], - '', - false, - false, - true, - ['getRealPath'] - ); - $this->driverMock->expects($this->any())->method('getRealPath')->will($this->returnArgument(0)); + $this->driverMock = $this->getMockBuilder(\Magento\Framework\Filesystem\DriverInterface::class) + ->setMethods(['getRealPathSafety']) + ->getMockForAbstractClass(); $this->directoryMock = $this->createPartialMock( \Magento\Framework\Filesystem\Directory\Write::class, @@ -243,6 +236,7 @@ public function testDeleteDirectoryOverRoot() $this->expectExceptionMessage( sprintf('Directory %s is not under storage root path.', self::INVALID_DIRECTORY_OVER_ROOT) ); + $this->driverMock->expects($this->atLeastOnce())->method('getRealPathSafety')->will($this->returnArgument(0)); $this->imagesStorage->deleteDirectory(self::INVALID_DIRECTORY_OVER_ROOT); } @@ -253,7 +247,7 @@ public function testDeleteRootDirectory() { $this->expectException(\Magento\Framework\Exception\LocalizedException::class); $this->expectExceptionMessage(sprintf('We can\'t delete root directory %s right now.', self::STORAGE_ROOT_DIR)); - + $this->driverMock->expects($this->atLeastOnce())->method('getRealPathSafety')->will($this->returnArgument(0)); $this->imagesStorage->deleteDirectory(self::STORAGE_ROOT_DIR); } diff --git a/app/code/Magento/Config/Model/Config/Structure/ConcealInProductionConfigList.php b/app/code/Magento/Config/Model/Config/Structure/ConcealInProductionConfigList.php index 92bc61b3d65e5..a5c1708cd6c49 100644 --- a/app/code/Magento/Config/Model/Config/Structure/ConcealInProductionConfigList.php +++ b/app/code/Magento/Config/Model/Config/Structure/ConcealInProductionConfigList.php @@ -42,36 +42,14 @@ class ConcealInProductionConfigList implements ElementVisibilityInterface */ private $state; - /** - * - * The list of form element paths which ignore visibility status. - * - * E.g. - * - * ```php - * [ - * 'general/country/default' => '', - * ]; - * ``` - * - * It means that: - * - field 'default' in group Country Options (in section General) will be showed, even if all group(section) - * will be hidden. - * - * @var array - */ - private $exemptions = []; - /** * @param State $state The object that has information about the state of the system * @param array $configs The list of form element paths with concrete visibility status. - * @param array $exemptions The list of form element paths which ignore visibility status. */ - public function __construct(State $state, array $configs = [], array $exemptions = []) + public function __construct(State $state, array $configs = []) { $this->state = $state; $this->configs = $configs; - $this->exemptions = $exemptions; } /** @@ -80,21 +58,11 @@ public function __construct(State $state, array $configs = [], array $exemptions */ public function isHidden($path) { - $result = false; $path = $this->normalizePath($path); - if ($this->state->getMode() === State::MODE_PRODUCTION - && preg_match('/(?(?
.*?)\/.*?)\/.*?/', $path, $match)) { - $group = $match['group']; - $section = $match['section']; - $exemptions = array_keys($this->exemptions); - foreach ($this->configs as $configPath => $value) { - if ($value === static::HIDDEN && strpos($path, $configPath) !==false) { - $result = empty(array_intersect([$section, $group, $path], $exemptions)); - } - } - } - return $result; + return $this->state->getMode() === State::MODE_PRODUCTION + && !empty($this->configs[$path]) + && $this->configs[$path] === static::HIDDEN; } /** diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Structure/ConcealInProductionConfigListTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Structure/ConcealInProductionConfigListTest.php index fa78d5dde652c..5cad923264e00 100644 --- a/app/code/Magento/Config/Test/Unit/Model/Config/Structure/ConcealInProductionConfigListTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Structure/ConcealInProductionConfigListTest.php @@ -33,13 +33,9 @@ protected function setUp() 'third/path' => 'no', 'third/path/field' => ConcealInProductionConfigList::DISABLED, 'first/path/field' => 'no', - 'fourth' => ConcealInProductionConfigList::HIDDEN, - ]; - $exemptions = [ - 'fourth/path/value' => '', ]; - $this->model = new ConcealInProductionConfigList($this->stateMock, $configs, $exemptions); + $this->model = new ConcealInProductionConfigList($this->stateMock, $configs); } /** @@ -100,10 +96,8 @@ public function hiddenDataProvider() ['first/path', State::MODE_PRODUCTION, false], ['first/path', State::MODE_DEFAULT, false], ['some/path', State::MODE_PRODUCTION, false], - ['second/path/field', State::MODE_PRODUCTION, true], + ['second/path', State::MODE_PRODUCTION, true], ['second/path', State::MODE_DEVELOPER, false], - ['fourth/path/value', State::MODE_PRODUCTION, false], - ['fourth/path/test', State::MODE_PRODUCTION, true], ]; } } diff --git a/app/code/Magento/ConfigurableProduct/Model/Plugin/ProductIdentitiesExtender.php b/app/code/Magento/ConfigurableProduct/Model/Plugin/ProductIdentitiesExtender.php new file mode 100644 index 0000000000000..0c3fc6fba6005 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Model/Plugin/ProductIdentitiesExtender.php @@ -0,0 +1,56 @@ +configurableType = $configurableType; + $this->productRepository = $productRepository; + } + + /** + * Add parent identities to product identities + * + * @param Product $subject + * @param array $identities + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetIdentities(Product $subject, array $identities): array + { + foreach ($this->configurableType->getParentIdsByChild($subject->getId()) as $parentId) { + $parentProduct = $this->productRepository->getById($parentId); + $identities = array_merge($identities, $parentProduct->getIdentities()); + } + + return array_unique($identities); + } +} diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Cache/Tag/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Cache/Tag/Configurable.php deleted file mode 100644 index ac42e320f3ad9..0000000000000 --- a/app/code/Magento/ConfigurableProduct/Model/Product/Cache/Tag/Configurable.php +++ /dev/null @@ -1,51 +0,0 @@ -catalogProductTypeConfigurable = $catalogProductTypeConfigurable; - } - - /** - * {@inheritdoc} - */ - public function getTags($object) - { - if (!is_object($object)) { - throw new \InvalidArgumentException('Provided argument is not an object'); - } - - if (!($object instanceof \Magento\Catalog\Model\Product)) { - throw new \InvalidArgumentException('Provided argument must be a product'); - } - - $result = $object->getIdentities(); - - foreach ($this->catalogProductTypeConfigurable->getParentIdsByChild($object->getId()) as $parentId) { - $result[] = \Magento\Catalog\Model\Product::CACHE_TAG . '_' . $parentId; - } - return $result; - } -} diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php index 95afba984d57d..ccff85dd9717f 100644 --- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php @@ -189,7 +189,6 @@ public function getChildrenIds($parentId, $required = true) */ public function getParentIdsByChild($childId) { - $parentIds = []; $select = $this->getConnection() ->select() ->from(['l' => $this->getMainTable()], []) @@ -198,10 +197,7 @@ public function getParentIdsByChild($childId) 'e.' . $this->optionProvider->getProductEntityLinkField() . ' = l.parent_id', ['e.entity_id'] )->where('l.product_id IN(?)', $childId); - - foreach ($this->getConnection()->fetchAll($select) as $row) { - $parentIds[] = $row['entity_id']; - } + $parentIds = $this->getConnection()->fetchCol($select); return $parentIds; } diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/ProductIdentitiesExtenderTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/ProductIdentitiesExtenderTest.php new file mode 100644 index 0000000000000..d29f163ee1129 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/ProductIdentitiesExtenderTest.php @@ -0,0 +1,77 @@ +configurableTypeMock = $this->getMockBuilder(Configurable::class) + ->disableOriginalConstructor() + ->getMock(); + $this->productRepositoryMock = $this->getMockBuilder(ProductRepositoryInterface::class) + ->getMock(); + + $this->plugin = new ProductIdentitiesExtender($this->configurableTypeMock, $this->productRepositoryMock); + } + + public function testAfterGetIdentities() + { + $productId = 1; + $productIdentity = 'cache_tag_1'; + $productMock = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->getMock(); + $parentProductId = 2; + $parentProductIdentity = 'cache_tag_2'; + $parentProductMock = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->getMock(); + + $productMock->expects($this->once()) + ->method('getId') + ->willReturn($productId); + $this->configurableTypeMock->expects($this->once()) + ->method('getParentIdsByChild') + ->with($productId) + ->willReturn([$parentProductId]); + $this->productRepositoryMock->expects($this->once()) + ->method('getById') + ->with($parentProductId) + ->willReturn($parentProductMock); + $parentProductMock->expects($this->once()) + ->method('getIdentities') + ->willReturn([$parentProductIdentity]); + + $productIdentities = $this->plugin->afterGetIdentities($productMock, [$productIdentity]); + $this->assertEquals([$productIdentity, $parentProductIdentity], $productIdentities); + } +} diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Cache/Tag/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Cache/Tag/ConfigurableTest.php deleted file mode 100644 index a3f1435f84d2f..0000000000000 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Cache/Tag/ConfigurableTest.php +++ /dev/null @@ -1,66 +0,0 @@ -typeResource = $this->createMock( - \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable::class - ); - - $this->model = new Configurable($this->typeResource); - } - - public function testGetWithScalar() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Provided argument is not an object'); - $this->model->getTags('scalar'); - } - - public function testGetTagsWithObject() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Provided argument must be a product'); - $this->model->getTags(new \stdClass()); - } - - public function testGetTagsWithVariation() - { - $product = $this->createMock(\Magento\Catalog\Model\Product::class); - - $identities = ['id1', 'id2']; - - $product->expects($this->once()) - ->method('getIdentities') - ->willReturn($identities); - - $parentId = 4; - $this->typeResource->expects($this->once()) - ->method('getParentIdsByChild') - ->willReturn([$parentId]); - - $expected = array_merge($identities, [\Magento\Catalog\Model\Product::CACHE_TAG . '_' . $parentId]); - - $this->assertEquals($expected, $this->model->getTags($product)); - } -} diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index 3f04081eaf645..15dbc53a5447a 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -168,13 +168,6 @@ - - - - \Magento\ConfigurableProduct\Model\Product\Cache\Tag\Configurable - - - @@ -209,4 +202,7 @@ + + + diff --git a/app/code/Magento/Customer/Api/AccountDelegationInterface.php b/app/code/Magento/Customer/Api/AccountDelegationInterface.php new file mode 100644 index 0000000000000..e3a738530c49d --- /dev/null +++ b/app/code/Magento/Customer/Api/AccountDelegationInterface.php @@ -0,0 +1,31 @@ +redirectFactory = $redirectFactory; + $this->storage = $storage; + } + + /** + * {@inheritdoc} + */ + public function createRedirectForNew( + CustomerInterface $customer, + array $mixedData = null + ): Redirect { + $this->storage->storeNewOperation($customer, $mixedData); + + return $this->redirectFactory->create()->setPath('customer/account/create'); + } +} diff --git a/app/code/Magento/Customer/Model/Delegation/Data/NewOperation.php b/app/code/Magento/Customer/Model/Delegation/Data/NewOperation.php new file mode 100644 index 0000000000000..5dcefc2326794 --- /dev/null +++ b/app/code/Magento/Customer/Model/Delegation/Data/NewOperation.php @@ -0,0 +1,54 @@ +customer = $customer; + $this->additionalData = $additionalData; + } + + /** + * @return CustomerInterface + */ + public function getCustomer(): CustomerInterface + { + return $this->customer; + } + + /** + * @return array + */ + public function getAdditionalData(): array + { + return $this->additionalData; + } +} diff --git a/app/code/Magento/Customer/Model/Delegation/Storage.php b/app/code/Magento/Customer/Model/Delegation/Storage.php new file mode 100644 index 0000000000000..71a61d59057cb --- /dev/null +++ b/app/code/Magento/Customer/Model/Delegation/Storage.php @@ -0,0 +1,151 @@ +newFactory = $newFactory; + $this->customerFactory = $customerFactory; + $this->addressFactory = $addressFactory; + $this->regionFactory = $regionFactory; + $this->logger = $logger; + $this->session = $session; + } + + /** + * Store data for new account operation. + * + * @param CustomerInterface $customer + * @param array $delegatedData + * + * @return void + */ + public function storeNewOperation(CustomerInterface $customer, array $delegatedData): void + { + /** @var Customer $customer */ + $customerData = $customer->__toArray(); + $addressesData = []; + if ($customer->getAddresses()) { + /** @var Address $address */ + foreach ($customer->getAddresses() as $address) { + $addressesData[] = $address->__toArray(); + } + } + $this->session->setCustomerFormData($customerData); + $this->session->setDelegatedNewCustomerData([ + 'customer' => $customerData, + 'addresses' => $addressesData, + 'delegated_data' => $delegatedData, + ]); + } + + /** + * Retrieve delegated new operation data and mark it as used. + * + * @return NewOperation|null + */ + public function consumeNewOperation() + { + try { + $serialized = $this->session->getDelegatedNewCustomerData(true); + } catch (\Throwable $exception) { + $this->logger->error($exception); + $serialized = null; + } + if ($serialized === null) { + return null; + } + + /** @var AddressInterface[] $addresses */ + $addresses = []; + foreach ($serialized['addresses'] as $addressData) { + if (isset($addressData['region'])) { + /** @var RegionInterface $region */ + $region = $this->regionFactory->create( + ['data' => $addressData['region']] + ); + $addressData['region'] = $region; + } + $addresses[] = $this->addressFactory->create( + ['data' => $addressData] + ); + } + $customerData = $serialized['customer']; + $customerData['addresses'] = $addresses; + + return $this->newFactory->create([ + 'customer' => $this->customerFactory->create( + ['data' => $customerData] + ), + 'additionalData' => $serialized['delegated_data'], + ]); + } +} diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php index 91a593c347806..29e35c721a3be 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php @@ -7,16 +7,20 @@ namespace Magento\Customer\Model\ResourceModel; use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Model\Delegation\Data\NewOperation; use Magento\Customer\Model\Customer\NotificationStorage; use Magento\Framework\Api\DataObjectHelper; use Magento\Framework\Api\ImageProcessorInterface; use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Customer\Model\Delegation\Storage as DelegatedStorage; use Magento\Framework\App\ObjectManager; /** * Customer repository. * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyFields) */ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInterface { @@ -95,6 +99,11 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte */ private $notificationStorage; + /** + * @var DelegatedStorage + */ + private $delegatedStorage; + /** * @param \Magento\Customer\Model\CustomerFactory $customerFactory * @param \Magento\Customer\Model\Data\CustomerSecureFactory $customerSecureFactory @@ -111,6 +120,7 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte * @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor * @param CollectionProcessorInterface $collectionProcessor * @param NotificationStorage $notificationStorage + * @param DelegatedStorage|null $delegatedStorage * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -128,7 +138,8 @@ public function __construct( ImageProcessorInterface $imageProcessor, \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor, CollectionProcessorInterface $collectionProcessor, - NotificationStorage $notificationStorage + NotificationStorage $notificationStorage, + DelegatedStorage $delegatedStorage = null ) { $this->customerFactory = $customerFactory; $this->customerSecureFactory = $customerSecureFactory; @@ -145,6 +156,8 @@ public function __construct( $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor; $this->collectionProcessor = $collectionProcessor; $this->notificationStorage = $notificationStorage; + $this->delegatedStorage = $delegatedStorage + ?? ObjectManager::getInstance()->get(DelegatedStorage::class); } /** @@ -152,8 +165,10 @@ public function __construct( * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ - public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $passwordHash = null) + public function save(CustomerInterface $customer, $passwordHash = null) { + /** @var NewOperation|null $delegatedNewOperation */ + $delegatedNewOperation = !$customer->getId() ? $this->delegatedStorage->consumeNewOperation() : null; $prevCustomerData = null; $prevCustomerDataArr = null; if ($customer->getId()) { @@ -167,56 +182,49 @@ public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $pa CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, $prevCustomerData ); - $origAddresses = $customer->getAddresses(); $customer->setAddresses([]); - $customerData = $this->extensibleDataObjectConverter->toNestedArray( - $customer, - [], - \Magento\Customer\Api\Data\CustomerInterface::class - ); - + $customerData = $this->extensibleDataObjectConverter->toNestedArray($customer, [], CustomerInterface::class); $customer->setAddresses($origAddresses); + /** @var Customer $customerModel */ $customerModel = $this->customerFactory->create(['data' => $customerData]); + //Model's actual ID field maybe different than "id" so "id" field from $customerData may be ignored. + $customerModel->setId($customer->getId()); $storeId = $customerModel->getStoreId(); if ($storeId === null) { $customerModel->setStoreId($this->storeManager->getStore()->getId()); } - $customerModel->setId($customer->getId()); - // Need to use attribute set or future updates can cause data loss if (!$customerModel->getAttributeSetId()) { - $customerModel->setAttributeSetId( - \Magento\Customer\Api\CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER - ); + $customerModel->setAttributeSetId(CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER); } $this->populateCustomerWithSecureData($customerModel, $passwordHash); - // If customer email was changed, reset RpToken info - if ($prevCustomerData - && $prevCustomerData->getEmail() !== $customerModel->getEmail() - ) { + if ($prevCustomerData && $prevCustomerData->getEmail() !== $customerModel->getEmail()) { $customerModel->setRpToken(null); $customerModel->setRpTokenCreatedAt(null); } - if (!array_key_exists('default_billing', $customerArr) && - null !== $prevCustomerDataArr && - array_key_exists('default_billing', $prevCustomerDataArr) + if (!array_key_exists('default_billing', $customerArr) + && null !== $prevCustomerDataArr + && array_key_exists('default_billing', $prevCustomerDataArr) ) { $customerModel->setDefaultBilling($prevCustomerDataArr['default_billing']); } - - if (!array_key_exists('default_shipping', $customerArr) && - null !== $prevCustomerDataArr && - array_key_exists('default_shipping', $prevCustomerDataArr) + if (!array_key_exists('default_shipping', $customerArr) + && null !== $prevCustomerDataArr + && array_key_exists('default_shipping', $prevCustomerDataArr) ) { $customerModel->setDefaultShipping($prevCustomerDataArr['default_shipping']); } - $customerModel->save(); $this->customerRegistry->push($customerModel); $customerId = $customerModel->getId(); - + if (!$customer->getAddresses() + && $delegatedNewOperation + && $delegatedNewOperation->getCustomer()->getAddresses() + ) { + $customer->setAddresses($delegatedNewOperation->getCustomer()->getAddresses()); + } if ($customer->getAddresses() !== null) { if ($customer->getId()) { $existingAddresses = $this->getById($customer->getId())->getAddresses(); @@ -227,7 +235,6 @@ public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $pa } else { $existingAddressIds = []; } - $savedAddressIds = []; foreach ($customer->getAddresses() as $address) { $address->setCustomerId($customerId) @@ -237,7 +244,6 @@ public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $pa $savedAddressIds[] = $address->getId(); } } - $addressIdsToDelete = array_diff($existingAddressIds, $savedAddressIds); foreach ($addressIdsToDelete as $addressId) { $this->addressRepository->deleteById($addressId); @@ -247,8 +253,13 @@ public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $pa $savedCustomer = $this->get($customer->getEmail(), $customer->getWebsiteId()); $this->eventManager->dispatch( 'customer_save_after_data_object', - ['customer_data_object' => $savedCustomer, 'orig_customer_data_object' => $prevCustomerData] + [ + 'customer_data_object' => $savedCustomer, + 'orig_customer_data_object' => $prevCustomerData, + 'delegate_data' => $delegatedNewOperation ? $delegatedNewOperation->getAdditionalData() : [], + ] ); + return $savedCustomer; } @@ -310,7 +321,7 @@ public function getList(SearchCriteriaInterface $searchCriteria) $collection = $this->customerFactory->create()->getCollection(); $this->extensionAttributesJoinProcessor->process( $collection, - \Magento\Customer\Api\Data\CustomerInterface::class + CustomerInterface::class ); // This is needed to make sure all the attributes are properly loaded foreach ($this->customerMetadata->getAllAttributesMetadata() as $metadata) { @@ -342,7 +353,7 @@ public function getList(SearchCriteriaInterface $searchCriteria) /** * {@inheritdoc} */ - public function delete(\Magento\Customer\Api\Data\CustomerInterface $customer) + public function delete(CustomerInterface $customer) { return $this->deleteById($customer->getId()); } diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php index 06133dd89d754..bd1dc774b5319 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php @@ -419,7 +419,11 @@ public function testSave() ->method('dispatch') ->with( 'customer_save_after_data_object', - ['customer_data_object' => $this->customer, 'orig_customer_data_object' => $origCustomer] + [ + 'customer_data_object' => $this->customer, + 'orig_customer_data_object' => $origCustomer, + 'delegate_data' => [], + ] ); $this->model->save($this->customer); @@ -646,7 +650,11 @@ public function testSaveWithPasswordHash() ->method('dispatch') ->with( 'customer_save_after_data_object', - ['customer_data_object' => $this->customer, 'orig_customer_data_object' => $origCustomer] + [ + 'customer_data_object' => $this->customer, + 'orig_customer_data_object' => $origCustomer, + 'delegate_data' => [], + ] ); $this->model->save($this->customer, $passwordHash); diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index 43c2b9cf7bb80..0d99c1145e81b 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -433,4 +433,7 @@ + diff --git a/app/code/Magento/Deploy/App/Mode/ConfigProvider.php b/app/code/Magento/Deploy/App/Mode/ConfigProvider.php index 900908a1f158f..142e3fe819438 100644 --- a/app/code/Magento/Deploy/App/Mode/ConfigProvider.php +++ b/app/code/Magento/Deploy/App/Mode/ConfigProvider.php @@ -16,7 +16,7 @@ class ConfigProvider * [ * 'developer' => [ * 'production' => [ - * {{setting_path}} => ['value' => {{setting_value}}, 'lock' => {{lock_value}}] + * {{setting_path}} => {{setting_value}} * ] * ] * ] @@ -41,7 +41,7 @@ public function __construct(array $config = []) * need to turn off 'dev/debug/debug_logging' setting in this case method * will return array * [ - * {{setting_path}} => ['value' => {{setting_value}}, 'lock' => {{lock_value}}] + * {{setting_path}} => {{setting_value}} * ] * * @param string $currentMode diff --git a/app/code/Magento/Deploy/Model/Mode.php b/app/code/Magento/Deploy/Model/Mode.php index d4ae72d63bce7..fe24fb297e978 100644 --- a/app/code/Magento/Deploy/Model/Mode.php +++ b/app/code/Magento/Deploy/Model/Mode.php @@ -234,17 +234,17 @@ protected function setStoreMode($mode) private function saveAppConfigs($mode) { $configs = $this->configProvider->getConfigs($this->getMode(), $mode); - foreach ($configs as $path => $item) { - $this->emulatedAreaProcessor->process(function () use ($path, $item) { + foreach ($configs as $path => $value) { + $this->emulatedAreaProcessor->process(function () use ($path, $value) { $this->processorFacadeFactory->create()->processWithLockTarget( $path, - $item['value'], + $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, - $item['lock'] + true ); }); - $this->output->writeln('Config "' . $path . ' = ' . $item['value'] . '" has been saved.'); + $this->output->writeln('Config "' . $path . ' = ' . $value . '" has been saved.'); } } } diff --git a/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php b/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php index 50725a3382073..5cb8a8e47bc97 100644 --- a/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php +++ b/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php @@ -228,7 +228,7 @@ public function testEnableProductionModeMinimal() ->method('getConfigs') ->with('developer', 'production') ->willReturn([ - 'dev/debug/debug_logging' => ['value' => 0, 'lock' => false] + 'dev/debug/debug_logging' => 0, ]); $this->emulatedAreaProcessor->expects($this->once()) ->method('process') @@ -247,7 +247,7 @@ public function testEnableProductionModeMinimal() 0, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, - false + true ); $this->outputMock->expects($this->once()) ->method('writeln') diff --git a/app/code/Magento/Deploy/etc/di.xml b/app/code/Magento/Deploy/etc/di.xml index 9e936f70c9986..ce7c84c95538a 100644 --- a/app/code/Magento/Deploy/etc/di.xml +++ b/app/code/Magento/Deploy/etc/di.xml @@ -76,32 +76,7 @@ - - 0 - false - - - - - - - 1 - false - - - - - - - 0 - false - - - - - 1 - false - + 0 diff --git a/app/code/Magento/Developer/etc/adminhtml/system.xml b/app/code/Magento/Developer/etc/adminhtml/system.xml index 0166814d889c2..9663cff72bc9d 100644 --- a/app/code/Magento/Developer/etc/adminhtml/system.xml +++ b/app/code/Magento/Developer/etc/adminhtml/system.xml @@ -28,6 +28,7 @@ + Not available in production mode. Magento\Config\Model\Config\Source\Yesno diff --git a/app/code/Magento/ReleaseNotification/Ui/Renderer/NotificationRenderer.php b/app/code/Magento/ReleaseNotification/Ui/Renderer/NotificationRenderer.php index a43b33b5a8cdf..c4760bd9d28c3 100644 --- a/app/code/Magento/ReleaseNotification/Ui/Renderer/NotificationRenderer.php +++ b/app/code/Magento/ReleaseNotification/Ui/Renderer/NotificationRenderer.php @@ -174,7 +174,7 @@ private function buildFooter(array $footer) * correct HTML format. * * @param string $content - * @returns string + * @return string */ private function formatContentWithLinks($content) { diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index 41a55f4c25166..e1c9bf99f2675 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -6,9 +6,14 @@ namespace Magento\Rule\Model\Condition\Sql; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DB\Select; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Rule\Model\Condition\AbstractCondition; use Magento\Rule\Model\Condition\Combine; +use Magento\Eav\Api\AttributeRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Eav\Model\Entity\Collection\AbstractCollection; /** * Class SQL Builder @@ -41,12 +46,22 @@ class Builder */ protected $_expressionFactory; + /** + * @var AttributeRepositoryInterface + */ + private $attributeRepository; + /** * @param ExpressionFactory $expressionFactory + * @param AttributeRepositoryInterface|null $attributeRepository */ - public function __construct(ExpressionFactory $expressionFactory) - { + public function __construct( + ExpressionFactory $expressionFactory, + AttributeRepositoryInterface $attributeRepository = null + ) { $this->_expressionFactory = $expressionFactory; + $this->attributeRepository = $attributeRepository ?: + ObjectManager::getInstance()->get(AttributeRepositoryInterface::class); } /** @@ -88,14 +103,14 @@ protected function _getChildCombineTablesToJoin(Combine $combine, $tables = []) /** * Join tables from conditions combination to collection * - * @param \Magento\Eav\Model\Entity\Collection\AbstractCollection $collection + * @param AbstractCollection $collection * @param Combine $combine * @return $this */ protected function _joinTablesToCollection( - \Magento\Eav\Model\Entity\Collection\AbstractCollection $collection, + AbstractCollection $collection, Combine $combine - ) { + ): Builder { foreach ($this->_getCombineTablesToJoin($combine) as $alias => $joinTable) { /** @var $condition AbstractCondition */ $collection->getSelect()->joinLeft( @@ -104,6 +119,7 @@ protected function _joinTablesToCollection( isset($joinTable['columns']) ? $joinTable['columns'] : '*' ); } + return $this; } @@ -112,11 +128,15 @@ protected function _joinTablesToCollection( * * @param AbstractCondition $condition * @param string $value + * @param bool $isDefaultStoreUsed * @return string * @throws \Magento\Framework\Exception\LocalizedException */ - protected function _getMappedSqlCondition(AbstractCondition $condition, $value = '') - { + protected function _getMappedSqlCondition( + AbstractCondition $condition, + string $value = '', + bool $isDefaultStoreUsed = true + ): string { $argument = $condition->getMappedSqlField(); // If rule hasn't valid argument - create negative expression to prevent incorrect rule behavior. @@ -130,9 +150,16 @@ protected function _getMappedSqlCondition(AbstractCondition $condition, $value = throw new \Magento\Framework\Exception\LocalizedException(__('Unknown condition operator')); } + $defaultValue = 0; + // Check if attribute has a table with default value and add it to the query + if ($this->canAttributeHaveDefaultValue($condition->getAttribute(), $isDefaultStoreUsed)) { + $defaultField = 'at_' . $condition->getAttribute() . '_default.value'; + $defaultValue = $this->_connection->quoteIdentifier($defaultField); + } + $sql = str_replace( ':field', - $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), 0), + $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), $defaultValue), $this->_conditionOperatorMap[$conditionOperator] ); @@ -144,11 +171,15 @@ protected function _getMappedSqlCondition(AbstractCondition $condition, $value = /** * @param Combine $combine * @param string $value + * @param bool $isDefaultStoreUsed * @return string * @SuppressWarnings(PHPMD.NPathComplexity) */ - protected function _getMappedSqlCombination(Combine $combine, $value = '') - { + protected function _getMappedSqlCombination( + Combine $combine, + string $value = '', + bool $isDefaultStoreUsed = true + ): string { $out = (!empty($value) ? $value : ''); $value = ($combine->getValue() ? '' : ' NOT '); $getAggregator = $combine->getAggregator(); @@ -158,33 +189,68 @@ protected function _getMappedSqlCombination(Combine $combine, $value = '') $con = ($getAggregator == 'any' ? Select::SQL_OR : Select::SQL_AND); $con = (isset($conditions[$key+1]) ? $con : ''); if ($condition instanceof Combine) { - $out .= $this->_getMappedSqlCombination($condition, $value); + $out .= $this->_getMappedSqlCombination($condition, $value, $isDefaultStoreUsed); } else { - $out .= $this->_getMappedSqlCondition($condition, $value); + $out .= $this->_getMappedSqlCondition($condition, $value, $isDefaultStoreUsed); } $out .= $out ? (' ' . $con) : ''; } + return $this->_expressionFactory->create(['expression' => $out]); } /** * Attach conditions filter to collection * - * @param \Magento\Eav\Model\Entity\Collection\AbstractCollection $collection + * @param AbstractCollection $collection * @param Combine $combine - * * @return void */ public function attachConditionToCollection( - \Magento\Eav\Model\Entity\Collection\AbstractCollection $collection, + AbstractCollection $collection, Combine $combine - ) { + ): void { $this->_connection = $collection->getResource()->getConnection(); $this->_joinTablesToCollection($collection, $combine); - $whereExpression = (string)$this->_getMappedSqlCombination($combine); + $isDefaultStoreUsed = $this->checkIsDefaultStoreUsed($collection); + $whereExpression = (string)$this->_getMappedSqlCombination($combine, '', $isDefaultStoreUsed); if (!empty($whereExpression)) { // Select ::where method adds braces even on empty expression $collection->getSelect()->where($whereExpression); } } + + /** + * Check is default store used. + * + * @param AbstractCollection $collection + * @return bool + */ + private function checkIsDefaultStoreUsed(AbstractCollection $collection): bool + { + return (int)$collection->getStoreId() === (int)$collection->getDefaultStoreId(); + } + + /** + * Check if attribute can have default value. + * + * @param string $attributeCode + * @param bool $isDefaultStoreUsed + * @return bool + */ + private function canAttributeHaveDefaultValue(string $attributeCode, bool $isDefaultStoreUsed): bool + { + if ($isDefaultStoreUsed) { + return false; + } + + try { + $attribute = $this->attributeRepository->get(Product::ENTITY, $attributeCode); + } catch (NoSuchEntityException $e) { + // It's not exceptional case as we want to check if we have such attribute or not + return false; + } + + return !$attribute->isScopeGlobal(); + } } diff --git a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php index f53098c4bb97e..daf7b1462c722 100644 --- a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php +++ b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php @@ -35,7 +35,12 @@ public function testAttachConditionToCollection() { $collection = $this->createPartialMock( \Magento\Eav\Model\Entity\Collection\AbstractCollection::class, - ['getResource', 'getSelect'] + [ + 'getResource', + 'getSelect', + 'getStoreId', + 'getDefaultStoreId', + ] ); $combine = $this->createPartialMock(\Magento\Rule\Model\Condition\Combine::class, ['getConditions']); $resource = $this->createPartialMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, ['getConnection']); @@ -53,10 +58,15 @@ public function testAttachConditionToCollection() $collection->expects($this->once()) ->method('getResource') ->will($this->returnValue($resource)); - $collection->expects($this->any()) ->method('getSelect') ->will($this->returnValue($select)); + $collection->expects($this->once()) + ->method('getStoreId') + ->willReturn(1); + $collection->expects($this->once()) + ->method('getDefaultStoreId') + ->willReturn(1); $resource->expects($this->once()) ->method('getConnection') diff --git a/app/code/Magento/Sales/Api/OrderCustomerDelegateInterface.php b/app/code/Magento/Sales/Api/OrderCustomerDelegateInterface.php new file mode 100644 index 0000000000000..2902903b0b7d0 --- /dev/null +++ b/app/code/Magento/Sales/Api/OrderCustomerDelegateInterface.php @@ -0,0 +1,25 @@ +objectCopyService = $objectCopyService; $this->accountManagement = $accountManagement; @@ -74,9 +87,10 @@ public function __construct( $this->customerFactory = $customerFactory; $this->addressFactory = $addressFactory; $this->regionFactory = $regionFactory; - $this->quoteAddressFactory = $quoteAddressFactory ?: ObjectManager::getInstance()->get( - \Magento\Quote\Model\Quote\AddressFactory::class - ); + $this->quoteAddressFactory = $quoteAddressFactory + ?: ObjectManager::getInstance()->get(QuoteAddressFactory::class); + $this->customerExtractor = $orderCustomerExtractor + ?? ObjectManager::getInstance()->get(OrderCustomerExtractor::class); } /** @@ -86,50 +100,23 @@ public function create($orderId) { $order = $this->orderRepository->get($orderId); if ($order->getCustomerId()) { - throw new AlreadyExistsException(__("This order already has associated customer account")); - } - $customerData = $this->objectCopyService->copyFieldsetToTarget( - 'order_address', - 'to_customer', - $order->getBillingAddress(), - [] - ); - $addresses = $order->getAddresses(); - foreach ($addresses as $address) { - if (!$this->isNeededToSaveAddress($address->getData('quote_address_id'))) { - continue; - } - $addressData = $this->objectCopyService->copyFieldsetToTarget( - 'order_address', - 'to_customer_address', - $address, - [] + throw new AlreadyExistsException( + __('This order already has associated customer account') ); - /** @var \Magento\Customer\Api\Data\AddressInterface $customerAddress */ - $customerAddress = $this->addressFactory->create(['data' => $addressData]); - switch ($address->getAddressType()) { - case QuoteAddress::ADDRESS_TYPE_BILLING: - $customerAddress->setIsDefaultBilling(true); - break; - case QuoteAddress::ADDRESS_TYPE_SHIPPING: - $customerAddress->setIsDefaultShipping(true); - break; - } + } - if (is_string($address->getRegion())) { - /** @var \Magento\Customer\Api\Data\RegionInterface $region */ - $region = $this->regionFactory->create(); - $region->setRegion($address->getRegion()); - $region->setRegionCode($address->getRegionCode()); - $region->setRegionId($address->getRegionId()); - $customerAddress->setRegion($region); + $customer = $this->customerExtractor->extract($orderId); + /** @var AddressInterface[] $filteredAddresses */ + $filteredAddresses = []; + foreach ($customer->getAddresses() as $address) { + if ($this->needToSaveAddress($order, $address)) { + $filteredAddresses[] = $address; } - $customerData['addresses'][] = $customerAddress; } + $customer->setAddresses($filteredAddresses); - /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ - $customer = $this->customerFactory->create(['data' => $customerData]); $account = $this->accountManagement->createAccount($customer); + $order = $this->orderRepository->get($orderId); $order->setCustomerId($account->getId()); $order->setCustomerIsGuest(0); $this->orderRepository->save($order); @@ -138,21 +125,36 @@ public function create($orderId) } /** - * Check if we need to save address in address book. - * - * @param int $quoteAddressId + * @param OrderInterface $order + * @param AddressInterface $address * * @return bool */ - private function isNeededToSaveAddress($quoteAddressId) - { - $saveInAddressBook = true; + private function needToSaveAddress( + OrderInterface $order, + AddressInterface $address + ): bool { + /** @var OrderAddressInterface|null $orderAddress */ + $orderAddress = null; + if ($address->isDefaultBilling()) { + $orderAddress = $order->getBillingAddress(); + } elseif ($address->isDefaultShipping()) { + $orderAddress = $order->getShippingAddress(); + } + if ($orderAddress) { + $quoteAddressId = $orderAddress->getData('quote_address_id'); + if ($quoteAddressId) { + /** @var QuoteAddress $quote */ + $quote = $this->quoteAddressFactory->create() + ->load($quoteAddressId); + if ($quote && $quote->getId()) { + return (bool)(int)$quote->getData('save_in_address_book'); + } + } - $quoteAddress = $this->quoteAddressFactory->create()->load($quoteAddressId); - if ($quoteAddress && $quoteAddress->getId()) { - $saveInAddressBook = (int)$quoteAddress->getData('save_in_address_book'); + return true; } - return $saveInAddressBook; + return false; } } diff --git a/app/code/Magento/Sales/Model/Order/OrderCustomerDelegate.php b/app/code/Magento/Sales/Model/Order/OrderCustomerDelegate.php new file mode 100644 index 0000000000000..5d0cd4f37df5a --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/OrderCustomerDelegate.php @@ -0,0 +1,54 @@ +customerExtractor = $customerExtractor; + $this->delegateService = $delegateService; + } + + /** + * {@inheritdoc} + */ + public function delegateNew(int $orderId): Redirect + { + return $this->delegateService->createRedirectForNew( + $this->customerExtractor->extract($orderId), + ['__sales_assign_order_id' => $orderId] + ); + } +} diff --git a/app/code/Magento/Sales/Model/Order/OrderCustomerExtractor.php b/app/code/Magento/Sales/Model/Order/OrderCustomerExtractor.php new file mode 100644 index 0000000000000..2a93f389e569f --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/OrderCustomerExtractor.php @@ -0,0 +1,142 @@ +orderRepository = $orderRepository; + $this->customerRepository = $customerRepository; + $this->objectCopyService = $objectCopyService; + $this->addressFactory = $addressFactory; + $this->regionFactory = $regionFactory; + $this->customerFactory = $customerFactory; + $this->quoteAddressFactory = $quoteAddressFactory; + } + + /** + * @param int $orderId + * + * @return CustomerInterface + */ + public function extract(int $orderId): CustomerInterface + { + $order = $this->orderRepository->get($orderId); + + //Simply return customer from DB. + if ($order->getCustomerId()) { + return $this->customerRepository->getById($order->getCustomerId()); + } + + //Prepare customer data from order data if customer doesn't exist yet. + $customerData = $this->objectCopyService->copyFieldsetToTarget( + 'order_address', + 'to_customer', + $order->getBillingAddress(), + [] + ); + $addresses = $order->getAddresses(); + foreach ($addresses as $address) { + $addressData = $this->objectCopyService->copyFieldsetToTarget( + 'order_address', + 'to_customer_address', + $address, + [] + ); + /** @var AddressInterface $customerAddress */ + $customerAddress = $this->addressFactory->create(['data' => $addressData]); + switch ($address->getAddressType()) { + case QuoteAddress::ADDRESS_TYPE_BILLING: + $customerAddress->setIsDefaultBilling(true); + break; + case QuoteAddress::ADDRESS_TYPE_SHIPPING: + $customerAddress->setIsDefaultShipping(true); + break; + } + + if (is_string($address->getRegion())) { + /** @var RegionInterface $region */ + $region = $this->regionFactory->create(); + $region->setRegion($address->getRegion()); + $region->setRegionCode($address->getRegionCode()); + $region->setRegionId($address->getRegionId()); + $customerAddress->setRegion($region); + } + $customerData['addresses'][] = $customerAddress; + } + + return $this->customerFactory->create(['data' => $customerData]); + } +} diff --git a/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php b/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php new file mode 100644 index 0000000000000..cade86d18e935 --- /dev/null +++ b/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php @@ -0,0 +1,54 @@ +orderRepository = $orderRepository; + } + + /** + * {@inheritdoc} + */ + public function execute(Observer $observer) + { + $event = $observer->getEvent(); + /** @var CustomerInterface $customer */ + $customer = $event->getData('customer_data_object'); + /** @var array $delegateData */ + $delegateData = $event->getData('delegate_data'); + if (array_key_exists('__sales_assign_order_id', $delegateData)) { + $orderId = $delegateData['__sales_assign_order_id']; + $order = $this->orderRepository->get($orderId); + if (!$order->getCustomerId()) { + //if customer ID wasn't already assigned then assigning. + $order->setCustomerId($customer->getId()); + $order->setCustomerIsGuest(0); + $this->orderRepository->save($order); + } + } + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/CustomerManagementTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/CustomerManagementTest.php deleted file mode 100644 index 2794860793ed6..0000000000000 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/CustomerManagementTest.php +++ /dev/null @@ -1,185 +0,0 @@ -objectCopyService = $this->createMock(\Magento\Framework\DataObject\Copy::class); - $this->accountManagement = $this->createMock(\Magento\Customer\Api\AccountManagementInterface::class); - $this->customerFactory = $this->createPartialMock( - \Magento\Customer\Api\Data\CustomerInterfaceFactory::class, - ['create'] - ); - $this->addressFactory = $this->createPartialMock( - \Magento\Customer\Api\Data\AddressInterfaceFactory::class, - ['create'] - ); - $this->regionFactory = $this->createPartialMock( - \Magento\Customer\Api\Data\RegionInterfaceFactory::class, - ['create'] - ); - $this->orderRepository = $this->createMock(\Magento\Sales\Api\OrderRepositoryInterface::class); - $this->quoteAddressFactory = $this->createMock(\Magento\Quote\Model\Quote\AddressFactory::class); - - $this->service = new \Magento\Sales\Model\Order\CustomerManagement( - $this->objectCopyService, - $this->accountManagement, - $this->customerFactory, - $this->addressFactory, - $this->regionFactory, - $this->orderRepository, - $this->quoteAddressFactory - ); - } - - /** - * @expectedException \Magento\Framework\Exception\AlreadyExistsException - */ - public function testCreateThrowsExceptionIfCustomerAlreadyExists() - { - $orderMock = $this->createMock(\Magento\Sales\Api\Data\OrderInterface::class); - $orderMock->expects($this->once())->method('getCustomerId')->will($this->returnValue('customer_id')); - $this->orderRepository->expects($this->once())->method('get')->with(1)->will($this->returnValue($orderMock)); - $this->service->create(1); - } - - public function testCreateCreatesCustomerBasedonGuestOrder() - { - $orderMock = $this->createMock(\Magento\Sales\Model\Order::class); - $orderMock->expects($this->once())->method('getCustomerId')->will($this->returnValue(null)); - $orderMock->expects($this->any())->method('getBillingAddress')->will($this->returnValue('billing_address')); - - $orderBillingAddress = $this->createPartialMockForAbstractClass(OrderAddressInterface::class, ['getData']); - $orderBillingAddress->expects($this->once()) - ->method('getAddressType') - ->willReturn(Address::ADDRESS_TYPE_BILLING); - - $orderShippingAddress = $this->createPartialMockForAbstractClass(OrderAddressInterface::class, ['getData']); - $orderShippingAddress->expects($this->once()) - ->method('getAddressType') - ->willReturn(Address::ADDRESS_TYPE_SHIPPING); - - $orderMock->expects($this->any()) - ->method('getAddresses') - ->will($this->returnValue([$orderBillingAddress, $orderShippingAddress])); - - $billingQuoteAddress = $this->createMock(\Magento\Quote\Model\Quote\Address::class); - $billingQuoteAddress->expects($this->once())->method('load')->willReturn($billingQuoteAddress); - $billingQuoteAddress->expects($this->once())->method('getId')->willReturn(4); - $billingQuoteAddress->expects($this->once())->method('getData')->with('save_in_address_book')->willReturn(1); - - $shippingQuoteAddress = $this->createMock(\Magento\Quote\Model\Quote\Address::class); - $shippingQuoteAddress->expects($this->once())->method('load')->willReturn($shippingQuoteAddress); - $shippingQuoteAddress->expects($this->once())->method('getId')->willReturn(5); - $shippingQuoteAddress->expects($this->once())->method('getData')->with('save_in_address_book')->willReturn(1); - $this->quoteAddressFactory->expects($this->exactly(2))->method('create') - ->willReturnOnConsecutiveCalls($billingQuoteAddress, $shippingQuoteAddress); - $this->orderRepository->expects($this->once())->method('get')->with(1)->will($this->returnValue($orderMock)); - $this->objectCopyService->expects($this->any())->method('copyFieldsetToTarget')->will($this->returnValueMap( - [ - ['order_address', 'to_customer', 'billing_address', [], 'global', ['customer_data' => []]], - ['order_address', 'to_customer_address', $orderBillingAddress, [], 'global', 'address_data'], - ['order_address', 'to_customer_address', $orderShippingAddress, [], 'global', 'address_data'], - ] - )); - - $addressMock = $this->createMock(\Magento\Customer\Api\Data\AddressInterface::class); - $addressMock->expects($this->any()) - ->method('setIsDefaultBilling') - ->with(true) - ->willReturnSelf(); - $addressMock->expects($this->any()) - ->method('setIsDefaultShipping') - ->with(true) - ->willReturnSelf(); - - $this->addressFactory->expects($this->any())->method('create')->with(['data' => 'address_data'])->will( - $this->returnValue($addressMock) - ); - $customerMock = $this->createMock(\Magento\Customer\Api\Data\CustomerInterface::class); - $customerMock->expects($this->any())->method('getId')->will($this->returnValue('customer_id')); - $this->customerFactory->expects($this->once())->method('create')->with( - ['data' => ['customer_data' => [], 'addresses' => [$addressMock, $addressMock]]] - )->will($this->returnValue($customerMock)); - $this->accountManagement->expects($this->once())->method('createAccount')->with($customerMock)->will( - $this->returnValue($customerMock) - ); - $orderMock->expects($this->once())->method('setCustomerId')->with('customer_id'); - $this->orderRepository->expects($this->once())->method('save')->with($orderMock); - $this->assertEquals($customerMock, $this->service->create(1)); - } - - /** - * Get mock for abstract class with methods. - * - * @param string $className - * @param array $methods - * - * @return \PHPUnit_Framework_MockObject_MockObject - */ - private function createPartialMockForAbstractClass($className, $methods = []) - { - return $this->getMockForAbstractClass( - $className, - [], - '', - true, - true, - true, - $methods - ); - } -} diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml index cbc06856f5283..ce2948983edbe 100644 --- a/app/code/Magento/Sales/etc/di.xml +++ b/app/code/Magento/Sales/etc/di.xml @@ -991,4 +991,7 @@ + diff --git a/app/code/Magento/Sales/etc/events.xml b/app/code/Magento/Sales/etc/events.xml index 9ec983acab5bd..b3a7a4ab99577 100644 --- a/app/code/Magento/Sales/etc/events.xml +++ b/app/code/Magento/Sales/etc/events.xml @@ -51,4 +51,9 @@ + + + diff --git a/app/code/Magento/Swatches/Helper/Data.php b/app/code/Magento/Swatches/Helper/Data.php index 05daf3ddf584a..38879178235c0 100644 --- a/app/code/Magento/Swatches/Helper/Data.php +++ b/app/code/Magento/Swatches/Helper/Data.php @@ -158,6 +158,28 @@ public function assembleAdditionalDataEavAttribute(Attribute $attribute) return $this; } + /** + * Check is media attribute available + * + * @param ModelProduct $product + * @param string $attributeCode + * @return bool + */ + private function isMediaAvailable(ModelProduct $product, string $attributeCode): bool + { + $isAvailable = false; + + $mediaGallery = $product->getMediaGalleryEntries(); + foreach ($mediaGallery as $mediaEntry) { + if (in_array($attributeCode, $mediaEntry->getTypes(), true)) { + $isAvailable = !$mediaEntry->isDisabled(); + break; + } + } + + return $isAvailable; + } + /** * @param string $attributeCode swatch_image|image * @param ModelProduct $configurableProduct @@ -170,8 +192,8 @@ private function loadFirstVariation($attributeCode, ModelProduct $configurablePr $usedProducts = $configurableProduct->getTypeInstance()->getUsedProducts($configurableProduct); foreach ($usedProducts as $simpleProduct) { - if (!in_array($simpleProduct->getData($attributeCode), [null, self::EMPTY_IMAGE_VALUE], true) - && !array_diff_assoc($requiredAttributes, $simpleProduct->getData()) + if (!array_diff_assoc($requiredAttributes, $simpleProduct->getData()) + && $this->isMediaAvailable($simpleProduct, $attributeCode) ) { return $simpleProduct; } @@ -290,47 +312,32 @@ private function addFilterByParent(ProductCollection $productCollection, $parent */ public function getProductMediaGallery(ModelProduct $product) { - if (!in_array($product->getData('image'), [null, self::EMPTY_IMAGE_VALUE], true)) { - $baseImage = $product->getData('image'); - } else { - $productMediaAttributes = array_filter($product->getMediaAttributeValues(), function ($value) { - return $value !== self::EMPTY_IMAGE_VALUE && $value !== null; - }); - foreach ($productMediaAttributes as $attributeCode => $value) { - if ($attributeCode !== 'swatch_image') { - $baseImage = (string)$value; - break; - } + $baseImage = null; + $gallery = []; + + $mediaGallery = $product->getMediaGalleryEntries(); + foreach ($mediaGallery as $mediaEntry) { + if ($mediaEntry->isDisabled()) { + continue; + } + + if (in_array('image', $mediaEntry->getTypes(), true) || !$baseImage) { + $baseImage = $mediaEntry->getFile(); } + + $gallery[$mediaEntry->getId()] = $this->getAllSizeImages($mediaEntry->getFile()); } - if (empty($baseImage)) { + if (!$baseImage) { return []; } $resultGallery = $this->getAllSizeImages($baseImage); - $resultGallery['gallery'] = $this->getGalleryImages($product); + $resultGallery['gallery'] = $gallery; return $resultGallery; } - /** - * @param ModelProduct $product - * @return array - */ - private function getGalleryImages(ModelProduct $product) - { - //TODO: remove after fix MAGETWO-48040 - $product = $this->productRepository->getById($product->getId()); - - $result = []; - $mediaGallery = $product->getMediaGalleryImages(); - foreach ($mediaGallery as $media) { - $result[$media->getData('value_id')] = $this->getAllSizeImages($media->getData('file')); - } - return $result; - } - /** * @param string $imageFile * @return array @@ -497,9 +504,7 @@ private function addFallbackOptions(array $fallbackValues, array $swatches) */ public function isProductHasSwatch(Product $product) { - $swatchAttributes = $this->getSwatchAttributes($product); - - return count($swatchAttributes) > 0; + return !empty($this->getSwatchAttributes($product)); } /** diff --git a/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php b/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php index 3029094c9ef4a..96e84dc6eecd0 100644 --- a/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php +++ b/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php @@ -3,13 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Swatches\Test\Unit\Helper; +use Magento\Catalog\Model\Product\Image\UrlBuilder; use Magento\Catalog\Model\ResourceModel\Eav\Attribute; use Magento\Framework\EntityManager\MetadataPool; use Magento\Swatches\Model\ResourceModel\Swatch\Collection; use Magento\Swatches\Model\SwatchAttributesProvider; -use Magento\Swatches\Model\SwatchAttributeType; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -61,9 +62,9 @@ class DataTest extends \PHPUnit\Framework\TestCase private $swatchAttributesProvider; /** - * @var SwatchAttributeType|\PHPUnit_Framework_MockObject_MockObject + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\Product\Image\UrlBuilder */ - private $swatchTypeCheckerMock; + private $imageUrlBuilderMock; protected function setUp() { @@ -122,9 +123,9 @@ protected function setUp() $this->swatchAttributesProvider = $this->getMockBuilder(SwatchAttributesProvider::class) ->disableOriginalConstructor() ->getMock(); - $this->swatchTypeCheckerMock = $this->getMockBuilder(SwatchAttributeType::class) + $this->imageUrlBuilderMock = $this->getMockBuilder(\Magento\Catalog\Model\Product\Image\UrlBuilder::class) ->disableOriginalConstructor() - ->setMethods(['isVisualSwatch', 'isTextSwatch', 'isSwatchAttribute']) + ->setMethods(['getUrl']) ->getMock(); $this->swatchHelperObject = $this->objectManager->getObject( @@ -135,10 +136,9 @@ protected function setUp() 'productRepository' => $this->productRepoMock, 'storeManager' => $this->storeManagerMock, 'swatchCollectionFactory' => $this->swatchCollectionFactoryMock, - 'imageHelper' => $this->imageHelperMock, + 'imageUrlBuilder' => $this->imageUrlBuilderMock, 'serializer' => $serializer, 'swatchAttributesProvider' => $this->swatchAttributesProvider, - 'swatchTypeChecker' => $this->swatchTypeCheckerMock, ] ); $this->objectManager->setBackwardCompatibleProperty( @@ -232,7 +232,7 @@ public function dataForAssembleEavAttribute() public function testLoadFirstVariationWithSwatchImage($imageTypes, $expected, $requiredAttributes) { $this->getSwatchAttributes($this->productMock); - $this->getUsedProducts($imageTypes + $requiredAttributes); + $this->getUsedProducts($imageTypes + $requiredAttributes, $imageTypes); $result = $this->swatchHelperObject->loadFirstVariationWithSwatchImage($this->productMock, $requiredAttributes); @@ -295,7 +295,7 @@ public function testLoadVariationByFallback($product) public function testLoadFirstVariationWithImage($imageTypes, $expected, $requiredAttributes) { $this->getSwatchAttributes($this->productMock); - $this->getUsedProducts($imageTypes + $requiredAttributes); + $this->getUsedProducts($imageTypes + $requiredAttributes, $imageTypes); $result = $this->swatchHelperObject->loadFirstVariationWithImage($this->productMock, $requiredAttributes); @@ -333,23 +333,13 @@ public function dataForVariationWithImage() public function testLoadFirstVariationWithImageNoProduct() { - $this->swatchAttributesProvider - ->method('provide') - ->with($this->productMock) - ->willReturn([]); $result = $this->swatchHelperObject->loadVariationByFallback($this->productMock, ['color' => 31]); - $this->assertFalse($result); } public function testLoadVariationByFallbackWithoutProduct() { - $this->swatchAttributesProvider - ->method('provide') - ->with($this->productMock) - ->willReturn([]); $result = $this->swatchHelperObject->loadFirstVariationWithImage($this->productMock, ['color' => 31]); - $this->assertFalse($result); } @@ -358,44 +348,50 @@ public function testLoadVariationByFallbackWithoutProduct() */ public function testGetProductMediaGallery($mediaGallery, $image) { - $this->productMock->expects($this->once())->method('getMediaAttributeValues')->willReturn($mediaGallery); - $this->productMock->expects($this->any())->method('getId')->willReturn(95); - - $this->imageHelperMock->expects($this->any()) - ->method('init') - ->willReturnMap([ - [$this->productMock, 'product_page_image_large', [], $this->imageHelperMock], - [$this->productMock, 'product_page_image_medium', [], $this->imageHelperMock], - [$this->productMock, 'product_page_image_small', [], $this->imageHelperMock], - ]); - - $this->imageHelperMock->expects($this->any()) - ->method('setImageFile') - ->with($image) - ->willReturnSelf(); - $this->imageHelperMock->expects($this->any()) - ->method('getUrl') - ->willReturn('http://full_path_to_image/magento1.png'); - - $this->productRepoMock->expects($this->any()) - ->method('getById') - ->with(95) - ->willReturn($this->productMock); - - $mediaObject = $this->createMock(\Magento\Framework\DataObject::class); - $iterator = new \ArrayIterator([$mediaObject]); - $mediaCollectionMock = $this->createMock(\Magento\Framework\Data\Collection::class); - $mediaCollectionMock->expects($this->any())->method('getIterator')->willReturn($iterator); - $mediaObject->method('getData')->withConsecutive( - ['value_id'], - ['file'] - )->willReturnOnConsecutiveCalls( - 0, - $image - ); - $this->productMock->method('getMediaGalleryImages')->willReturn($mediaCollectionMock); + $mediaGalleryEntries = []; + $id = 0; + $mediaUrls = []; + foreach ($mediaGallery as $mediaType => $mediaFile) { + $mediaGalleryEntryMock = $this->getMockBuilder( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + )->getMock(); + $mediaGalleryEntryMock->expects($this->atLeastOnce()) + ->method('isDisabled') + ->willReturn(false); + $mediaGalleryEntryMock->expects($this->atLeastOnce()) + ->method('getTypes') + ->willReturn([$mediaType]); + $mediaGalleryEntryMock->expects($this->atLeastOnce()) + ->method('getFile') + ->willReturn($mediaFile); + $mediaGalleryEntryMock->expects($this->atLeastOnce()) + ->method('getId') + ->willReturn(++$id); + + $mediaGalleryEntries[] = $mediaGalleryEntryMock; + $mediaUrls[] = [$mediaFile, 'product_swatch_image_large', 'http://full_path_to_image' . $mediaFile]; + $mediaUrls[] = [$mediaFile, 'product_swatch_image_medium' ,'http://full_path_to_image' . $mediaFile]; + $mediaUrls[] = [$mediaFile, 'product_swatch_image_small','http://full_path_to_image' . $mediaFile]; + } + + $this->productMock->expects($this->once()) + ->method('getMediaGalleryEntries') + ->willReturn($mediaGalleryEntries); + + if ($mediaGallery) { + $this->imageUrlBuilderMock->expects($this->any()) + ->method('getUrl') + ->willReturnMap($mediaUrls); + } - $this->swatchHelperObject->getProductMediaGallery($this->productMock); + $productMediaGallery = $this->swatchHelperObject->getProductMediaGallery($this->productMock); + if ($mediaGallery) { + $this->assertContains($image, $productMediaGallery['large']); + $this->assertContains($image, $productMediaGallery['medium']); + $this->assertContains($image, $productMediaGallery['small']); + } else { + $this->assertEmpty($productMediaGallery); + } } public function dataForMediaGallery() @@ -408,7 +404,7 @@ public function dataForMediaGallery() 'thumbnail' => '/m/a/magento3.png', 'swatch_image' => '/m/a/magento4.png', ], - '/m/a/magento1.png' + '/m/a/magento1.png', ], [ [ @@ -416,7 +412,7 @@ public function dataForMediaGallery() 'thumbnail' => '/m/a/magento5.png', 'swatch_image' => '/m/a/magento6.png', ], - '/m/a/magento4.png' + '/m/a/magento4.png', ], [ [], @@ -435,22 +431,45 @@ protected function getSwatchAttributes() ->willReturn($returnFromProvideMethod); } - protected function getUsedProducts(array $attributes) + protected function getUsedProducts(array $attributes, array $imageTypes) { $this->productMock ->expects($this->atLeastOnce()) ->method('getTypeInstance') ->willReturn($this->configurableMock); - $product1 = $this->createPartialMock(\Magento\Catalog\Model\Product::class, ['hasData']); - $product1->setData($attributes); - - $product2 = $this->createPartialMock(\Magento\Catalog\Model\Product::class, ['hasData']); - $product2->setData($attributes); - - $simpleProducts = [$product2, $product1]; + $simpleProducts = []; + for ($i = 0; $i < 2; $i++) { + $simpleProduct = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->setMethods(['hasData', 'getMediaGalleryEntries']) + ->getMock(); + $simpleProduct->setData($attributes); + + $mediaGalleryEntries = []; + foreach (array_keys($imageTypes) as $mediaType) { + $mediaGalleryEntryMock = $this->getMockBuilder( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + )->getMock(); + $mediaGalleryEntryMock->expects($this->any()) + ->method('isDisabled') + ->willReturn(false); + $mediaGalleryEntryMock->expects($this->any()) + ->method('getTypes') + ->willReturn([$mediaType]); + + $mediaGalleryEntries[] = $mediaGalleryEntryMock; + } + $simpleProduct->expects($this->any()) + ->method('getMediaGalleryEntries') + ->willReturn($mediaGalleryEntries); + + $simpleProducts[] = $simpleProduct; + } - $this->configurableMock->expects($this->once())->method('getUsedProducts')->with($this->productMock) + $this->configurableMock->expects($this->once()) + ->method('getUsedProducts') + ->with($this->productMock) ->willReturn($simpleProducts); } @@ -761,79 +780,4 @@ public function testIsProductHasSwatch() $result = $this->swatchHelperObject->isProductHasSwatch($this->productMock); $this->assertEquals(true, $result); } - - /** - * @param bool $boolResult - * @return void - * @dataProvider dataIsSwatch - */ - public function testIsVisualSwatch(bool $boolResult) : void - { - $this->swatchTypeCheckerMock - ->expects($this->once()) - ->method('isVisualSwatch') - ->with($this->attributeMock) - ->willReturn($boolResult); - $result = $this->swatchHelperObject->isVisualSwatch($this->attributeMock); - - if ($boolResult) { - $this->assertTrue($result); - } else { - $this->assertFalse($result); - } - } - - /** - * @return array - */ - public function dataIsSwatch() : array - { - return [ - [true], - [false], - ]; - } - - /** - * @param bool $boolResult - * @return void - * @dataProvider dataIsSwatch - */ - public function testIsTextSwatch(bool $boolResult) : void - { - $this->swatchTypeCheckerMock - ->expects($this->once()) - ->method('isTextSwatch') - ->with($this->attributeMock) - ->willReturn($boolResult); - - $result = $this->swatchHelperObject->isTextSwatch($this->attributeMock); - - if ($boolResult) { - $this->assertTrue($result); - } else { - $this->assertFalse($result); - } - } - - /** - * @param bool $boolResult - * @return void - * @dataProvider dataIsSwatch - */ - public function testIsSwatchAttribute(bool $boolResult) : void - { - $this->swatchTypeCheckerMock - ->expects($this->once()) - ->method('isSwatchAttribute') - ->with($this->attributeMock) - ->willReturn($boolResult); - - $result = $this->swatchHelperObject->isSwatchAttribute($this->attributeMock); - if ($boolResult) { - $this->assertTrue($result); - } else { - $this->assertFalse($result); - } - } } diff --git a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js index 680b6a2b1e54e..7537107560cb4 100644 --- a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js +++ b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js @@ -721,6 +721,8 @@ define([ * @param {Number} page - current page */ changePage: function (page) { + this.clear(); + if (page === 1 && !this.recordData().length) { return false; } @@ -762,7 +764,6 @@ define([ * Change page to next */ nextPage: function () { - this.clear(); this.currentPage(this.currentPage() + 1); }, @@ -770,7 +771,6 @@ define([ * Change page to previous */ previousPage: function () { - this.clear(); this.currentPage(this.currentPage() - 1); }, diff --git a/app/code/Magento/Ui/view/base/web/js/grid/filters/range.js b/app/code/Magento/Ui/view/base/web/js/grid/filters/range.js index 438d6ccd58a55..ccfba8e98b6f4 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/filters/range.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/filters/range.js @@ -27,7 +27,8 @@ define([ }, date: { component: 'Magento_Ui/js/form/element/date', - dateFormat: 'MM/dd/YYYY' + dateFormat: 'MM/dd/YYYY', + shiftedValue: 'filter' }, text: { component: 'Magento_Ui/js/form/element/abstract' diff --git a/bin/UpgradeScripts/2.3_upgrade_additions.php b/bin/UpgradeScripts/pre_composer_update_2.3.php similarity index 100% rename from bin/UpgradeScripts/2.3_upgrade_additions.php rename to bin/UpgradeScripts/pre_composer_update_2.3.php diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/AdminAddDefaultImageBundleProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/AdminAddDefaultImageBundleProductTest.xml new file mode 100644 index 0000000000000..064c57958f37b --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/AdminAddDefaultImageBundleProductTest.xml @@ -0,0 +1,86 @@ + + + + + + + + + + <description value="Admin should be able to add default images for a Bundle Product"/> + <severity value="MAJOR"/> + <testCaseId value="MC-115"/> + <group value="Bundle"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"/> + </before> + <after> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + </after> + + <!-- Create a bundle product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="visitAdminProductPageBundle"/> + <waitForPageLoad stepKey="waitForProductPageLoadBundle"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateBundleProduct"> + <argument name="product" value="BundleProduct"/> + </actionGroup> + + <actionGroup ref="fillProductNameAndSkuInProductForm" stepKey="fillBundleProductNameAndSku"> + <argument name="product" value="BundleProduct"/> + </actionGroup> + + <!-- Add two bundle items --> + <conditionalClick selector="{{AdminProductFormBundleSection.bundleItemsToggle}}" dependentSelector="{{AdminProductFormBundleSection.bundleItemsToggle}}" visible="false" stepKey="conditionallyOpenSectionBundleItems"/> + <click selector="{{AdminProductFormBundleSection.addOption}}" stepKey="clickAddOption3"/> + <waitForElementVisible selector="{{AdminProductFormBundleSection.bundleOptionXTitle('0')}}" stepKey="waitForBundleOptions"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXTitle('0')}}" userInput="{{BundleProduct.optionTitle1}}" stepKey="fillOptionTitle"/> + <selectOption selector="{{AdminProductFormBundleSection.bundleOptionXInputType('0')}}" userInput="{{BundleProduct.optionInputType1}}" stepKey="selectInputType"/> + <waitForElementVisible selector="{{AdminProductFormBundleSection.addProductsToOption}}" stepKey="waitForAddProductsToBundle"/> + <click selector="{{AdminProductFormBundleSection.addProductsToOption}}" stepKey="clickAddProductsToOption"/> + <waitForPageLoad stepKey="waitForPageLoadAfterBundleProducts"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterBundleProductOptions"> + <argument name="product" value="$$simpleProduct1$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToOptionPanel.firstCheckbox}}" stepKey="selectFirstGridRow"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterBundleProductOptions2"> + <argument name="product" value="$$simpleProduct2$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToOptionPanel.firstCheckbox}}" stepKey="selectFirstGridRow2"/> + <click selector="{{AdminAddProductsToOptionPanel.addSelectedProducts}}" stepKey="clickAddSelectedBundleProducts"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '0')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillProductDefaultQty1"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '1')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillProductDefaultQty2"/> + + <!-- Add image to product --> + <actionGroup ref="addProductImage" stepKey="addImageForProduct"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + + <!--Save product--> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + + <!-- Assert product image in admin product form --> + <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> + + <!-- Assert product in storefront product page --> + <actionGroup ref="AssertProductNameAndSkuInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> + <argument name="product" value="BundleProduct"/> + </actionGroup> + + <!-- Assert product image in storefront product page --> + <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> + <argument name="product" value="BundleProduct"/> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/AdminAddRemoveProductImageBundleProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/AdminRemoveDefaultImageBundleProductTest.xml similarity index 77% rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/AdminAddRemoveProductImageBundleProductTest.xml rename to dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/AdminRemoveDefaultImageBundleProductTest.xml index d39b633bedcba..3dec79cf1b054 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/AdminAddRemoveProductImageBundleProductTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/AdminRemoveDefaultImageBundleProductTest.xml @@ -8,14 +8,14 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AdminAddRemoveProductImageBundleProductTest"> + <test name="AdminRemoveDefaultImageBundleProductTest"> <annotations> <features value="Bundle"/> - <stories value="Bundle Product Add/Remove Images"/> - <title value="Admin should be able to add/remove images for a Bundle Product"/> - <description value="Admin should be able to add/remove images for a Bundle Product"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to remove default images from a Bundle Product"/> + <description value="Admin should be able to remove default images from a Bundle Product"/> <severity value="MAJOR"/> - <testCaseId value="MC-115"/> + <testCaseId value="MC-200"/> <group value="Bundle"/> </annotations> <before> @@ -69,27 +69,7 @@ <!--Save product--> <actionGroup ref="saveProductForm" stepKey="saveProduct"/> - <!-- Assert product image in admin product form --> - <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> - - <!-- Assert product in storefront product page --> - <actionGroup ref="AssertProductNameAndSkuInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> - <argument name="product" value="BundleProduct"/> - </actionGroup> - - <!-- Assert product image in storefront product page --> - <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> - <argument name="product" value="BundleProduct"/> - <argument name="image" value="MagentoLogo"/> - </actionGroup> - <!-- Remove image from product --> - <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageRemove"/> - <waitForPageLoad stepKey="waitForProductIndexPageLoad2"/> - <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku"> - <argument name="product" value="BundleProduct"/> - </actionGroup> - <actionGroup ref="openProducForEditByClickingRowXColumnYInProductGrid" stepKey="openProducForEditByClickingRow1Column2InProductGrid"/> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductGridActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductGridActionGroup.xml index 9bfbab2d5d872..6398010f06687 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductGridActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductGridActionGroup.xml @@ -53,6 +53,15 @@ <waitForElementNotVisible selector="{{AdminProductGridSection.loadingMask}}" stepKey="waitForFilteredGridLoad" time="30"/> </actionGroup> + <!--Filter the product grid by new from date filter--> + <actionGroup name="filterProductGridBySetNewFromDate"> + <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> + <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="openProductFilters"/> + <fillField selector="{{AdminProductGridFilterSection.newFromDateFilter}}" userInput="05/16/2018" stepKey="fillSetAsNewProductFilter"/> + <click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="clickApplyFilters"/> + <waitForElementNotVisible selector="{{AdminProductGridSection.loadingMask}}" stepKey="waitForFilteredGridLoad" time="30"/> + </actionGroup> + <!--Filter the product grid by a price range--> <actionGroup name="filterProductGridByPriceRange"> <arguments> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CustomAttributeData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CustomAttributeData.xml index b143c3932f936..c0f2e391a4e2b 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CustomAttributeData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CustomAttributeData.xml @@ -31,4 +31,8 @@ <data key="attribute_code">short_description</data> <data key="value" unique="suffix">API Product Short Description</data> </entity> + <entity name="ApiProductNewsFromDate" type="custom_attribute"> + <data key="attribute_code">news_from_date</data> + <data key="value">2018-05-17 00:00:00</data> + </entity> </entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductData.xml index 2a8f57708c33b..34110d0417661 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductData.xml @@ -253,4 +253,32 @@ <requiredEntity type="product_option">ProductOptionDateTime</requiredEntity> <requiredEntity type="product_option">ProductOptionTime</requiredEntity> </entity> + <entity name="ApiVirtualProductWithDescription" type="product"> + <data key="sku" unique="suffix">api-virtual-product</data> + <data key="type_id">virtual</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">Api Virtual Product</data> + <data key="price">123.00</data> + <data key="urlKey" unique="suffix">api-virtual-product</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">ApiProductDescription</requiredEntity> + <requiredEntity type="custom_attribute_array">ApiProductShortDescription</requiredEntity> + </entity> + <entity name="SimpleProductWithNewFromDate" type="product"> + <data key="sku" unique="suffix">SimpleProduct</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="name" unique="suffix">SimpleProduct</data> + <data key="price">125.00</data> + <data key="visibility">4</data> + <data key="status">1</data> + <data key="quantity">1000</data> + <data key="urlKey" unique="suffix">simpleproduct</data> + <data key="weight">1</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">ApiProductNewsFromDate</requiredEntity> + </entity> </entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductAttributeGridSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductAttributeGridSection.xml index 97e8a913e6010..f1347643cbd9d 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductAttributeGridSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductAttributeGridSection.xml @@ -11,5 +11,9 @@ <section name="AdminProductAttributeGridSection"> <element name="AttributeCode" type="text" selector="//td[contains(text(),'{{var1}}')]" parameterized="true"/> <element name="createNewAttributeBtn" type="button" selector="button[data-index='add_new_attribute_button']"/> + <element name="GridFilterFrontEndLabel" type="input" selector="#attributeGrid_filter_frontend_label"/> + <element name="Search" type="button" selector="button[data-action=grid-filter-apply]" timeout="30"/> + <element name="ResetFilter" type="button" selector="button[data-action='grid-filter-reset']" timeout="30"/> + <element name="FirstRow" type="button" selector="//*[@id='attributeGrid_table']/tbody/tr[1]"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormActionSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormActionSection.xml index 16e060557ab09..e55a45d590910 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormActionSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormActionSection.xml @@ -11,8 +11,9 @@ <section name="AdminProductFormActionSection"> <element name="backButton" type="button" selector="#back" timeout="30"/> <element name="saveButton" type="button" selector="#save-button" timeout="30"/> - <element name="saveArrow" type="button" selector="button[data-ui-id='save-button-dropdown']" timeout="10"/> - <element name="saveAndClose" type="button" selector="span[title='Save & Close']" timeout="30"/> + <element name="saveArrow" type="button" selector="button[data-ui-id='save-button-dropdown']" timeout="30"/> + <!--<element name="saveAndClose" type="button" selector="span[title='Save & Close']" timeout="30"/>--> + <element name="saveAndClose" type="button" selector="span[id='save_and_close']" timeout="30"/> <element name="changeStoreButton" type="button" selector="#store-change-button" timeout="10"/> <element name="selectStoreView" type="button" selector="//ul[@data-role='stores-list']/li/a[normalize-space(.)='{{var1}}']" timeout="10" parameterized="true"/> </section> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridFilterSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridFilterSection.xml index 3436bbf0c08d2..b0b8d90c8625e 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridFilterSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridFilterSection.xml @@ -28,6 +28,7 @@ <element name="priceFilterTo" type="input" selector="input.admin__control-text[name='price[to]']"/> <element name="typeFilter" type="select" selector="select.admin__control-select[name='type_id']"/> <element name="statusFilter" type="select" selector="select.admin__control-select[name='status']"/> + <element name="newFromDateFilter" type="input" selector="input.admin__control-text[name='news_from_date[from]']"/> <element name="keywordSearch" type="input" selector="input#fulltext"/> <element name="keywordSearchButton" type="button" selector=".data-grid-search-control-wrap button.action-submit" timeout="30"/> </section> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductInfoMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductInfoMainSection.xml index bdcbb509738a4..5abc388a7d65d 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductInfoMainSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductInfoMainSection.xml @@ -12,6 +12,7 @@ <element name="stock" type="input" selector=".stock.available"/> <element name="productName" type="text" selector=".base"/> <element name="productSku" type="text" selector=".product.attribute.sku>.value"/> + <element name="productPriceLabel" type="text" selector=".price-label"/> <element name="productPrice" type="text" selector="div.price-box.price-final_price"/> <element name="specialPrice" type="text" selector=".special-price"/> <element name="oldPrice" type="text" selector=".old-price"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddDefaultImageSimpleProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddDefaultImageSimpleProductTest.xml new file mode 100644 index 0000000000000..3b3693d0ff8a6 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddDefaultImageSimpleProductTest.xml @@ -0,0 +1,59 @@ +<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminAddDefaultImageSimpleProductTest"> + <annotations> + <features value="Catalog"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to add default image for a Simple Product"/> + <description value="Admin should be able to add default images for a Simple Product"/> + <severity value="MAJOR"/> + <testCaseId value="MC-113"/> + <group value="Catalog"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + </after> + + <!--Create product--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPage"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateSimpleProduct"> + <argument name="product" value="SimpleProduct3"/> + </actionGroup> + <actionGroup ref="fillMainProductFormNoWeight" stepKey="fillSimpleProductMain"> + <argument name="product" value="SimpleProduct3"/> + </actionGroup> + + <!-- Add image to product --> + <actionGroup ref="addProductImage" stepKey="addImageForProductSimple"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveSimpleProduct"/> + + <!-- Assert product image in admin product form --> + <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> + + <!-- Assert product in storefront product page --> + <actionGroup ref="AssertProductInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> + <argument name="product" value="SimpleProduct3"/> + </actionGroup> + + <!-- Assert product image in storefront product page --> + <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> + <argument name="product" value="SimpleProduct3"/> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddDefaultImageVirtualProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddDefaultImageVirtualProductTest.xml new file mode 100644 index 0000000000000..292ba20f48bd3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddDefaultImageVirtualProductTest.xml @@ -0,0 +1,59 @@ +<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminAddRemoveProductImageVirtualProductTest"> + <annotations> + <features value="Catalog"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to add default images for a Virtual Product"/> + <description value="Admin should be able to add default images for a Virtual Product"/> + <severity value="MAJOR"/> + <testCaseId value="MC-103"/> + <group value="Catalog"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + </after> + + <!--Create product--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPage"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProduct"> + <argument name="product" value="defaultVirtualProduct"/> + </actionGroup> + <actionGroup ref="fillMainProductFormNoWeight" stepKey="fillProductMain"> + <argument name="product" value="defaultVirtualProduct"/> + </actionGroup> + + <!-- Add image to product --> + <actionGroup ref="addProductImage" stepKey="addImageForProduct"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + + <!-- Assert product image in admin product form --> + <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> + + <!-- Assert product in storefront product page --> + <actionGroup ref="AssertProductInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> + <argument name="product" value="defaultVirtualProduct"/> + </actionGroup> + + <!-- Assert product image in storefront product page --> + <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> + <argument name="product" value="defaultVirtualProduct"/> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminMassChangeProductsStatusTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminMassChangeProductsStatusTest.xml new file mode 100644 index 0000000000000..cf7c6af2fbd85 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminMassChangeProductsStatusTest.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminMassChangeProductsStatusTest"> + <annotations> + <features value="Catalog"/> + <stories value="Mass change product status"/> + <title value="Admin should be able to mass change products status"/> + <description value="Admin should be able to mass change products status"/> + <severity value="AVERAGE"/> + <testCaseId value="MC-57"/> + <group value="Catalog"/> + <group value="Product Attributes"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="ApiSimpleProduct" stepKey="createProductOne"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="createProductTwo"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + <deleteData createDataKey="createProductTwo" stepKey="deleteProductTwo"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + </after> + + <!-- Search and select products --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="searchProductGridByKeyword2" stepKey="searchByKeyword"> + <argument name="keyword" value="api-simple-product"/> + </actionGroup> + <actionGroup ref="sortProductsByIdDescending" stepKey="sortProductsByIdDescending"/> + <click selector="{{AdminProductGridSection.productGridCheckboxOnRow('1')}}" stepKey="clickCheckbox1"/> + <click selector="{{AdminProductGridSection.productGridCheckboxOnRow('2')}}" stepKey="clickCheckbox2"/> + <!-- Mass change status --> + <click selector="{{AdminProductGridSection.bulkActionDropdown}}" stepKey="clickDropdown"/> + <click selector="{{AdminProductGridSection.bulkActionOption('Change status')}}" stepKey="clickChangeStatus"/> + <click selector="{{AdminProductGridSection.bulkActionOption('Disable')}}" stepKey="clickDisable"/> + <waitForPageLoad stepKey="waitForBulkUpdatePage"/> + <see selector="{{AdminProductMessagesSection.successMessage}}" userInput="A total of 2 record(s) have been updated." stepKey="seeAttributeUpateSuccessMsg"/> + + <!-- Assert product one is not visible on storefront --> + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStorefrontAdvancedCatalogSearchProductOne"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductNameAndPriceActionGroup" stepKey="searchByNameProductOne"> + <argument name="name" value="$$createProductOne.name$$"/> + <argument name="priceFrom" value="$$createProductOne.price$$0"/> + <argument name="priceTo" value="$$createProductOne.price$$0"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResultForProductOne"/> + <see userInput="We can't find any items matching these search criteria" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.message}}" stepKey="seeCantFindProductOneMessage"/> + + <!-- Assert product two is not visible on storefront --> + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStorefrontAdvancedCatalogSearchProductTwo"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductNameAndPriceActionGroup" stepKey="searchByNameProductTwo"> + <argument name="name" value="$$createProductTwo.name$$"/> + <argument name="priceFrom" value="$$createProductTwo.price$$0"/> + <argument name="priceTo" value="$$createProductTwo.price$$0"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResultForProductTwo"/> + <see userInput="We can't find any items matching these search criteria" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.message}}" stepKey="seeCantFindProductTwoMessage"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminProductGridFilteringByDateAttributeTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminProductGridFilteringByDateAttributeTest.xml new file mode 100644 index 0000000000000..43edc3a54e00b --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminProductGridFilteringByDateAttributeTest.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminProductGridFilteringByDateAttributeTest"> + <annotations> + <title value="Verify Set Product as new Filter input on Product Grid doesn't getreset to currentDate"/> + <description value="Data input in the new from date filter field should not change"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-92019"/> + <group value="product"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <createData entity="SimpleProductWithNewFromDate" stepKey="createSimpleProductWithDate"/> + </before> + <after> + <deleteData createDataKey="createSimpleProductWithDate" stepKey="deleteProduct"/> + <actionGroup ref="logout" stepKey="logoutOfAdmin"/> + </after> + <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttribute"/> + <waitForPageLoad stepKey="wait1"/> + <click selector="{{AdminProductAttributeGridSection.ResetFilter}}" stepKey="resetFiltersOnGrid"/> + <fillField selector="{{AdminProductAttributeGridSection.GridFilterFrontEndLabel}}" userInput="Set Product as New from Date" stepKey="setAttributeLabel"/> + <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="searchForAttributeFromGrid"/> + <click selector="{{AdminProductAttributeGridSection.FirstRow}}" stepKey="clickOnAttributeRow"/> + <waitForPageLoad stepKey="wait2"/> + <click selector="{{AttributePropertiesSection.AdvancedProperties}}" stepKey="openAdvancedPropertiesTab"/> + <selectOption selector="#is_filterable_in_grid" userInput="Yes" stepKey="isFilterableInGrid"/> + <click selector="{{AttributePropertiesSection.Save}}" stepKey="saveAttribute"/> + <waitForPageLoad stepKey="waitForSaveAttribute"/> + <actionGroup ref="ClearCacheActionGroup" stepKey="clearCache"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad time="30" stepKey="waitForProductGridPageLoad"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="openColumnsdropDown1"/> + <checkOption selector="{{AdminProductGridFilterSection.viewColumnOption('Set Product as New from Date')}}" stepKey="showProductAsNewColumn"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="closeColumnsDropdown1"/> + <seeElement selector="{{AdminProductGridSection.columnHeader('Set Product as New from Date')}}" stepKey="seeNewFromDateColumn"/> + <waitForPageLoad stepKey="waitforFiltersToApply"/> + <actionGroup ref="filterProductGridBySetNewFromDate" stepKey="filterProductGridToCheckSetAsNewColumn"/> + <click selector="{{AdminProductGridSection.firstRow}}" stepKey="clickOnFirstRowProductGrid"/> + <waitForPageLoad stepKey="waitForProductEditPageToLoad"/> + <actionGroup ref="AdminFormSaveAndClose" stepKey="saveAndCloseProductForm"/> + <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="expandFilters"/> + <seeInField selector="{{AdminProductGridFilterSection.newFromDateFilter}}" userInput="05/16/2018" stepKey="checkForNewFromDate"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="openColumnsDropdown2"/> + <uncheckOption selector="{{AdminProductGridFilterSection.viewColumnOption('Set Product as New from Date')}}" stepKey="hideProductAsNewColumn"/> + <dontSeeElement selector="{{AdminProductGridSection.columnHeader('Set Product as New from Date')}}" stepKey="dontSeeNewFromDateColumn"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="closeColumnsDropdown2"/> + <click selector="{{AdminProductGridFilterSection.clearAll}}" stepKey="clearGridFilters"/> + </test> + </tests> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddRemoveProductImageSimpleProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminRemoveDefaultImageSimpleProductTest.xml similarity index 64% rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddRemoveProductImageSimpleProductTest.xml rename to dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminRemoveDefaultImageSimpleProductTest.xml index f3ff2d1b3f635..36b2c5e9ffac5 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddRemoveProductImageSimpleProductTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminRemoveDefaultImageSimpleProductTest.xml @@ -8,15 +8,16 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AdminAddRemoveProductImageSimpleProductTest"> + <test name="AdminRemoveDefaultImageSimpleProductTest"> <annotations> <features value="Catalog"/> - <stories value="Simple Product Add/Remove Images"/> - <title value="Admin should be able to add/remove images for a Simple Product"/> - <description value="Admin should be able to add/remove images for a Simple Product"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to remove default images from a Simple Product"/> + <description value="Admin should be able to remove default images from a Simple Product"/> <severity value="MAJOR"/> - <testCaseId value="MC-113"/> + <testCaseId value="MC-195"/> <group value="Catalog"/> + <group value="ji"/> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> @@ -40,29 +41,10 @@ <actionGroup ref="addProductImage" stepKey="addImageForProductSimple"> <argument name="image" value="MagentoLogo"/> </actionGroup> - <actionGroup ref="saveProductForm" stepKey="saveSimpleProduct"/> - - <!-- Assert product image in admin product form --> - <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> - - <!-- Assert product in storefront product page --> - <actionGroup ref="AssertProductInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> - <argument name="product" value="SimpleProduct3"/> - </actionGroup> - <!-- Assert product image in storefront product page --> - <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> - <argument name="product" value="SimpleProduct3"/> - <argument name="image" value="MagentoLogo"/> - </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveSimpleProduct"/> <!-- Remove image from product --> - <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageRemove"/> - <waitForPageLoad stepKey="waitForProductIndexPageLoad2"/> - <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku"> - <argument name="product" value="SimpleProduct3"/> - </actionGroup> - <actionGroup ref="openProducForEditByClickingRowXColumnYInProductGrid" stepKey="openProducForEditByClickingRow1Column2InProductGrid"/> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddRemoveProductImageVirtualProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminRemoveDefaultImageVirtualProductTest.xml similarity index 63% rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddRemoveProductImageVirtualProductTest.xml rename to dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminRemoveDefaultImageVirtualProductTest.xml index 360b1b4d95819..e872d96b8fdff 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddRemoveProductImageVirtualProductTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminRemoveDefaultImageVirtualProductTest.xml @@ -8,14 +8,14 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AdminAddRemoveProductImageVirtualProductTest"> + <test name="AdminRemoveDefaultImageVirtualProductTest"> <annotations> <features value="Catalog"/> - <stories value="Virtual Product Add/Remove Images"/> - <title value="Admin should be able to add/remove images for a Virtual Product"/> - <description value="Admin should be able to add/remove images for a Virtual Product"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to remove default images from a Virtual Product"/> + <description value="Admin should be able to remove default images from a Virtual Product"/> <severity value="MAJOR"/> - <testCaseId value="MC-103"/> + <testCaseId value="MC-197"/> <group value="Catalog"/> </annotations> <before> @@ -40,29 +40,10 @@ <actionGroup ref="addProductImage" stepKey="addImageForProduct"> <argument name="image" value="MagentoLogo"/> </actionGroup> - <actionGroup ref="saveProductForm" stepKey="saveProduct"/> - - <!-- Assert product image in admin product form --> - <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> - - <!-- Assert product in storefront product page --> - <actionGroup ref="AssertProductInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> - <argument name="product" value="defaultVirtualProduct"/> - </actionGroup> - <!-- Assert product image in storefront product page --> - <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> - <argument name="product" value="defaultVirtualProduct"/> - <argument name="image" value="MagentoLogo"/> - </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> <!-- Remove image from product --> - <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageRemove"/> - <waitForPageLoad stepKey="waitForProductIndexPageLoad2"/> - <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku"> - <argument name="product" value="defaultVirtualProduct"/> - </actionGroup> - <actionGroup ref="openProducForEditByClickingRowXColumnYInProductGrid" stepKey="openProducForEditByClickingRow1Column2InProductGrid"/> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/StorefrontProductsCompareWithEmptyAttributeTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/StorefrontProductsCompareWithEmptyAttributeTest.xml new file mode 100644 index 0000000000000..38872c4c58dcf --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/StorefrontProductsCompareWithEmptyAttributeTest.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="StorefrontProductsCompareWithEmptyAttributeTest"> + <annotations> + <title value="Product attribute is not visible on product compare page if it is empty"/> + <description value="Product attribute should not be visible on the product compare page if it is empty for all products that are being compared, not even displayed as N/A"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-91960"/> + <group value="productCompare"/> + </annotations> + <before> + <createData entity="productAttributeWithDropdownTwoOptions" stepKey="createProductAttribute"/> + <createData entity="ApiCategory" stepKey="createCategory"/> + <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct1"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct2"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createProductAttribute" stepKey="deleteProductAttribute"/> + <deleteData createDataKey="createSimpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="createSimpleProduct2" stepKey="deleteSimpleProduct2"/> + <actionGroup ref="logout" stepKey="logoutOfAdmin"/> + </after> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + <amOnPage url="{{AdminProductAttributeSetGridPage.url}}" stepKey="amOnAttributeSetPage"/> + <click selector="{{AdminProductAttributeSetGridSection.AttributeSetName('Default')}}" stepKey="chooseDefaultAttributeSet"/> + <waitForPageLoad stepKey="waitForAttributeSetPageLoad"/> + <dragAndDrop selector1="{{UnassignedAttributes.ProductAttributeName('testattribute')}}" selector2="{{Group.FolderName('Product Details')}}" stepKey="moveProductAttributeToGroup"/> + <click selector="{{AttributeSetSection.Save}}" stepKey="saveAttributeSet"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear" /> + <seeElement selector=".message-success" stepKey="assertSuccess"/> + <actionGroup ref="ClearCacheActionGroup" stepKey="clearCache"/> + <amOnPage url="{{StorefrontProductPage.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="goProductPageOnStorefront1"/> + <!-- View Simple Product 1 --> + <comment userInput="View simple product 1" stepKey="commentViewSimpleProduct1" after="goProductPageOnStorefront1"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct1.name$$)}}" stepKey="browseClickCategorySimpleProduct1View" after="commentViewSimpleProduct1"/> + <waitForLoadingMaskToDisappear stepKey="waitForSimpleProduct1Viewloaded" after="browseClickCategorySimpleProduct1View"/> + <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="compareAddSimpleProduct1ToCompare"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + <amOnPage url="{{StorefrontProductPage.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="goProductPageOnStorefront2"/> + <!-- View Simple Product 2 --> + <comment userInput="View simple product 2" stepKey="commentViewSimpleProduct2" after="goProductPageOnStorefront2"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct2.name$$)}}" stepKey="browseClickCategorySimpleProduct2View" after="commentViewSimpleProduct2"/> + <waitForLoadingMaskToDisappear stepKey="waitForSimpleProduct2Viewloaded" after="browseClickCategorySimpleProduct2View"/> + <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="compareAddSimpleProduct2ToCompare"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + <amOnPage url="{{StorefrontProductPage.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="goProductPageOnStorefront3"/> + <!-- Check products in comparison sidebar --> + <!-- Check simple product 1 in comparison sidebar --> + <comment userInput="Check simple product 1 in comparison sidebar" stepKey="commentCheckSimpleProduct1InComparisonSidebar" after="goProductPageOnStorefront3"/> + <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="compareSimpleProduct1InSidebar" after="commentCheckSimpleProduct1InComparisonSidebar"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- Check simple product2 in comparison sidebar --> + <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="compareSimpleProduct2InSidebar" after="compareSimpleProduct1InSidebar"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- Check products on comparison page --> + <!-- Check simple product 1 on comparison page --> + <comment userInput="Check simple product 1 on comparison page" stepKey="commentCheckSimpleProduct1OnComparisonPage"/> + <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="compareOpenComparePage" after="commentCheckSimpleProduct1OnComparisonPage"/> + <actionGroup ref="StorefrontCheckCompareSimpleProductActionGroup" stepKey="compareAssertSimpleProduct1InComparison" after="compareOpenComparePage"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + <seeElement selector="//table[@id='product-comparison']/tbody/tr/th/*[contains(text(),'SKU')]" stepKey="seeCompareAttribute1"/> + <dontSeeElement selector="//table[@id='product-comparison']/tbody/tr/th/*[contains(text(),'testattribute')]" stepKey="seeCompareAttribute2"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/ActionGroup/StorefrontCatalogSearchActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/ActionGroup/StorefrontCatalogSearchActionGroup.xml index 5e6bfeb448e13..fdf0564780024 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/ActionGroup/StorefrontCatalogSearchActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/ActionGroup/StorefrontCatalogSearchActionGroup.xml @@ -51,6 +51,46 @@ <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> + <!-- Storefront advanced catalog search by product name --> + <actionGroup name="StorefrontAdvancedCatalogSearchByProductNameActionGroup"> + <arguments> + <argument name="name" type="string"/> + </arguments> + <fillField selector="{{StorefrontCatalogSearchAdvancedFormSection.ProductName}}" userInput="{{name}}" stepKey="fill"/> + <click selector="{{StorefrontCatalogSearchAdvancedFormSection.SubmitButton}}" stepKey="clickSubmit"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> + + <!-- Storefront advanced catalog search by product sku --> + <actionGroup name="StorefrontAdvancedCatalogSearchByProductSkuActionGroup"> + <arguments> + <argument name="sku" type="string"/> + </arguments> + <fillField selector="{{StorefrontCatalogSearchAdvancedFormSection.SKU}}" userInput="{{sku}}" stepKey="fill"/> + <click selector="{{StorefrontCatalogSearchAdvancedFormSection.SubmitButton}}" stepKey="clickSubmit"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> + + <!-- Storefront advanced catalog search by product description --> + <actionGroup name="StorefrontAdvancedCatalogSearchByDescriptionActionGroup"> + <arguments> + <argument name="description" type="string"/> + </arguments> + <fillField selector="{{StorefrontCatalogSearchAdvancedFormSection.Description}}" userInput="{{description}}" stepKey="fill"/> + <click selector="{{StorefrontCatalogSearchAdvancedFormSection.SubmitButton}}" stepKey="clickSubmit"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> + + <!-- Storefront advanced catalog search by product short description --> + <actionGroup name="StorefrontAdvancedCatalogSearchByShortDescriptionActionGroup"> + <arguments> + <argument name="shortDescription" type="string"/> + </arguments> + <fillField selector="{{StorefrontCatalogSearchAdvancedFormSection.ShortDescription}}" userInput="{{shortDescription}}" stepKey="fill"/> + <click selector="{{StorefrontCatalogSearchAdvancedFormSection.SubmitButton}}" stepKey="clickSubmit"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> + <!-- Storefront advanced catalog search by product name and price --> <actionGroup name="StorefrontAdvancedCatalogSearchByProductNameAndPriceActionGroup"> <arguments> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedResultMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedResultMainSection.xml index f211561177da4..bf143d5f4b8b5 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedResultMainSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedResultMainSection.xml @@ -16,5 +16,6 @@ <element name="productCount" type="text" selector="#toolbar-amount"/> <element name="message" type="text" selector="div.message div"/> <element name="itemFound" type="text" selector=".search.found>strong"/> + <element name="productName" type="text" selector=".product.name.product-item-name>a"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/AdvanceCatalogSearchSimpleProductsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/AdvanceCatalogSearchSimpleProductsTest.xml new file mode 100644 index 0000000000000..f52a86810842e --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/AdvanceCatalogSearchSimpleProductsTest.xml @@ -0,0 +1,140 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdvanceCatalogSearchSimpleProductByNameTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search simple product with product name"/> + <description value="Guest customer should be able to advance search simple product with product name"/> + <severity value="MAJOR"/> + <testCaseId value="MC-132"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductNameActionGroup" stepKey="search"> + <argument name="name" value="$$createProductOne.name$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + </test> + <test name="AdvanceCatalogSearchSimpleProductBySkuTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search simple product with product sku"/> + <description value="Guest customer should be able to advance search simple product with product sku"/> + <severity value="MAJOR"/> + <testCaseId value="MC-133"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductSkuActionGroup" stepKey="search"> + <argument name="sku" value="$$createProductOne.sku$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + <see userInput="$$createProductOne.name$$" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productName}}" stepKey="seeProductName"/> + </test> + + <test name="AdvanceCatalogSearchSimpleProductByDescriptionTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search simple product with product description"/> + <description value="Guest customer should be able to advance search simple product with product description"/> + <severity value="MAJOR"/> + <testCaseId value="MC-134"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByDescriptionActionGroup" stepKey="search"> + <argument name="description" value="$$createProductOne.custom_attributes[description]$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + <see userInput="$$createProductOne.name$$" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productName}}" stepKey="seeProductName"/> + </test> + + <test name="AdvanceCatalogSearchSimpleProductByShortDescriptionTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search simple product with product short description"/> + <description value="Guest customer should be able to advance search simple product with product short description"/> + <severity value="MAJOR"/> + <testCaseId value="MC-135"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByShortDescriptionActionGroup" stepKey="search"> + <argument name="shortDescription" value="$$createProductOne.custom_attributes[short_description]$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + <see userInput="$$createProductOne.name$$" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productName}}" stepKey="seeProductName"/> + </test> + + <test name="AdvanceCatalogSearchSimpleProductByPriceTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search simple product with product price"/> + <description value="Guest customer should be able to advance search simple product with product price"/> + <severity value="MAJOR"/> + <testCaseId value="MC-136"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductNameAndPriceActionGroup" stepKey="search"> + <argument name="name" value="$$createProductOne.name$$"/> + <argument name="priceFrom" value="$$createProductOne.price$$"/> + <argument name="priceTo" value="$$createProductOne.price$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + <see userInput="$$createProductOne.name$$" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productName}}" stepKey="seeProductName"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/AdvanceCatalogSearchVirtualProductsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/AdvanceCatalogSearchVirtualProductsTest.xml new file mode 100644 index 0000000000000..80b1b294fecd5 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/AdvanceCatalogSearchVirtualProductsTest.xml @@ -0,0 +1,141 @@ +<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdvanceCatalogSearchVirtualProductByNameTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search virtual product with product name"/> + <description value="Guest customer should be able to advance search virtual product with product name"/> + <severity value="MAJOR"/> + <testCaseId value="MC-137"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiVirtualProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductNameActionGroup" stepKey="search"> + <argument name="name" value="$$createProductOne.name$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + <see userInput="$$createProductOne.name$$" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productName}}" stepKey="seeProductName"/> + </test> + <test name="AdvanceCatalogSearchVirtualProductBySkuTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search virtual product with product sku"/> + <description value="Guest customer should be able to advance search virtual product with product sku"/> + <severity value="MAJOR"/> + <testCaseId value="MC-162"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiVirtualProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductSkuActionGroup" stepKey="search"> + <argument name="sku" value="$$createProductOne.sku$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + <see userInput="$$createProductOne.name$$" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productName}}" stepKey="seeProductName"/> + </test> + + <test name="AdvanceCatalogSearchVirtualProductByDescriptionTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search virtual product with product description"/> + <description value="Guest customer should be able to advance search virtual product with product description"/> + <severity value="MAJOR"/> + <testCaseId value="MC-163"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiVirtualProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByDescriptionActionGroup" stepKey="search"> + <argument name="description" value="$$createProductOne.custom_attributes[description]$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + <see userInput="$$createProductOne.name$$" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productName}}" stepKey="seeProductName"/> + </test> + + <test name="AdvanceCatalogSearchVirtualProductByShortDescriptionTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search virtual product with product short description"/> + <description value="Guest customer should be able to advance search virtual product with product short description"/> + <severity value="MAJOR"/> + <testCaseId value="MC-164"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiVirtualProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByShortDescriptionActionGroup" stepKey="search"> + <argument name="shortDescription" value="$$createProductOne.custom_attributes[short_description]$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + <see userInput="$$createProductOne.name$$" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productName}}" stepKey="seeProductName"/> + </test> + + <test name="AdvanceCatalogSearchVirtualProductByPriceTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Advanced Catalog Product Search for all product types"/> + <title value="Guest customer should be able to advance search virtual product with product price"/> + <description value="Guest customer should be able to advance search virtual product with product price"/> + <severity value="MAJOR"/> + <testCaseId value="MC-165"/> + <group value="CatalogSearch"/> + </annotations> + <before> + <createData entity="ApiVirtualProductWithDescription" stepKey="createProductOne"/> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + </after> + + <actionGroup ref="GoToStoreViewAdvancedCatalogSearchActionGroup" stepKey="GoToStoreViewAdvancedCatalogSearchActionGroup"/> + <actionGroup ref="StorefrontAdvancedCatalogSearchByProductNameAndPriceActionGroup" stepKey="search"> + <argument name="name" value="$$createProductOne.name$$"/> + <argument name="priceFrom" value="$$createProductOne.price$$"/> + <argument name="priceTo" value="$$createProductOne.price$$"/> + </actionGroup> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="StorefrontCheckAdvancedSearchResult"/> + <see userInput="1 item" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.itemFound}}" stepKey="see"/> + <see userInput="$$createProductOne.name$$" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productName}}" stepKey="seeProductName"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/composer.json index 8446dd8fba446..65e7b9c781e61 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/composer.json @@ -12,19 +12,19 @@ }, "require": { "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-backend": "100.0.0-dev", "magento/magento2-functional-test-module-catalog": "100.0.0-dev", + "magento/magento2-functional-test-module-eav": "100.0.0-dev", "magento/magento2-functional-test-module-search": "100.0.0-dev", "magento/magento2-functional-test-module-theme": "100.0.0-dev", "magento/magento2-functional-test-module-ui": "100.0.0-dev", "magento/magento2-functional-test-module-store": "100.0.0-dev", + "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", "php": "~7.1.3||~7.2.0" }, "suggest": { - "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", "magento/magento2-functional-test-module-customer": "100.0.0-dev", - "magento/magento2-functional-test-module-directory": "100.0.0-dev", - "magento/magento2-functional-test-module-eav": "100.0.0-dev" + "magento/magento2-functional-test-module-directory": "100.0.0-dev" }, "autoload": { "psr-4": { diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ProductConfigurableAttributeData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ProductConfigurableAttributeData.xml index da02b259956c4..5a1c0139d56ca 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ProductConfigurableAttributeData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ProductConfigurableAttributeData.xml @@ -25,4 +25,8 @@ <data key="name" unique="suffix">Blue</data> <data key="price">3.00</data> </entity> + <entity name="colorProductAttribute4" type="product_attribute"> + <data key="name" unique="suffix">Orange</data> + <data key="price">99.99</data> + </entity> </entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/AdminCreateProductConfigurationsPanelSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/AdminCreateProductConfigurationsPanelSection.xml index 737d2b7cd0740..a097dfa4ad764 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/AdminCreateProductConfigurationsPanelSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/AdminCreateProductConfigurationsPanelSection.xml @@ -21,6 +21,7 @@ <element name="createNewValue" type="input" selector=".action-create-new" timeout="30"/> <element name="attributeName" type="input" selector="li[data-attribute-option-title=''] .admin__field-create-new .admin__control-text"/> <element name="saveAttribute" type="button" selector="li[data-attribute-option-title=''] .action-save" timeout="30"/> + <element name="attributeCheckboxByIndex" type="input" selector="li.attribute-option:nth-of-type({{var1}}) input" parameterized="true"/> <element name="applyUniquePricesByAttributeToEachSku" type="radio" selector=".admin__field-label[for='apply-unique-prices-radio']"/> <element name="selectAttribute" type="select" selector="#select-each-price" timeout="30"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/StorefrontProductInfoMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/StorefrontProductInfoMainSection.xml index c5da83d9ac6ed..cebb76e68a6cc 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/StorefrontProductInfoMainSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/StorefrontProductInfoMainSection.xml @@ -13,5 +13,6 @@ <element name="productAttributeTitle1" type="text" selector="#product-options-wrapper div[tabindex='0'] label"/> <element name="productAttributeOptions1" type="select" selector="#product-options-wrapper div[tabindex='0'] option"/> <element name="productAttributeOptionsSelectButton" type="select" selector="#product-options-wrapper .super-attribute-select"/> + <element name="productAttributeOptionsError" type="text" selector="//div[@class='mage-error']"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminAddDefaultImageConfigurableTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminAddDefaultImageConfigurableTest.xml new file mode 100644 index 0000000000000..55d6029c917ce --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminAddDefaultImageConfigurableTest.xml @@ -0,0 +1,122 @@ +<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminAddDefaultImageConfigurableTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to add default images for a Configurable Product"/> + <description value="Admin should be able to add default images for a Configurable Product"/> + <severity value="MAJOR"/> + <testCaseId value="MC-101"/> + <group value="ConfigurableProduct"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <createData entity="SimpleSubCategory" stepKey="categoryHandle"/> + + <createData entity="SimpleProduct" stepKey="simple1Handle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + + <createData entity="SimpleProduct" stepKey="simple2Handle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + + <!-- TODO: Move configurable product creation to an actionGroup when MQE-697 is fixed --> + <createData entity="BaseConfigurableProduct" stepKey="baseConfigProductHandle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + <createData entity="productDropDownAttribute" stepKey="productAttributeHandle"/> + + <createData entity="productAttributeOption1" stepKey="productAttributeOption1Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + <createData entity="productAttributeOption2" stepKey="productAttributeOption2Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + + <createData entity="AddToDefaultSet" stepKey="addToAttributeSetHandle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getAttributeOption1Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getAttributeOption2Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </getData> + + <createData entity="SimpleOne" stepKey="childProductHandle1"> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption1Handle"/> + </createData> + <createData entity="SimpleOne" stepKey="childProductHandle2"> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption2Handle"/> + </createData> + + <createData entity="ConfigurableProductTwoOptions" stepKey="configProductOptionHandle"> + <requiredEntity createDataKey="baseConfigProductHandle"/> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption1Handle"/> + <requiredEntity createDataKey="getAttributeOption2Handle"/> + </createData> + + <createData entity="ConfigurableProductAddChild" stepKey="configProductHandle1"> + <requiredEntity createDataKey="baseConfigProductHandle"/> + <requiredEntity createDataKey="childProductHandle1"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="configProductHandle2"> + <requiredEntity createDataKey="baseConfigProductHandle"/> + <requiredEntity createDataKey="childProductHandle2"/> + </createData> + </before> + <after> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="simple1Handle" stepKey="deleteSimple1"/> + <deleteData createDataKey="simple2Handle" stepKey="deleteSimple2"/> + <deleteData createDataKey="childProductHandle1" stepKey="deleteChild1"/> + <deleteData createDataKey="childProductHandle2" stepKey="deleteChild2"/> + <deleteData createDataKey="baseConfigProductHandle" stepKey="deleteConfig"/> + <deleteData createDataKey="categoryHandle" stepKey="deleteCategory"/> + <deleteData createDataKey="productAttributeHandle" stepKey="deleteProductAttribute"/> + </after> + + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="productIndexPage"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGrid"> + <argument name="product" value="$$baseConfigProductHandle$$"/> + </actionGroup> + <actionGroup ref="openProducForEditByClickingRowXColumnYInProductGrid" stepKey="openProducForEditByClickingRow1Column2InProductGrid1"/> + + <!-- Add image to product --> + <actionGroup ref="addProductImage" stepKey="addImageForProduct"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + + <!-- Assert product image in admin product form --> + <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> + + <!-- Assert product in storefront product page --> + <actionGroup ref="AssertProductNameAndSkuInStorefrontProductPageByCustomAttributeUrlKey" stepKey="AssertProductInStorefrontProductPage"> + <argument name="product" value="$$baseConfigProductHandle$$"/> + </actionGroup> + + <!-- Assert product image in storefront product page --> + <actionGroup ref="assertProductImageStorefrontProductPage2" stepKey="assertProductImageStorefrontProductPage"> + <argument name="product" value="$$baseConfigProductHandle$$"/> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminConfigurableProductUpdateTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminConfigurableProductUpdateTest.xml index 646bf9f65bbe5..d640e243c0572 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminConfigurableProductUpdateTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminConfigurableProductUpdateTest.xml @@ -246,4 +246,107 @@ <dontSee selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" userInput="option1" stepKey="dontSeeOption1InStorefront"/> <see selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" userInput="option2" stepKey="seeOption2Again"/> </test> + + <test name="AdminConfigurableProductRemoveConfigurationTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Edit a configurable product in admin"/> + <title value="Admin should be able to remove a configuration from a Configurable Product"/> + <description value="Admin should be able to remove a configuration from a Configurable Product"/> + <severity value="AVERAGE"/> + <testCaseId value="MC-86"/> + <group value="ConfigurableProduct"/> + </annotations> + + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <amOnPage url="admin/admin/auth/logout/" stepKey="logout"/> + </after> + + <!-- Create a configurable product via the UI --> + <actionGroup ref="createConfigurableProduct" stepKey="createProduct"> + <argument name="product" value="_defaultProduct"/> + <argument name="category" value="$$createCategory$$"/> + </actionGroup> + + <!-- + After saving, we are still on the product edit page. There is no need to reload or go to this page + again, because a round trip to the server has already happened. + --> + + <!-- Remove a configuration option from the configurable product --> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickEditConfigurations"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton1"/> + <click selector="{{AdminCreateProductConfigurationsPanel.attributeCheckboxByIndex('1')}}" stepKey="deselectOption"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton2"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton3"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton4"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> + + <!-- Verify that the removed option is not present in the storefront --> + <amOnPage url="{{StorefrontProductPage.url(_defaultProduct.urlKey)}}" stepKey="amOnStorefrontPage"/> + <waitForPageLoad stepKey="waitForStorefrontPage"/> + <dontSee selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" userInput="{{colorProductAttribute1.name}}" stepKey="seeInDropDown1"/> + <see selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" userInput="{{colorProductAttribute2.name}}" stepKey="seeInDropDown2"/> + <see selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" userInput="{{colorProductAttribute3.name}}" stepKey="seeInDropDown3"/> + </test> + + <test name="AdminConfigurableProductAddConfigurationTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Edit a configurable product in admin"/> + <title value="Admin should be able to edit configuration to add a value to an existing attribute"/> + <description value="Admin should be able to edit configuration to add a value to an existing attribute"/> + <severity value="AVERAGE"/> + <testCaseId value="MC-95"/> + <group value="ConfigurableProduct"/> + </annotations> + + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <amOnPage url="admin/admin/auth/logout/" stepKey="logout"/> + </after> + + <!-- Create a configurable product via the UI --> + <actionGroup ref="createConfigurableProduct" stepKey="createProduct"> + <argument name="product" value="_defaultProduct"/> + <argument name="category" value="$$createCategory$$"/> + </actionGroup> + + <!-- + After saving, we are still on the product edit page. There is no need to reload or go to this page + again, because a round trip to the server has already happened. + --> + + <!-- Add a configuration option to the configurable product --> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickEditConfigurations"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton1"/> + <click selector="{{AdminCreateProductConfigurationsPanel.createNewValue}}" stepKey="clickOnCreateNewValue1"/> + <fillField userInput="{{colorProductAttribute4.name}}" selector="{{AdminCreateProductConfigurationsPanel.attributeName}}" stepKey="fillFieldForNewAttribute1"/> + <click selector="{{AdminCreateProductConfigurationsPanel.saveAttribute}}" stepKey="clickOnSaveNewAttribute1"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton2"/> + <click selector="{{AdminCreateProductConfigurationsPanel.applySingleQuantityToEachSkus}}" stepKey="clickOnApplySingleQuantityToEachSku"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.quantity}}" userInput="42" stepKey="enterAttributeQuantity"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton3"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton4"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> + + <!-- Verify that the added option is present in the storefront --> + <amOnPage url="{{StorefrontProductPage.url(_defaultProduct.urlKey)}}" stepKey="amOnStorefrontPage"/> + <waitForPageLoad stepKey="waitForStorefrontPage"/> + <see selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" userInput="{{colorProductAttribute1.name}}" stepKey="seeInDropDown1"/> + <see selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" userInput="{{colorProductAttribute2.name}}" stepKey="seeInDropDown2"/> + <see selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" userInput="{{colorProductAttribute3.name}}" stepKey="seeInDropDown3"/> + <see selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" userInput="{{colorProductAttribute4.name}}" stepKey="seeInDropDown4"/> + </test> </tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminAddRemoveProductImageConfigurableTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminRemoveDefaultImageConfigurableTest.xml similarity index 79% rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminAddRemoveProductImageConfigurableTest.xml rename to dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminRemoveDefaultImageConfigurableTest.xml index 52dc1bf0b5390..287cdce875d77 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminAddRemoveProductImageConfigurableTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminRemoveDefaultImageConfigurableTest.xml @@ -8,14 +8,14 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AdminAddRemoveProductImageConfigurableTest"> + <test name="AdminRemoveDefaultImageConfigurableTest"> <annotations> <features value="ConfigurableProduct"/> - <stories value="Configurable Product Add/Remove Images"/> - <title value="Admin should be able to add/remove images for a Configurable Product"/> - <description value="Admin should be able to add/remove images for a Configurable Product"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to remove default images from a Configurable Product"/> + <description value="Admin should be able to remove default images from a Configurable Product"/> <severity value="MAJOR"/> - <testCaseId value="MC-101"/> + <testCaseId value="MC-196"/> <group value="ConfigurableProduct"/> </annotations> @@ -103,29 +103,10 @@ <actionGroup ref="addProductImage" stepKey="addImageForProduct"> <argument name="image" value="MagentoLogo"/> </actionGroup> - <actionGroup ref="saveProductForm" stepKey="saveProduct"/> - - <!-- Assert product image in admin product form --> - <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> - - <!-- Assert product in storefront product page --> - <actionGroup ref="AssertProductNameAndSkuInStorefrontProductPageByCustomAttributeUrlKey" stepKey="AssertProductInStorefrontProductPage"> - <argument name="product" value="$$baseConfigProductHandle$$"/> - </actionGroup> - <!-- Assert product image in storefront product page --> - <actionGroup ref="assertProductImageStorefrontProductPage2" stepKey="assertProductImageStorefrontProductPage"> - <argument name="product" value="$$baseConfigProductHandle$$"/> - <argument name="image" value="MagentoLogo"/> - </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> <!-- Remove image from product --> - <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageRemove"/> - <waitForPageLoad stepKey="waitForProductIndexPageLoad2"/> - <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku"> - <argument name="product" value="$$baseConfigProductHandle$$"/> - </actionGroup> - <actionGroup ref="openProducForEditByClickingRowXColumnYInProductGrid" stepKey="openProducForEditByClickingRow1Column2InProductGrid2"/> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/StorefrontConfigurableProductDetailsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/StorefrontConfigurableProductDetailsTest.xml new file mode 100644 index 0000000000000..e7f733cf010f3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/StorefrontConfigurableProductDetailsTest.xml @@ -0,0 +1,165 @@ +<?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="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="StorefrontConfigurableProductBasicInfoTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="View configurable product details in storefront"/> + <title value="Guest customer should see basic Configurable Product details"/> + <description value="Guest customer should see basic Configurable Product details"/> + <severity value="MAJOR"/> + <testCaseId value="MC-77"/> + <group value="ConfigurableProduct"/> + </annotations> + + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!-- Create a configurable product via the UI --> + <actionGroup ref="createConfigurableProduct" stepKey="createProduct"> + <argument name="product" value="_defaultProduct"/> + <argument name="category" value="$$createCategory$$"/> + </actionGroup> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + </after> + + <!-- Verify configurable product details in storefront product view --> + <amOnPage url="{{_defaultProduct.urlKey}}.html" stepKey="amOnConfigurableProductPage"/> + <waitForPageLoad stepKey="wait"/> + <see userInput="{{_defaultProduct.name}}" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="seeProductName"/> + <see userInput="{{_defaultProduct.sku}}" selector="{{StorefrontProductInfoMainSection.productSku}}" stepKey="seeProductSku"/> + <see userInput="As low as" selector="{{StorefrontProductInfoMainSection.productPriceLabel}}" stepKey="seeProductPriceLabel"/> + <see userInput="IN STOCK" selector="{{StorefrontProductInfoMainSection.productStockStatus}}" stepKey="seeProductStockStatus"/> + <see userInput="1.00" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="seeProductPrice"/> + <see userInput="{{colorProductAttribute.default_label}}" selector="{{StorefrontProductInfoMainSection.productAttributeTitle1}}" stepKey="seeProductAttributeTitle"/> + <see selector="{{StorefrontProductInfoMainSection.productAttributeTitle1}}" userInput="{{colorProductAttribute.default_label}}" stepKey="seeColorAttributeName1"/> + <see userInput="{{colorProductAttribute1.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" stepKey="seeInDropDown1"/> + <see userInput="{{colorProductAttribute2.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" stepKey="seeInDropDown2"/> + <see userInput="{{colorProductAttribute3.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptions1}}" stepKey="seeInDropDown3"/> + </test> + + <test name="StorefrontConfigurableProductOptionsTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="View configurable product details in storefront"/> + <title value="Guest customer should be able to see product configuration options"/> + <description value="Guest customer should be able to see product configuration options"/> + <severity value="MAJOR"/> + <testCaseId value="MC-92"/> + <group value="ConfigurableProduct"/> + </annotations> + + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!-- Create a configurable product via the UI --> + <actionGroup ref="createConfigurableProduct" stepKey="createProduct"> + <argument name="product" value="_defaultProduct"/> + <argument name="category" value="$$createCategory$$"/> + </actionGroup> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + </after> + + <!-- Verify configurable product options in storefront product view --> + <amOnPage url="{{_defaultProduct.urlKey}}.html" stepKey="amOnConfigurableProductPage"/> + <waitForPageLoad stepKey="wait"/> + <see userInput="{{_defaultProduct.name}}" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="seeProductName"/> + <selectOption userInput="{{colorProductAttribute1.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOption1"/> + <dontSee userInput="As low as" selector="{{StorefrontProductInfoMainSection.productPriceLabel}}" stepKey="dontSeeProductPriceLabel1"/> + <see userInput="1.00" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="seeProductPrice1"/> + <selectOption userInput="{{colorProductAttribute2.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOption2"/> + <dontSee userInput="As low as" selector="{{StorefrontProductInfoMainSection.productPriceLabel}}" stepKey="dontSeeProductPriceLabel2"/> + <see userInput="2.00" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="seeProductPrice2"/> + <selectOption userInput="{{colorProductAttribute3.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOption3"/> + <dontSee userInput="As low as" selector="{{StorefrontProductInfoMainSection.productPriceLabel}}" stepKey="dontSeeProductPriceLabel3"/> + <see userInput="3.00" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="seeProductPrice3"/> + </test> + + <test name="StorefrontConfigurableProductCanAddToCartTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="View configurable product details in storefront"/> + <title value="Guest customer should be able to successfully add the product to the cart"/> + <description value="Guest customer should be able to successfully add the product to the cart"/> + <severity value="MAJOR"/> + <testCaseId value="MC-97"/> + <group value="ConfigurableProduct"/> + </annotations> + + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!-- Create a configurable product via the UI --> + <actionGroup ref="createConfigurableProduct" stepKey="createProduct"> + <argument name="product" value="_defaultProduct"/> + <argument name="category" value="$$createCategory$$"/> + </actionGroup> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + </after> + + <!-- Verify adding configurable product to cart after an option is selected in storefront product view --> + <amOnPage url="{{_defaultProduct.urlKey}}.html" stepKey="amOnConfigurableProductPage"/> + <waitForPageLoad stepKey="wait"/> + <see userInput="{{_defaultProduct.name}}" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="seeProductName"/> + <selectOption userInput="{{colorProductAttribute1.name}}" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" stepKey="selectOption1"/> + <waitForElementVisible selector="{{StorefrontProductInfoMainSection.AddToCart}}" stepKey="waitForAddToCartVisible"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="addProductToCart"> + <argument name="product" value="_defaultProduct"/> + <argument name="productCount" value="1"/> + </actionGroup> + </test> + + <test name="StorefrontConfigurableProductCantAddToCartTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="View configurable product details in storefront"/> + <title value="Guest customer should not be able to add the product to the cart if options are not selected"/> + <description value="Guest customer should not be able to add the product to the cart if options are not selected"/> + <severity value="MAJOR"/> + <testCaseId value="MC-81"/> + <group value="ConfigurableProduct"/> + </annotations> + + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!-- Create a configurable product via the UI --> + <actionGroup ref="createConfigurableProduct" stepKey="createProduct"> + <argument name="product" value="_defaultProduct"/> + <argument name="category" value="$$createCategory$$"/> + </actionGroup> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + </after> + + <!-- Verify not able to add configurable product to cart when no option is selected in storefront product view --> + <amOnPage url="{{_defaultProduct.urlKey}}.html" stepKey="amOnConfigurableProductPage"/> + <waitForPageLoad stepKey="wait"/> + <see userInput="{{_defaultProduct.name}}" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="seeProductName"/> + <waitForElementVisible selector="{{StorefrontProductInfoMainSection.AddToCart}}" stepKey="waitForAddToCartVisible"/> + <click selector="{{StorefrontProductInfoMainSection.AddToCart}}" stepKey="clickAddToCart" /> + <see userInput="This is a required field" selector="{{StorefrontProductInfoMainSection.productAttributeOptionsError}}" stepKey="seeError"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/StorefrontConfigurableProductViewTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/StorefrontConfigurableProductViewTest.xml index 447bb6683bca0..baaa5c4ef938f 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/StorefrontConfigurableProductViewTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/StorefrontConfigurableProductViewTest.xml @@ -11,7 +11,7 @@ <test name="StorefrontConfigurableProductGridViewTest"> <annotations> <features value="ConfigurableProduct"/> - <stories value="Storefront"/> + <stories value="View configurable product in a category in storefront"/> <title value="customer should see the configurable product in the category grid"/> <description value="customer should see the configurable product in the category grid"/> <severity value="CRITICAL"/> @@ -47,7 +47,7 @@ <test name="StorefrontConfigurableProductListViewTest"> <annotations> <features value="ConfigurableProduct"/> - <stories value="Storefront"/> + <stories value="View configurable product in a category in storefront"/> <title value="customer should see the configurable product in the category list"/> <description value="customer should see the configurable product in the category list"/> <severity value="CRITICAL"/> @@ -85,7 +85,7 @@ <test name="StorefrontConfigurableProductAddToCartTest"> <annotations> <features value="ConfigurableProduct"/> - <stories value="Storefront"/> + <stories value="View configurable product in a category in storefront"/> <title value="customer should be taken to the product details page when clicking add to cart"/> <description value="customer should be taken to the product details page when clicking add to cart"/> <severity value="CRITICAL"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/AdminAddDefaultImageDownloadableProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/AdminAddDefaultImageDownloadableProductTest.xml new file mode 100644 index 0000000000000..e95e788957395 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/AdminAddDefaultImageDownloadableProductTest.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminAddDefaultImageDownloadableProductTest"> + <annotations> + <features value="Downloadable"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to add default images for a Downloadable Product"/> + <description value="Admin should be able to add default images for a Downloadable Product"/> + <severity value="MAJOR"/> + <testCaseId value="MC-117"/> + <group value="Downloadable"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + </after> + + <!-- Create product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageAdd"/> + <waitForPageLoad stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProductPage"> + <argument name="product" value="DownloadableProduct"/> + </actionGroup> + <actionGroup ref="fillMainProductFormNoWeight" stepKey="fillMainProductForm"> + <argument name="product" value="DownloadableProduct"/> + </actionGroup> + + <!-- Add image to product --> + <actionGroup ref="addProductImage" stepKey="addImageForProduct"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + + <!-- Add downloadable links --> + <click selector="{{AdminProductDownloadableSection.sectionHeader}}" stepKey="openDownloadableSection"/> + <checkOption selector="{{AdminProductDownloadableSection.isDownloadableProduct}}" stepKey="checkIsDownloadable"/> + <fillField userInput="{{downloadableData.link_title}}" selector="{{AdminProductDownloadableSection.linksTitleInput}}" stepKey="fillDownloadableLinkTitle"/> + <checkOption selector="{{AdminProductDownloadableSection.isLinksPurchasedSeparately}}" stepKey="checkLinksPurchasedSeparately"/> + <fillField userInput="{{downloadableData.sample_title}}" selector="{{AdminProductDownloadableSection.samplesTitleInput}}" stepKey="fillDownloadableSampleTitle"/> + <actionGroup ref="addDownloadableProductLinkWithMaxDownloads" stepKey="addDownloadableLinkWithMaxDownloads"> + <argument name="link" value="downloadableLinkWithMaxDownloads"/> + </actionGroup> + <actionGroup ref="addDownloadableProductLink" stepKey="addDownloadableLink"> + <argument name="link" value="downloadableLink"/> + </actionGroup> + + <!--Save product--> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + + <!-- Assert product image in admin product form --> + <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> + + <!-- Assert product in storefront product page --> + <actionGroup ref="AssertProductNameAndSkuInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> + <argument name="product" value="DownloadableProduct"/> + </actionGroup> + + <!-- Assert product image in storefront product page --> + <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> + <argument name="product" value="DownloadableProduct"/> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/AdminAddRemoveProductImageDownloadableProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/AdminRemoveDefaultImageDownloadableProductTest.xml similarity index 70% rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/AdminAddRemoveProductImageDownloadableProductTest.xml rename to dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/AdminRemoveDefaultImageDownloadableProductTest.xml index 6b086a3d4050b..43d73e45a943f 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/AdminAddRemoveProductImageDownloadableProductTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/AdminRemoveDefaultImageDownloadableProductTest.xml @@ -8,14 +8,14 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AdminAddRemoveProductImageDownloadableProductTest"> + <test name="AdminRemoveDefaultImageDownloadableProductTest"> <annotations> <features value="Downloadable"/> - <stories value="Downloadable Product Add/Remove Images"/> - <title value="Admin should be able to add/remove images for a Downloadable Product"/> - <description value="Admin should be able to add/remove images for a Downloadable Product"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to remove default images from a Downloadable Product"/> + <description value="Admin should be able to remove default images from a Downloadable Product"/> <severity value="MAJOR"/> - <testCaseId value="MC-117"/> + <testCaseId value="MC-201"/> <group value="Downloadable"/> </annotations> <before> @@ -56,27 +56,7 @@ <!--Save product--> <actionGroup ref="saveProductForm" stepKey="saveProduct"/> - <!-- Assert product image in admin product form --> - <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> - - <!-- Assert product in storefront product page --> - <actionGroup ref="AssertProductNameAndSkuInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> - <argument name="product" value="DownloadableProduct"/> - </actionGroup> - - <!-- Assert product image in storefront product page --> - <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> - <argument name="product" value="DownloadableProduct"/> - <argument name="image" value="MagentoLogo"/> - </actionGroup> - <!-- Remove image from product --> - <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageRemove"/> - <waitForPageLoad stepKey="waitForProductIndexPageLoad2"/> - <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku"> - <argument name="product" value="DownloadableProduct"/> - </actionGroup> - <actionGroup ref="openProducForEditByClickingRowXColumnYInProductGrid" stepKey="openProducForEditByClickingRow1Column2InProductGrid"/> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/AdminAddDefaultImageGroupedProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/AdminAddDefaultImageGroupedProductTest.xml new file mode 100644 index 0000000000000..2120045513e13 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/AdminAddDefaultImageGroupedProductTest.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminAddDefaultImageGroupedProductTest"> + <annotations> + <features value="GroupedProduct"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to add default images for a Grouped Product"/> + <description value="Admin should be able to add default images for a Grouped Product"/> + <severity value="MAJOR"/> + <testCaseId value="MC-106"/> + <group value="GroupedProduct"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="ApiSimpleProduct" stepKey="createProductOne"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="createProductTwo"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + <deleteData createDataKey="createProductTwo" stepKey="deleteProductTwo"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + </after> + + <!-- Create product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPage"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProduct"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <actionGroup ref="fillGroupedProductForm" stepKey="fillProductForm"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + + <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToGroupedSection"/> + <conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductsSection"/> + <click selector="body" stepKey="clickBodyToCorrectFocusGrouped"/> + <click selector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" stepKey="clickAddProductsToGroup"/> + <waitForElementVisible selector="{{AdminAddProductsToGroupPanel.filters}}" stepKey="waitForGroupedProductModal"/> + <actionGroup ref="filterProductGridBySku2" stepKey="filterGroupedProducts"> + <argument name="sku" value="api-simple-product"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToGroupPanel.nThCheckbox('0')}}" stepKey="checkFilterResult1"/> + <checkOption selector="{{AdminAddProductsToGroupPanel.nThCheckbox('1')}}" stepKey="checkFilterResult2"/> + + <click selector="{{AdminAddProductsToGroupPanel.addSelectedProducts}}" stepKey="clickAddSelectedGroupProducts"/> + + <!-- Add image to product --> + <actionGroup ref="addProductImage" stepKey="addImageForProduct"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + + <!-- Assert product image in admin product form --> + <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> + + <!-- Assert product in storefront product page --> + <actionGroup ref="AssertProductNameAndSkuInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + + <!-- Assert product image in storefront product page --> + <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> + <argument name="product" value="GroupedProduct"/> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/AdminAddRemoveProductImageGroupedProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/AdminRemoveDefaultImageGroupedProductTest.xml similarity index 74% rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/AdminAddRemoveProductImageGroupedProductTest.xml rename to dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/AdminRemoveDefaultImageGroupedProductTest.xml index 84ecec485db6d..b1105369b2ff5 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/AdminAddRemoveProductImageGroupedProductTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/AdminRemoveDefaultImageGroupedProductTest.xml @@ -8,14 +8,14 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AdminAddRemoveProductImageGroupedProductTest"> + <test name="AdminRemoveDefaultImageGroupedProductTest"> <annotations> <features value="GroupedProduct"/> - <stories value="Grouped Product Add/Remove Images"/> - <title value="Admin should be able to add/remove images for a Grouped Product"/> - <description value="Admin should be able to add/remove images for a Grouped Product"/> + <stories value="Add/remove images and videos for all product types and category"/> + <title value="Admin should be able to remove default images from a Grouped Product"/> + <description value="Admin should be able to remove default images from a Grouped Product"/> <severity value="MAJOR"/> - <testCaseId value="MC-106"/> + <testCaseId value="MC-198"/> <group value="GroupedProduct"/> </annotations> <before> @@ -63,29 +63,10 @@ <actionGroup ref="addProductImage" stepKey="addImageForProduct"> <argument name="image" value="MagentoLogo"/> </actionGroup> - <actionGroup ref="saveProductForm" stepKey="saveProduct"/> - - <!-- Assert product image in admin product form --> - <actionGroup ref="assertProductImageAdminProductPage" stepKey="assertProductImageAdminProductPage"/> - - <!-- Assert product in storefront product page --> - <actionGroup ref="AssertProductNameAndSkuInStorefrontProductPage" stepKey="AssertProductInStorefrontProductPage"> - <argument name="product" value="GroupedProduct"/> - </actionGroup> - <!-- Assert product image in storefront product page --> - <actionGroup ref="assertProductImageStorefrontProductPage" stepKey="assertProductImageStorefrontProductPage"> - <argument name="product" value="GroupedProduct"/> - <argument name="image" value="MagentoLogo"/> - </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> <!-- Remove image from product --> - <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageRemove"/> - <waitForPageLoad stepKey="waitForProductIndexPageLoad2"/> - <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku"> - <argument name="product" value="GroupedProduct"/> - </actionGroup> - <actionGroup ref="openProducForEditByClickingRowXColumnYInProductGrid" stepKey="openProducForEditByClickingRow1Column2InProductGrid"/> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form.php index 31fadc2cf4f85..61a39a441c973 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Form.php @@ -60,7 +60,17 @@ class Form extends Block */ public function getGroup($tabName, $groupName) { - $this->openTab($tabName); + $this->baseUrl = $this->getBrowserUrl(); + if (substr($this->baseUrl, -1) !== '/') { + $this->baseUrl = $this->baseUrl . '/'; + } + + $tabUrl = $this->getTabUrl($tabName); + + if ($this->getBrowserUrl() !== $tabUrl) { + $this->browser->open($tabUrl); + } + $this->waitForElementNotVisible($this->tabReadiness); $groupElement = $this->_rootElement->find( sprintf($this->groupBlock, $tabName, $groupName), @@ -85,24 +95,6 @@ public function getGroup($tabName, $groupName) return $blockFactory->getMagentoBackendSystemConfigFormGroup($groupElement); } - /** - * Check whether specified group presented on page. - * - * @param string $tabName - * @param string $groupName - * - * @return bool - */ - public function isGroupVisible(string $tabName, string $groupName) - { - $this->openTab($tabName); - - return $this->_rootElement->find( - sprintf($this->groupBlockLink, $tabName, $groupName), - Locator::SELECTOR_CSS - )->isVisible(); - } - /** * Retrieve url associated with the form. */ @@ -145,24 +137,4 @@ private function getTabUrl($tabName) return $tabUrl; } - - /** - * Open specified tab. - * - * @param string $tabName - * @return void - */ - private function openTab(string $tabName) - { - $this->baseUrl = $this->getBrowserUrl(); - if (substr($this->baseUrl, -1) !== '/') { - $this->baseUrl = $this->baseUrl . '/'; - } - $tabUrl = $this->getTabUrl($tabName); - - if ($this->getBrowserUrl() !== $tabUrl) { - $this->browser->open($tabUrl); - } - $this->waitForElementNotVisible($this->tabReadiness); - } } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertDeveloperSectionVisibility.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertDeveloperSectionVisibility.php index 010b3a58134aa..4cff4b2a90c17 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertDeveloperSectionVisibility.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertDeveloperSectionVisibility.php @@ -9,57 +9,27 @@ use Magento\Backend\Test\Page\Adminhtml\SystemConfigEdit; /** - * Assert that all groups in Developer section is not present in production mode except debug group "Log to File" field. + * Assert that Developer section is not present in production mode. */ class AssertDeveloperSectionVisibility extends AbstractConstraint { /** - * List of groups not visible in production mode. - * - * @var array - */ - private $groups = [ - 'front_end_development_workflow', - 'restrict', - 'template', - 'translate_inline', - 'js', - 'css', - 'image', - 'static', - 'grid', - ]; - - /** - * Assert all groups in Developer section is not present in production mode except debug group "Log to File" field. + * Assert Developer section is not present in production mode. * * @param SystemConfigEdit $configEdit * @return void */ public function processAssert(SystemConfigEdit $configEdit) { - $configEdit->open(); if ($_ENV['mage_mode'] === 'production') { - foreach ($this->groups as $group) { - \PHPUnit\Framework\Assert::assertFalse( - $configEdit->getForm()->isGroupVisible('dev', $group), - sprintf('%s group should be hidden in production mode.', $group) - ); - } - \PHPUnit\Framework\Assert::assertTrue( - $configEdit->getForm()->getGroup('dev', 'debug')->isFieldVisible('dev', 'debug_debug', 'logging'), - '"Log to File" should be presented in production mode.' + \PHPUnit\Framework\Assert::assertFalse( + in_array('Developer', $configEdit->getTabs()->getSubTabsNames('Advanced')), + 'Developer section should be hidden in production mode.' ); } else { - foreach ($this->groups as $group) { - \PHPUnit\Framework\Assert::assertTrue( - $configEdit->getForm()->isGroupVisible('dev', $group), - sprintf('%s group should be visible in developer mode.', $group) - ); - } \PHPUnit\Framework\Assert::assertTrue( - $configEdit->getForm()->isGroupVisible('dev', 'debug'), - 'Debug group should be visible in developer mode.' + in_array('Developer', $configEdit->getTabs()->getSubTabsNames('Advanced')), + 'Developer section should be not hidden in developer or default mode.' ); } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Registration.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Registration.php index 0952ebf46d711..c1bab0ae68897 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Registration.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Registration.php @@ -19,7 +19,7 @@ class Registration extends Block * * @var string */ - protected $createAccountButton = '[data-bind*="createAccount"] input'; + protected $createAccountButton = 'input[data-bind*="Create an Account"]'; /** * Click 'Create an Account' button and wait until button will be not visible. diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml index 4052e1f732975..5e08ad3097ed3 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml @@ -198,6 +198,7 @@ <data name="tag" xsi:type="string">severity:S0</data> <data name="products/0" xsi:type="string">catalogProductSimple::default</data> <data name="customer/dataset" xsi:type="string">default</data> + <data name="customerPassword" xsi:type="string">12312Qa.</data> <data name="checkoutMethod" xsi:type="string">register</data> <data name="shippingAddress/dataset" xsi:type="string">UK_address_2</data> <data name="billingAddress/dataset" xsi:type="string">UK_address_without_email</data> @@ -207,7 +208,7 @@ <item name="grandTotal" xsi:type="string">565.00</item> </data> <data name="payment/method" xsi:type="string">checkmo</data> - <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> + <constraint name="Magento\Customer\Test\Constraint\AssertCustomerRedirectToDashboard" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> </variation> <variation name="OnePageCheckoutTestVariation9" summary="One Page Checkout Products with different shipping/billing address and Tier Prices" ticketId="MAGETWO-42604"> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/CreateCustomerAccountStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/CreateCustomerAccountStep.php index 816659284a93d..13e4cfb195f9d 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/CreateCustomerAccountStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/CreateCustomerAccountStep.php @@ -7,7 +7,9 @@ namespace Magento\Checkout\Test\TestStep; use Magento\Checkout\Test\Page\CheckoutOnepageSuccess; +use Magento\Customer\Test\Page\CustomerAccountCreate; use Magento\Mtf\TestStep\TestStepInterface; +use Magento\Mtf\Fixture\FixtureFactory; /** * Create customer account on checkout one page success after place order. @@ -15,7 +17,7 @@ class CreateCustomerAccountStep implements TestStepInterface { /** - * Checkout one page success. + * "Success One Page Checkout" Storefront page. * * @var CheckoutOnepageSuccess */ @@ -28,15 +30,47 @@ class CreateCustomerAccountStep implements TestStepInterface */ private $checkoutMethod; + /** + * Fixture factory. + * + * @var FixtureFactory + */ + private $fixtureFactory; + + /** + * "Create New Customer Account" Storefront page. + * + * @var CustomerAccountCreate + */ + private $customerAccountCreate; + + /** + * Customer specifies this password while registration. + * + * @var string + */ + private $customerPassword; + /** * @constructor * @param CheckoutOnepageSuccess $checkoutOnepageSuccess * @param string $checkoutMethod + * @param FixtureFactory $fixtureFactory + * @param CustomerAccountCreate $customerAccountCreate + * @param null|string $customerPassword */ - public function __construct(CheckoutOnepageSuccess $checkoutOnepageSuccess, $checkoutMethod) - { + public function __construct( + CheckoutOnepageSuccess $checkoutOnepageSuccess, + $checkoutMethod, + FixtureFactory $fixtureFactory, + CustomerAccountCreate $customerAccountCreate, + $customerPassword = null + ) { $this->checkoutOnepageSuccess = $checkoutOnepageSuccess; $this->checkoutMethod = $checkoutMethod; + $this->fixtureFactory = $fixtureFactory; + $this->customerAccountCreate = $customerAccountCreate; + $this->customerPassword = $customerPassword; } /** @@ -48,6 +82,17 @@ public function run() { if ($this->checkoutMethod === 'register') { $this->checkoutOnepageSuccess->getRegistrationBlock()->createAccount(); + + $customerFixture = $this->fixtureFactory->createByCode( + 'customer', + [ + 'data' => [ + 'password' => $this->customerPassword, + 'password_confirmation' => $this->customerPassword, + ], + ] + ); + $this->customerAccountCreate->getRegisterForm()->registerCustomer($customerFixture); } } } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeAddressInterface.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeAddressInterface.php similarity index 85% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeAddressInterface.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeAddressInterface.php index ed085b13bc720..d792adae9b786 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeAddressInterface.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeAddressInterface.php @@ -4,8 +4,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); -namespace Magento\Wonderland\Api\Data; +namespace Magento\TestModuleExtensionAttributes\Api\Data; use Magento\Framework\Api\ExtensibleDataInterface; @@ -55,14 +56,14 @@ public function getCustomerId(); /** * Get region * - * @return \Magento\Wonderland\Api\Data\FakeRegionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionInterface|null */ public function getRegion(); /** * Get region * - * @return \Magento\Wonderland\Api\Data\FakeRegionInterface[]|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionInterface[]|null */ public function getRegions(); @@ -174,17 +175,17 @@ public function isDefaultBilling(); /** * Retrieve existing extension attributes object or create a new one. * - * @return \Magento\Wonderland\Api\Data\FakeAddressExtensionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressExtensionInterface|null */ public function getExtensionAttributes(); /** * Set an extension attributes object. * - * @param \Magento\Wonderland\Api\Data\FakeAddressExtensionInterface $extensionAttributes + * @param \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressExtensionInterface $extensionAttributes * @return $this */ public function setExtensionAttributes( - \Magento\Wonderland\Api\Data\FakeAddressExtensionInterface $extensionAttributes + \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressExtensionInterface $extensionAttributes ); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Api/Data/FakeAttributeMetadataInterface.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeAttributeMetadataInterface.php similarity index 94% rename from dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Api/Data/FakeAttributeMetadataInterface.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeAttributeMetadataInterface.php index 9f183be7e5d36..6cd7d2e212adf 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Api/Data/FakeAttributeMetadataInterface.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeAttributeMetadataInterface.php @@ -3,8 +3,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); -namespace Magento\Wonderland\Api\Data; +namespace Magento\TestModuleExtensionAttributes\Api\Data; /** * Customer attribute metadata interface. diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Api/Data/FakeCustomerInterface.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeCustomerInterface.php similarity index 83% rename from dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Api/Data/FakeCustomerInterface.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeCustomerInterface.php index 1cb6336866474..63c32869941e2 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Api/Data/FakeCustomerInterface.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeCustomerInterface.php @@ -3,7 +3,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Wonderland\Api\Data; +declare(strict_types=1); + +namespace Magento\TestModuleExtensionAttributes\Api\Data; /** * Customer interface. @@ -98,17 +100,17 @@ public function setPrefix($prefix); /** * Retrieve existing extension attributes object or create a new one. * - * @return \Magento\Wonderland\Api\Data\FakeCustomerExtensionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerExtensionInterface|null */ public function getExtensionAttributes(); /** * Set an extension attributes object. * - * @param \Magento\Wonderland\Api\Data\FakeCustomerExtensionInterface $extensionAttributes + * @param \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerExtensionInterface $extensionAttributes * @return $this */ public function setExtensionAttributes( - \Magento\Wonderland\Api\Data\FakeCustomerExtensionInterface $extensionAttributes + \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerExtensionInterface $extensionAttributes ); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeExtensibleOneInterface.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeExtensibleOneInterface.php similarity index 80% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeExtensibleOneInterface.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeExtensibleOneInterface.php index 086c28b1e52af..c1178d2867e8f 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeExtensibleOneInterface.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeExtensibleOneInterface.php @@ -4,8 +4,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); -namespace Magento\Wonderland\Api\Data; +namespace Magento\TestModuleExtensionAttributes\Api\Data; use Magento\Framework\Api\ExtensibleDataInterface; diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeExtensibleTwoInterface.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeExtensibleTwoInterface.php similarity index 85% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeExtensibleTwoInterface.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeExtensibleTwoInterface.php index 79adec87b9f1d..c740e3ec07bed 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeExtensibleTwoInterface.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeExtensibleTwoInterface.php @@ -4,8 +4,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); -namespace Magento\Wonderland\Api\Data; +namespace Magento\TestModuleExtensionAttributes\Api\Data; use Magento\Framework\Api\ExtensibleDataInterface; diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeRegionInterface.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeRegionInterface.php similarity index 72% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeRegionInterface.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeRegionInterface.php index 20784a289360a..57a08f1fbd216 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeRegionInterface.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Api/Data/FakeRegionInterface.php @@ -4,7 +4,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Wonderland\Api\Data; +declare(strict_types=1); + +namespace Magento\TestModuleExtensionAttributes\Api\Data; use Magento\Framework\Api\ExtensibleDataInterface; @@ -45,17 +47,17 @@ public function getRegionId(); /** * Retrieve existing extension attributes object or create a new one. * - * @return \Magento\Wonderland\Api\Data\FakeRegionExtensionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtensionInterface|null */ public function getExtensionAttributes(); /** * Set an extension attributes object. * - * @param \Magento\Wonderland\Api\Data\FakeRegionExtensionInterface $extensionAttributes + * @param \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtensionInterface $extensionAttributes * @return $this */ public function setExtensionAttributes( - \Magento\Wonderland\Api\Data\FakeRegionExtensionInterface $extensionAttributes + \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtensionInterface $extensionAttributes ); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeAddress.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeAddress.php similarity index 85% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeAddress.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeAddress.php index bc5413964c234..a2a177bc5b9d0 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeAddress.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeAddress.php @@ -4,10 +4,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Wonderland\Model\Data; +declare(strict_types=1); + +namespace Magento\TestModuleExtensionAttributes\Model\Data; use Magento\Framework\Api\AbstractExtensibleObject; -use Magento\Wonderland\Api\Data\FakeAddressInterface; +use Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressInterface; class FakeAddress extends AbstractExtensibleObject implements FakeAddressInterface { @@ -34,7 +36,7 @@ public function getCustomerId() /** * Get region * - * @return \Magento\Wonderland\Model\Data\FakeRegion|null + * @return \Magento\TestModuleExtensionAttributes\Model\Data\FakeRegion|null */ public function getRegion() { @@ -44,7 +46,7 @@ public function getRegion() /** * Get region * - * @return \Magento\Wonderland\Model\Data\FakeRegion[]|null + * @return \Magento\TestModuleExtensionAttributes\Model\Data\FakeRegion[]|null */ public function getRegions() { @@ -194,7 +196,7 @@ public function isDefaultShipping() /** * {@inheritdoc} * - * @return \Magento\Wonderland\Api\Data\FakeAddressExtensionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressExtensionInterface|null */ public function getExtensionAttributes() { @@ -214,11 +216,11 @@ public function isDefaultBilling() /** * {@inheritdoc} * - * @param \Magento\Wonderland\Api\Data\FakeAddressExtensionInterface $extensionAttributes + * @param \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressExtensionInterface $extensionAttributes * @return $this */ public function setExtensionAttributes( - \Magento\Wonderland\Api\Data\FakeAddressExtensionInterface $extensionAttributes + \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressExtensionInterface $extensionAttributes ) { return $this->_setExtensionAttributes($extensionAttributes); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/FakeAttributeMetadata.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeAttributeMetadata.php similarity index 91% rename from dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/FakeAttributeMetadata.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeAttributeMetadata.php index 293f238b24adf..ea50342a01d7f 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/FakeAttributeMetadata.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeAttributeMetadata.php @@ -3,14 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); -namespace Magento\Wonderland\Api\Model; +namespace Magento\TestModuleExtensionAttributes\Model\Data; /** * Customer attribute metadata class. */ class FakeAttributeMetadata extends \Magento\Framework\Api\AbstractSimpleObject implements - \Magento\Wonderland\Api\Data\FakeAttributeMetadataInterface + \Magento\TestModuleExtensionAttributes\Api\Data\FakeAttributeMetadataInterface { /** * {@inheritdoc} diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/FakeCustomer.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeCustomer.php similarity index 83% rename from dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/FakeCustomer.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeCustomer.php index 0f533ebf83bcc..c2396374ba073 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/FakeCustomer.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeCustomer.php @@ -3,26 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); -namespace Magento\Wonderland\Api\Model; +namespace Magento\TestModuleExtensionAttributes\Model\Data; /** * Class Customer * */ class FakeCustomer extends \Magento\Framework\Api\AbstractExtensibleObject implements - \Magento\Wonderland\Api\Data\FakeCustomerInterface + \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerInterface { - /** - * Get customer id - * - * @return int|null - */ - public function getId() - { - return $this->_get(self::ID); - } - /** * Get email address * @@ -44,23 +35,23 @@ public function getFirstname() } /** - * Get last name + * Get customer id * - * @return string + * @return int|null */ - public function getLastname() + public function getId() { - return $this->_get(self::LASTNAME); + return $this->_get(self::ID); } /** - * Get prefix + * Get last name * - * @return string|null + * @return string */ - public function getPrefix() + public function getLastname() { - return $this->_get(self::PREFIX); + return $this->_get(self::LASTNAME); } /** @@ -107,6 +98,16 @@ public function setLastname($lastname) return $this->setData(self::LASTNAME, $lastname); } + /** + * Get prefix + * + * @return string|null + */ + public function getPrefix() + { + return $this->_get(self::PREFIX); + } + /** * Set prefix * @@ -121,7 +122,7 @@ public function setPrefix($prefix) /** * {@inheritdoc} * - * @return \Magento\Wonderland\Api\Data\FakeCustomerExtensionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerExtensionInterface|null */ public function getExtensionAttributes() { @@ -131,11 +132,11 @@ public function getExtensionAttributes() /** * {@inheritdoc} * - * @param \Magento\Wonderland\Api\Data\FakeCustomerExtensionInterface $extensionAttributes + * @param \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerExtensionInterface $extensionAttributes * @return $this */ public function setExtensionAttributes( - \Magento\Wonderland\Api\Data\FakeCustomerExtensionInterface $extensionAttributes + \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerExtensionInterface $extensionAttributes ) { return $this->_setExtensionAttributes($extensionAttributes); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeExtensibleOne.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeExtensibleOne.php similarity index 51% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeExtensibleOne.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeExtensibleOne.php index a4d5152990409..1bbd48020bcfc 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeExtensibleOne.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeExtensibleOne.php @@ -4,9 +4,11 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Wonderland\Model\Data; +declare(strict_types=1); -use Magento\Wonderland\Api\Data\FakeExtensibleOneInterface; +namespace Magento\TestModuleExtensionAttributes\Model\Data; + +use Magento\TestModuleExtensionAttributes\Api\Data\FakeExtensibleOneInterface; class FakeExtensibleOne implements FakeExtensibleOneInterface { diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeExtensibleTwo.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeExtensibleTwo.php similarity index 71% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeExtensibleTwo.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeExtensibleTwo.php index 70ea680162a41..3064b884616ed 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeExtensibleTwo.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeExtensibleTwo.php @@ -4,10 +4,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Wonderland\Model\Data; +declare(strict_types=1); + +namespace Magento\TestModuleExtensionAttributes\Model\Data; use Magento\Framework\Api\AbstractExtensibleObject; -use Magento\Wonderland\Api\Data\FakeExtensibleTwoInterface; +use Magento\TestModuleExtensionAttributes\Api\Data\FakeExtensibleTwoInterface; class FakeExtensibleTwo extends AbstractExtensibleObject implements FakeExtensibleTwoInterface { diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeRegion.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeRegion.php similarity index 68% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeRegion.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeRegion.php index 7ee12ce5e3a3b..ff3dbecbb8a7c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/Data/FakeRegion.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/Data/FakeRegion.php @@ -4,11 +4,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Wonderland\Model\Data; +declare(strict_types=1); +namespace Magento\TestModuleExtensionAttributes\Model\Data; + +use Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionInterface; use Magento\Framework\Api\AbstractExtensibleObject; -class FakeRegion extends AbstractExtensibleObject implements \Magento\Wonderland\Api\Data\FakeRegionInterface +class FakeRegion extends AbstractExtensibleObject implements FakeRegionInterface { /** * Get region @@ -43,7 +46,7 @@ public function getRegionId() /** * {@inheritdoc} * - * @return \Magento\Wonderland\Api\Data\FakeRegionExtensionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtensionInterface|null */ public function getExtensionAttributes() { @@ -53,11 +56,11 @@ public function getExtensionAttributes() /** * {@inheritdoc} * - * @param \Magento\Wonderland\Api\Data\FakeRegionExtensionInterface $extensionAttributes + * @param \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtensionInterface $extensionAttributes * @return $this */ public function setExtensionAttributes( - \Magento\Wonderland\Api\Data\FakeRegionExtensionInterface $extensionAttributes + \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtensionInterface $extensionAttributes ) { return $this->_setExtensionAttributes($extensionAttributes); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/FakeAddress.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeAddress.php similarity index 85% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/FakeAddress.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeAddress.php index 2b657ffc25839..36c2aabd72037 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/FakeAddress.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeAddress.php @@ -4,10 +4,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Wonderland\Model; +declare(strict_types=1); + +namespace Magento\TestModuleExtensionAttributes\Model; use Magento\Framework\Model\AbstractExtensibleModel; -use Magento\Wonderland\Api\Data\FakeAddressInterface; +use Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressInterface; class FakeAddress extends AbstractExtensibleModel implements FakeAddressInterface { @@ -34,7 +36,7 @@ public function getCustomerId() /** * Get region * - * @return \Magento\Wonderland\Api\Data\FakeRegionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionInterface|null */ public function getRegion() { @@ -44,7 +46,7 @@ public function getRegion() /** * Get region * - * @return \Magento\Wonderland\Api\Data\FakeRegionInterface[]|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionInterface[]|null */ public function getRegions() { @@ -204,7 +206,7 @@ public function isDefaultBilling() /** * {@inheritdoc} * - * @return \Magento\Wonderland\Api\Data\FakeAddressExtensionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressExtensionInterface|null */ public function getExtensionAttributes() { @@ -214,11 +216,11 @@ public function getExtensionAttributes() /** * {@inheritdoc} * - * @param \Magento\Wonderland\Api\Data\FakeAddressExtensionInterface $extensionAttributes + * @param \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressExtensionInterface $extensionAttributes * @return $this */ public function setExtensionAttributes( - \Magento\Wonderland\Api\Data\FakeAddressExtensionInterface $extensionAttributes + \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressExtensionInterface $extensionAttributes ) { return $this->_setExtensionAttributes($extensionAttributes); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/Data/FakeAttributeMetadata.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeAttributeMetadata.php similarity index 91% rename from dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/Data/FakeAttributeMetadata.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeAttributeMetadata.php index 2efe9f353c4df..ae791de4e0943 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/Data/FakeAttributeMetadata.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeAttributeMetadata.php @@ -3,14 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); -namespace Magento\Wonderland\Model\Data; +namespace Magento\TestModuleExtensionAttributes\Api\Model; /** * Customer attribute metadata class. */ class FakeAttributeMetadata extends \Magento\Framework\Api\AbstractSimpleObject implements - \Magento\Wonderland\Api\Data\FakeAttributeMetadataInterface + \Magento\TestModuleExtensionAttributes\Api\Data\FakeAttributeMetadataInterface { /** * {@inheritdoc} diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/Data/FakeCustomer.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeCustomer.php similarity index 83% rename from dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/Data/FakeCustomer.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeCustomer.php index 38022ef213875..64ff041179b71 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/_files/Magento/Wonderland/Model/Data/FakeCustomer.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeCustomer.php @@ -3,16 +3,27 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); -namespace Magento\Wonderland\Model\Data; +namespace Magento\TestModuleExtensionAttributes\Api\Model; /** * Class Customer * */ class FakeCustomer extends \Magento\Framework\Api\AbstractExtensibleObject implements - \Magento\Wonderland\Api\Data\FakeCustomerInterface + \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerInterface { + /** + * Get customer id + * + * @return int|null + */ + public function getId() + { + return $this->_get(self::ID); + } + /** * Get email address * @@ -34,23 +45,23 @@ public function getFirstname() } /** - * Get customer id + * Get last name * - * @return int|null + * @return string */ - public function getId() + public function getLastname() { - return $this->_get(self::ID); + return $this->_get(self::LASTNAME); } /** - * Get last name + * Get prefix * - * @return string + * @return string|null */ - public function getLastname() + public function getPrefix() { - return $this->_get(self::LASTNAME); + return $this->_get(self::PREFIX); } /** @@ -97,16 +108,6 @@ public function setLastname($lastname) return $this->setData(self::LASTNAME, $lastname); } - /** - * Get prefix - * - * @return string|null - */ - public function getPrefix() - { - return $this->_get(self::PREFIX); - } - /** * Set prefix * @@ -121,7 +122,7 @@ public function setPrefix($prefix) /** * {@inheritdoc} * - * @return \Magento\Wonderland\Api\Data\FakeCustomerExtensionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerExtensionInterface|null */ public function getExtensionAttributes() { @@ -131,11 +132,11 @@ public function getExtensionAttributes() /** * {@inheritdoc} * - * @param \Magento\Wonderland\Api\Data\FakeCustomerExtensionInterface $extensionAttributes + * @param \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerExtensionInterface $extensionAttributes * @return $this */ public function setExtensionAttributes( - \Magento\Wonderland\Api\Data\FakeCustomerExtensionInterface $extensionAttributes + \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerExtensionInterface $extensionAttributes ) { return $this->_setExtensionAttributes($extensionAttributes); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/FakeRegion.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeRegion.php similarity index 69% rename from dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/FakeRegion.php rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeRegion.php index fcadfc36deea7..aee30887fc341 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Model/FakeRegion.php +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/Model/FakeRegion.php @@ -4,10 +4,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Wonderland\Model; +declare(strict_types=1); + +namespace Magento\TestModuleExtensionAttributes\Model; use Magento\Framework\Model\AbstractExtensibleModel; -use Magento\Wonderland\Api\Data\FakeRegionInterface; +use Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionInterface; class FakeRegion extends AbstractExtensibleModel implements FakeRegionInterface { @@ -44,7 +46,7 @@ public function getRegionId() /** * {@inheritdoc} * - * @return \Magento\Wonderland\Api\Data\FakeRegionExtensionInterface|null + * @return \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtensionInterface|null */ public function getExtensionAttributes() { @@ -54,11 +56,11 @@ public function getExtensionAttributes() /** * {@inheritdoc} * - * @param \Magento\Wonderland\Api\Data\FakeRegionExtensionInterface $extensionAttributes + * @param \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtensionInterface $extensionAttributes * @return $this */ public function setExtensionAttributes( - \Magento\Wonderland\Api\Data\FakeRegionExtensionInterface $extensionAttributes + \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtensionInterface $extensionAttributes ) { return $this->_setExtensionAttributes($extensionAttributes); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/etc/extension_attributes.xml b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/etc/extension_attributes.xml similarity index 97% rename from dev/tests/integration/testsuite/Magento/Framework/Api/etc/extension_attributes.xml rename to dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/etc/extension_attributes.xml index f8162d54c1ad1..afe722cfac11e 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/etc/extension_attributes.xml +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/etc/extension_attributes.xml @@ -4,7 +4,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ ---> + --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd"> <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface"> @@ -33,7 +33,7 @@ </attribute> </extension_attributes> - <extension_attributes for="Magento\Wonderland\Api\Data\FakeCustomerInterface"> + <extension_attributes for="Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerInterface"> <attribute code="test_group_code" type="string"> <join reference_table="customer_group" join_on_field="group_id" diff --git a/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/etc/module.xml new file mode 100644 index 0000000000000..8f885b1d9a2a8 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestModuleExtensionAttributes" /> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/registration.php b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/registration.php new file mode 100644 index 0000000000000..2077708c02415 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleExtensionAttributes/registration.php @@ -0,0 +1,13 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleExtensionAttributes') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleExtensionAttributes', __DIR__); +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/SourceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/SourceTest.php index 77d6b44749943..4280e9dc8915c 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/SourceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/SourceTest.php @@ -97,6 +97,21 @@ public function testReindexEntitiesForConfigurableProduct() $result = $connection->fetchAll($select); $this->assertCount(0, $result); + + /** @var \Magento\Catalog\Model\Product $product1 **/ + $product1 = $productRepository->getById(10); + $product1->setStatus(Status::STATUS_ENABLED)->setWebsiteIds([]); + $productRepository->save($product1); + + /** @var \Magento\Catalog\Model\Product $product2 **/ + $product2 = $productRepository->getById(20); + $product2->setStatus(Status::STATUS_ENABLED); + $productRepository->save($product2); + + $statusSelect = clone $select; + $statusSelect->reset(\Magento\Framework\DB\Select::COLUMNS) + ->columns(new \Magento\Framework\DB\Sql\Expression('COUNT(*)')); + $this->assertEquals(1, $connection->fetchOne($statusSelect)); } /** diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php index 6da582195a823..bbcbc40dc6640 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php @@ -38,23 +38,33 @@ class DeleteFilesTest extends \PHPUnit\Framework\TestCase */ private $fileName = 'magento_small_image.jpg'; + /** + * @var \Magento\Framework\Filesystem + */ + private $filesystem; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + /** * @inheritdoc */ protected function setUp() { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $directoryName = 'directory1'; - $filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); + $this->filesystem = $this->objectManager->get(\Magento\Framework\Filesystem::class); /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ - $this->imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); - $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->imagesHelper = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot() . '/' . $directoryName; $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); $filePath = $this->fullDirectoryPath . DIRECTORY_SEPARATOR . $this->fileName; $fixtureDir = realpath(__DIR__ . '/../../../../../Catalog/_files'); copy($fixtureDir . '/' . $this->fileName, $filePath); - $this->model = $objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles::class); + $this->model = $this->objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles::class); } /** @@ -98,6 +108,30 @@ public function testExecuteWithWrongFileName() ); } + /** + * Execute method with correct directory path and file name to check that files under linked media directory + * can be removed. + * + * @return void + * @magentoDataFixture Magento/Cms/_files/linked_media.php + */ + public function testExecuteWithLinkedMedia() + { + $directoryName = 'linked_media'; + $fullDirectoryPath = $this->filesystem->getDirectoryRead(DirectoryList::PUB) + ->getAbsolutePath() . DIRECTORY_SEPARATOR . $directoryName; + $filePath = $fullDirectoryPath . DIRECTORY_SEPARATOR . $this->fileName; + $fixtureDir = realpath(__DIR__ . '/../../../../../Catalog/_files'); + copy($fixtureDir . '/' . $this->fileName, $filePath); + + $wysiwygDir = $this->mediaDirectory->getAbsolutePath() . '/wysiwyg'; + $this->model->getRequest()->setMethod('POST') + ->setPostValue('files', [$this->imagesHelper->idEncode($this->fileName)]); + $this->model->getStorage()->getSession()->setCurrentPath($wysiwygDir); + $this->model->execute(); + $this->assertFalse(is_file($fullDirectoryPath . DIRECTORY_SEPARATOR . $this->fileName)); + } + /** * @inheritdoc */ diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php index 2b59963b21dca..8e30e85541a42 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php @@ -33,14 +33,19 @@ class DeleteFolderTest extends \PHPUnit\Framework\TestCase */ private $fullDirectoryPath; + /** + * @var \Magento\Framework\Filesystem + */ + private $filesystem; + /** * @inheritdoc */ protected function setUp() { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); - $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); + $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ $this->imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot(); @@ -52,6 +57,7 @@ protected function setUp() * can be removed. * * @return void + * @magentoAppIsolation enabled */ public function testExecute() { @@ -71,6 +77,29 @@ public function testExecute() ); } + /** + * Execute method with correct directory path to check that directories under linked media directory + * can be removed. + * + * @magentoDataFixture Magento/Cms/_files/linked_media.php + */ + public function testExecuteWithLinkedMedia() + { + $linkedDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::PUB); + $linkedDirectoryPath = $this->filesystem->getDirectoryRead(DirectoryList::PUB) + ->getAbsolutePath() . 'linked_media'; + $directoryName = 'NewDirectory'; + + $linkedDirectory->create( + $linkedDirectory->getRelativePath($linkedDirectoryPath . DIRECTORY_SEPARATOR . $directoryName) + ); + $this->model->getRequest()->setParams( + ['node' => $this->imagesHelper->idEncode('wysiwyg' . DIRECTORY_SEPARATOR . $directoryName)] + ); + $this->model->execute(); + $this->assertFalse(is_dir($linkedDirectoryPath . DIRECTORY_SEPARATOR . $directoryName)); + } + /** * Execute method with traversal directory path to check that there is no ability to remove folder which is not * under media directory. diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php index b20b5a04a2a50..0c74f18e9c44a 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php @@ -33,17 +33,27 @@ class NewFolderTest extends \PHPUnit\Framework\TestCase */ private $dirName= 'NewDirectory'; + /** + * @var \Magento\Framework\Filesystem + */ + private $filesystem; + + /** + * @var \Magento\Cms\Helper\Wysiwyg\Images + */ + private $imagesHelper; + /** * @inheritdoc */ protected function setUp() { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); - $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ - $imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); - $this->fullDirectoryPath = $imagesHelper->getStorageRoot(); + $this->imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot(); $this->model = $objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\NewFolder::class); } @@ -68,6 +78,25 @@ public function testExecute() ); } + /** + * Execute method with correct directory path to check that new folder can be created under WYSIWYG media directory. + * + * @magentoDataFixture Magento/Cms/_files/linked_media.php + */ + public function testExecuteWithLinkedMedia() + { + $linkedDirectoryPath = $this->filesystem->getDirectoryRead(DirectoryList::PUB) + ->getAbsolutePath() . 'linked_media'; + $this->model->getRequest()->setMethod('POST') + ->setPostValue('name', $this->dirName); + $this->model->getStorage() + ->getSession() + ->setCurrentPath($this->fullDirectoryPath . DIRECTORY_SEPARATOR . 'wysiwyg'); + $this->model->execute(); + + $this->assertTrue(is_dir($linkedDirectoryPath . DIRECTORY_SEPARATOR . $this->dirName)); + } + /** * Execute method with traversal directory path to check that there is no ability to create new folder not * under media directory. diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php index ba2527e3e449e..534eb3db35b3f 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php @@ -33,22 +33,32 @@ class UploadTest extends \PHPUnit\Framework\TestCase */ private $fileName = 'magento_small_image.jpg'; + /** + * @var \Magento\Framework\Filesystem + */ + private $filesystem; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + /** * @inheritdoc */ protected function setUp() { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $directoryName = 'directory1'; - $filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); + $this->filesystem = $this->objectManager->get(\Magento\Framework\Filesystem::class); /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ - $imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); - $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $imagesHelper = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); $this->fullDirectoryPath = $imagesHelper->getStorageRoot() . DIRECTORY_SEPARATOR . $directoryName; $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); - $this->model = $objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\Upload::class); + $this->model = $this->objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\Upload::class); $fixtureDir = realpath(__DIR__ . '/../../../../../Catalog/_files'); - $tmpFile = __DIR__ . DIRECTORY_SEPARATOR . $this->fileName; + $tmpFile = $this->filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath() . $this->fileName; copy($fixtureDir . DIRECTORY_SEPARATOR . $this->fileName, $tmpFile); $_FILES = [ 'image' => [ @@ -66,6 +76,7 @@ protected function setUp() * located under WYSIWYG media. * * @return void + * @magentoAppIsolation enabled */ public function testExecute() { @@ -82,6 +93,25 @@ public function testExecute() ); } + /** + * Execute method with correct directory path and file name to check that file can be uploaded to the directory + * located under linked folder. + * + * @return void + * @magentoDataFixture Magento/Cms/_files/linked_media.php + */ + public function testExecuteWithLinkedMedia() + { + $directoryName = 'linked_media'; + $fullDirectoryPath = $this->filesystem->getDirectoryRead(DirectoryList::PUB) + ->getAbsolutePath() . DIRECTORY_SEPARATOR . $directoryName; + $wysiwygDir = $this->mediaDirectory->getAbsolutePath() . '/wysiwyg'; + $this->model->getRequest()->setParams(['type' => 'image/png']); + $this->model->getStorage()->getSession()->setCurrentPath($wysiwygDir); + $this->model->execute(); + $this->assertTrue(is_file($fullDirectoryPath . DIRECTORY_SEPARATOR . $this->fileName)); + } + /** * Execute method with traversal directory path to check that there is no ability to create file not * under media directory. diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/linked_media.php b/dev/tests/integration/testsuite/Magento/Cms/_files/linked_media.php new file mode 100644 index 0000000000000..5921f871aaeb2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/_files/linked_media.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$directoryName = 'linked_media'; +/** @var \Magento\Framework\Filesystem $filesystem */ +$filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); +$fullDirectoryPath = $filesystem->getDirectoryRead(Magento\Framework\App\Filesystem\DirectoryList::PUB) + ->getAbsolutePath() . $directoryName; +$mediaDirectory = $filesystem->getDirectoryWrite(Magento\Framework\App\Filesystem\DirectoryList::MEDIA); + +$wysiwygDir = $mediaDirectory->getAbsolutePath() . 'wysiwyg'; +$mediaDirectory->delete($wysiwygDir); +if (!is_dir($fullDirectoryPath)) { + mkdir($fullDirectoryPath); +} +if (is_dir($fullDirectoryPath) && !is_dir($wysiwygDir)) { + symlink($fullDirectoryPath, $wysiwygDir); +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/linked_media_rollback.php b/dev/tests/integration/testsuite/Magento/Cms/_files/linked_media_rollback.php new file mode 100644 index 0000000000000..803fa67aff9de --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/_files/linked_media_rollback.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$directoryName = 'linked_media'; +/** @var \Magento\Framework\Filesystem $filesystem */ +$filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); +$pubDir = $filesystem->getDirectoryWrite(Magento\Framework\App\Filesystem\DirectoryList::PUB); +$fullDirectoryPath = $pubDir->getAbsolutePath() . DIRECTORY_SEPARATOR . $directoryName; +$mediaDirectory = $filesystem->getDirectoryWrite(Magento\Framework\App\Filesystem\DirectoryList::MEDIA); +$wysiwygDir = $mediaDirectory->getAbsolutePath() . 'wysiwyg'; +if (is_link($wysiwygDir)) { + unlink($wysiwygDir); +} +if (is_dir($fullDirectoryPath)) { + $pubDir->delete($directoryName); +} diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ProductTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ProductTest.php new file mode 100644 index 0000000000000..223c9fbe708e2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ProductTest.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\ConfigurableProduct\Model; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Api\ProductRepositoryInterface; + +class ProductTest extends \PHPUnit\Framework\TestCase +{ + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testGetIdentities() + { + $productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); + $confProduct = $productRepository->get('configurable'); + $simple10Product = $productRepository->get('simple_10'); + $simple20Product = $productRepository->get('simple_20'); + + $this->assertEmpty(array_diff($confProduct->getIdentities(), $simple10Product->getIdentities())); + $this->assertEmpty(array_diff($confProduct->getIdentities(), $simple20Product->getIdentities())); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Api/AddressRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Api/AddressRepositoryTest.php index be2f07ce5de62..cf6e82639767e 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Api/AddressRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Api/AddressRepositoryTest.php @@ -160,6 +160,13 @@ public function testSaveNewAddress() $expectedNewAddress = $this->_expectedAddresses[1]; $expectedNewAddress->setId($savedAddress->getId()); $expectedNewAddress->setRegion($this->_expectedAddresses[1]->getRegion()); + + $this->assertEquals($expectedNewAddress->getExtensionAttributes(), $savedAddress->getExtensionAttributes()); + $this->assertEquals( + $expectedNewAddress->getRegion()->getExtensionAttributes(), + $savedAddress->getRegion()->getExtensionAttributes() + ); + $this->assertEquals($expectedNewAddress, $savedAddress); } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/View/PersonalInfoTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/View/PersonalInfoTest.php index 4ba1b44010c34..8d82ad94dfab4 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/View/PersonalInfoTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/View/PersonalInfoTest.php @@ -119,7 +119,10 @@ public function testGetCustomer() public function testGetCustomerEmpty() { - $this->assertEquals($this->_createCustomer(), $this->_block->getCustomer()); + $expectedCustomer = $this->createCustomerAndAddToBackendSession(); + $actualCustomer = $this->_block->getCustomer(); + $this->assertEquals($expectedCustomer->getExtensionAttributes(), $actualCustomer->getExtensionAttributes()); + $this->assertEquals($expectedCustomer, $actualCustomer); } /** @@ -133,7 +136,7 @@ public function testGetGroupName() public function testGetGroupNameNull() { - $this->_createCustomer(); + $this->createCustomerAndAddToBackendSession(); $this->assertNull($this->_block->getGroupName()); } @@ -243,7 +246,7 @@ public function testGetBillingAddressHtml() public function testGetBillingAddressHtmlNoDefaultAddress() { - $this->_createCustomer(); + $this->createCustomerAndAddToBackendSession(); $this->assertEquals( __('The customer does not have default billing address.'), $this->_block->getBillingAddressHtml() @@ -253,7 +256,7 @@ public function testGetBillingAddressHtmlNoDefaultAddress() /** * @return \Magento\Customer\Api\Data\CustomerInterface */ - private function _createCustomer() + private function createCustomerAndAddToBackendSession() { /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ $customer = $this->_customerFactory->create()->setFirstname( diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php index b06ddf48d9e64..4257b5a928505 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php @@ -166,6 +166,13 @@ public function testSaveNewAddress() $expectedNewAddress = $this->_expectedAddresses[1]; $expectedNewAddress->setId($savedAddress->getId()); $expectedNewAddress->setRegion($this->_expectedAddresses[1]->getRegion()); + + $this->assertEquals($expectedNewAddress->getExtensionAttributes(), $savedAddress->getExtensionAttributes()); + $this->assertEquals( + $expectedNewAddress->getRegion()->getExtensionAttributes(), + $savedAddress->getRegion()->getExtensionAttributes() + ); + $this->assertEquals($expectedNewAddress, $savedAddress); } diff --git a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php index 3b006b5044337..3bef48d8801f7 100644 --- a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php +++ b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php @@ -95,6 +95,7 @@ public function setUp() // Preconditions $this->mode->enableDeveloperMode(); + $this->enableDebugging(); if (file_exists($this->getDebuggerLogPath())) { unlink($this->getDebuggerLogPath()); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/AbstractExtensibleObjectTest.php b/dev/tests/integration/testsuite/Magento/Framework/Api/AbstractExtensibleObjectTest.php index 2aaaae9dd38f2..51e66eec676ea 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/AbstractExtensibleObjectTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Api/AbstractExtensibleObjectTest.php @@ -5,6 +5,9 @@ */ namespace Magento\Framework\Api; +use Magento\TestModuleExtensionAttributes\Model\Data\FakeRegionFactory; +use Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtension; + /** * Test for \Magento\Framework\Api\AbstractExtensibleObject */ @@ -15,16 +18,14 @@ class AbstractExtensibleObjectTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $autoloadWrapper = \Magento\Framework\Autoload\AutoloaderRegistry::getAutoloader(); - $autoloadWrapper->addPsr4('Magento\\Wonderland\\', realpath(__DIR__ . '/_files/Magento/Wonderland')); $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $this->_objectManager->configure( [ 'preferences' => [ - \Magento\Wonderland\Api\Data\FakeAddressInterface::class => - \Magento\Wonderland\Model\FakeAddress::class, - \Magento\Wonderland\Api\Data\FakeRegionInterface::class => - \Magento\Wonderland\Model\FakeRegion::class, + \Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressInterface::class => + \Magento\TestModuleExtensionAttributes\Model\FakeAddress::class, + \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionInterface::class => + \Magento\TestModuleExtensionAttributes\Model\FakeRegion::class, ], ] ); @@ -41,30 +42,30 @@ public function testExtensionAttributes($expectedDataBefore, $expectedDataAfter) { /** @var \Magento\Framework\Api\ExtensionAttributesFactory $regionExtensionFactory */ $regionExtensionFactory = $this->_objectManager->get(\Magento\Framework\Api\ExtensionAttributesFactory::class); - /** @var \Magento\Wonderland\Model\Data\FakeRegionFactory $regionFactory */ - $regionFactory = $this->_objectManager->get(\Magento\Wonderland\Model\Data\FakeRegionFactory::class); + /** @var FakeRegionFactory $regionFactory */ + $regionFactory = $this->_objectManager->get(FakeRegionFactory::class); - /** @var \Magento\Wonderland\Model\Data\FakeRegion $region */ + /** @var \Magento\TestModuleExtensionAttributes\Model\Data\FakeRegion $region */ $region = $regionFactory->create(); $regionCode = 'test_code'; - /** @var \Magento\Wonderland\Model\Data\FakeRegionExtensionInterface $regionExtension */ + /** @var \Magento\TestModuleExtensionAttributes\Model\Data\FakeRegionExtensionInterface $regionExtension */ $regionExtension = $regionExtensionFactory->create( - \Magento\Wonderland\Model\Data\FakeRegion::class, + \Magento\TestModuleExtensionAttributes\Model\Data\FakeRegion::class, ['data' => $expectedDataBefore] ); $region->setRegionCode($regionCode)->setExtensionAttributes($regionExtension); - $this->assertInstanceOf(\Magento\Wonderland\Model\Data\FakeRegion::class, $region); + $this->assertInstanceOf(\Magento\TestModuleExtensionAttributes\Model\Data\FakeRegion::class, $region); $extensionAttributes = $region->getExtensionAttributes(); - $this->assertInstanceOf(\Magento\Wonderland\Api\Data\FakeRegionExtension::class, $extensionAttributes); + $this->assertInstanceOf(FakeRegionExtension::class, $extensionAttributes); $this->assertEquals($expectedDataBefore, $extensionAttributes->__toArray()); $this->assertEquals($regionCode, $region->getRegionCode()); $regionCode = 'changed_test_code'; $region->setExtensionAttributes( $regionExtensionFactory->create( - \Magento\Wonderland\Model\Data\FakeRegion::class, + \Magento\TestModuleExtensionAttributes\Model\Data\FakeRegion::class, ['data' => $expectedDataAfter] ) )->setRegionCode($regionCode); // change $regionCode to test AbstractExtensibleObject::setData diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/ExtensionAttributesGenerationTest.php b/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/ExtensionAttributesGenerationTest.php new file mode 100644 index 0000000000000..991998cf59167 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/ExtensionAttributesGenerationTest.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Framework\Api\ExtensionAttribute; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\Data\ProductExtensionInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Api\Data\CustomerExtensionInterface; + +/** + * Class to test the automatic generation of extension attributes object. + */ +class ExtensionAttributesGenerationTest extends \PHPUnit\Framework\TestCase +{ + /** + * Test extension attributes generation for extensible models. + * + * Make sure that extension attributes object is not empty after instantiation + * of objects inherited from @see \Magento\Framework\Model\AbstractExtensibleModel. + * + * In addition, verify that empty objects are not generated for complex extension attributes. + */ + public function testAttributeObjectGenerationForExtensibleModel() + { + /** @var \Magento\Framework\ObjectManagerInterface */ + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var ProductInterface $product */ + $product = $objectManager->get(ProductInterface::class); + + $extensionAttributes = $product->getExtensionAttributes(); + $this->assertInstanceOf(ProductExtensionInterface::class, $extensionAttributes); + + $stockItemExtensionAttribute = $extensionAttributes->getStockItem(); + $this->assertNull($stockItemExtensionAttribute); + } + + /** + * Test extension attributes generation for extensible objects. + * + * Make sure that extension attributes object is not empty after instantiation + * of objects inherited from @see \Magento\Framework\Api\AbstractExtensibleObject + */ + public function testAttributeObjectGenerationForExtensibleObject() + { + /** @var \Magento\Framework\ObjectManagerInterface */ + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var CustomerInterface $customer */ + $customer = $objectManager->get(CustomerInterface::class); + + $extensionAttributes = $customer->getExtensionAttributes(); + $this->assertInstanceOf(CustomerExtensionInterface::class, $extensionAttributes); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttributesFactoryTest.php b/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttributesFactoryTest.php index c0cb63e30f69d..1c86bd594c6a0 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttributesFactoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttributesFactoryTest.php @@ -12,8 +12,6 @@ class ExtensionAttributesFactoryTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $autoloadWrapper = \Magento\Framework\Autoload\AutoloaderRegistry::getAutoloader(); - $autoloadWrapper->addPsr4('Magento\\Wonderland\\', realpath(__DIR__ . '/_files/Magento/Wonderland')); /** @var \Magento\Framework\ObjectManagerInterface */ $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); @@ -36,7 +34,7 @@ public function testCreateThrowExceptionIfInterfaceNotImplemented() */ public function testCreateThrowExceptionIfInterfaceNotOverridden() { - $this->factory->create(\Magento\Wonderland\Model\Data\FakeExtensibleOne::class); + $this->factory->create(\Magento\TestModuleExtensionAttributes\Model\Data\FakeExtensibleOne::class); } /** @@ -44,14 +42,14 @@ public function testCreateThrowExceptionIfInterfaceNotOverridden() */ public function testCreateThrowExceptionIfReturnIsIncorrect() { - $this->factory->create(\Magento\Wonderland\Model\Data\FakeExtensibleTwo::class); + $this->factory->create(\Magento\TestModuleExtensionAttributes\Model\Data\FakeExtensibleTwo::class); } public function testCreate() { $this->assertInstanceOf( - \Magento\Wonderland\Api\Data\FakeRegionExtension::class, - $this->factory->create(\Magento\Wonderland\Model\Data\FakeRegion::class) + \Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionExtension::class, + $this->factory->create(\Magento\TestModuleExtensionAttributes\Model\Data\FakeRegion::class) ); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/CopyTest.php b/dev/tests/integration/testsuite/Magento/Framework/DataObject/CopyTest.php index dce6880a1dbab..e333fb4bc42cf 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/CopyTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/DataObject/CopyTest.php @@ -39,8 +39,6 @@ public function testCopyFieldset() public function testCopyFieldsetWithExtensionAttributes() { - $autoloadWrapper = \Magento\Framework\Autoload\AutoloaderRegistry::getAutoloader(); - $autoloadWrapper->addPsr4('Magento\\Wonderland\\', realpath(__DIR__ . '/_files/Magento/Wonderland')); $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $fieldsetConfigMock = $this->getMockBuilder(\Magento\Framework\DataObject\Copy\Config::class) @@ -74,20 +72,22 @@ public function testCopyFieldsetWithExtensionAttributes() /** @var \Magento\Framework\Api\DataObjectHelper $dataObjectHelper */ $dataObjectHelper = $objectManager->get(\Magento\Framework\Api\DataObjectHelper::class); - /** @var \Magento\Wonderland\Model\Data\FakeCustomerFactory $customerFactory */ - $customerFactory = $objectManager->get(\Magento\Wonderland\Model\Data\FakeCustomerFactory::class); - /** @var \Magento\Wonderland\Api\Data\CustomerInterface $source */ + /** @var \Magento\TestModuleExtensionAttributes\Model\Data\FakeCustomerFactory $customerFactory */ + $customerFactory = $objectManager->get( + \Magento\TestModuleExtensionAttributes\Model\Data\FakeCustomerFactory::class + ); + /** @var \Magento\TestModuleExtensionAttributes\Api\Data\CustomerInterface $source */ $source = $customerFactory->create(); $dataObjectHelper->populateWithArray( $source, $dataWithExtraField, - \Magento\Wonderland\Api\Data\FakeCustomerInterface::class + \Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerInterface::class ); - /** @var \Magento\Wonderland\Api\Data\CustomerInterface $target */ + /** @var \Magento\TestModuleExtensionAttributes\Api\Data\CustomerInterface $target */ $target = $customerFactory->create(); $target = $service->copyFieldsetToTarget($fieldset, $aspect, $source, $target); - $this->assertInstanceOf(\Magento\Wonderland\Api\Data\FakeCustomerInterface::class, $target); + $this->assertInstanceOf(\Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerInterface::class, $target); $this->assertNull( $target->getEmail(), "Email should not be set because it is not defined in the fieldset." @@ -106,8 +106,6 @@ public function testCopyFieldsetWithExtensionAttributes() public function testCopyFieldsetWithAbstractSimpleObject() { - $autoloadWrapper = \Magento\Framework\Autoload\AutoloaderRegistry::getAutoloader(); - $autoloadWrapper->addPsr4('Magento\\Wonderland\\', realpath(__DIR__ . '/_files/Magento/Wonderland')); $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $fieldset = 'sales_copy_order'; @@ -130,13 +128,13 @@ public function testCopyFieldsetWithAbstractSimpleObject() ->method('getFieldSet') ->willReturn($data); - $source = $objectManager->get(\Magento\Wonderland\Model\Data\FakeAttributeMetadata::class); + $source = $objectManager->get(\Magento\TestModuleExtensionAttributes\Model\Data\FakeAttributeMetadata::class); $source->setStoreLabel('storeLabel'); $source->setFrontendLabel('frontendLabel'); $source->setAttributeCode('attributeCode'); $source->setNote('note'); - $target = $objectManager->get(\Magento\Wonderland\Model\Data\FakeAttributeMetadata::class); + $target = $objectManager->get(\Magento\TestModuleExtensionAttributes\Model\Data\FakeAttributeMetadata::class); $expectedTarget = $source; $this->assertEquals( diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php index 36539da724a23..ec1538e950c12 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php @@ -523,7 +523,6 @@ public function testAdvancedSearchDateField($rangeFilter, $expectedRecordsCount) */ public function testAdvancedSearchCompositeProductWithOutOfStockOption() { - $this->markTestSkipped('MAGETWO-71445: configurable product created incorrectly - children not linked'). /** @var Attribute $attribute */ $attribute = $this->objectManager->get(Attribute::class) ->loadByCode(Product::ENTITY, 'test_configurable'); diff --git a/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php b/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php index c9640ceba87d2..4473d31047d4b 100644 --- a/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php +++ b/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php @@ -7,60 +7,66 @@ namespace Magento\Rule\Model\Condition\Sql; use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory; +use Magento\CatalogWidget\Model\RuleFactory; +use Magento\CatalogWidget\Model\Rule\Condition\Combine as CombineCondition; +use Magento\CatalogWidget\Model\Rule\Condition\Product as ProductCondition; +/** + * Test for Magento\Rule\Model\Condition\Sql\Builder + */ class BuilderTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Rule\Model\Condition\Sql\Builder + * @var Builder */ private $model; protected function setUp() { - $this->model = Bootstrap::getObjectManager()->create(\Magento\Rule\Model\Condition\Sql\Builder::class); + $this->model = Bootstrap::getObjectManager()->create(Builder::class); } - public function testAttachConditionToCollection() + /** + * @return void + */ + public function testAttachConditionToCollection(): void { - /** @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory */ - $collectionFactory = Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class - ); - /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ + /** @var ProductCollectionFactory $collectionFactory */ + $collectionFactory = Bootstrap::getObjectManager()->create(ProductCollectionFactory::class); $collection = $collectionFactory->create(); - /** @var \Magento\CatalogWidget\Model\RuleFactory $ruleFactory */ - $ruleFactory = Bootstrap::getObjectManager()->create(\Magento\CatalogWidget\Model\RuleFactory::class); - /** @var \Magento\CatalogWidget\Model\Rule $rule */ + /** @var RuleFactory $ruleFactory */ + $ruleFactory = Bootstrap::getObjectManager()->create(RuleFactory::class); $rule = $ruleFactory->create(); $ruleConditionArray = [ 'conditions' => [ '1' => [ - 'type' => \Magento\CatalogWidget\Model\Rule\Condition\Combine::class, + 'type' => CombineCondition::class, 'aggregator' => 'all', 'value' => '1', - 'new_child' => '' + 'new_child' => '', ], '1--1' => [ - 'type' => \Magento\CatalogWidget\Model\Rule\Condition\Product::class, + 'type' => ProductCondition::class, 'attribute' => 'category_ids', 'operator' => '==', - 'value' => '3' + 'value' => '3', ], '1--2' => [ - 'type' => \Magento\CatalogWidget\Model\Rule\Condition\Product::class, + 'type' => ProductCondition::class, 'attribute' => 'special_to_date', 'operator' => '==', - 'value' => '2017-09-15' + 'value' => '2017-09-15', ], - ] + ], ]; $rule->loadPost($ruleConditionArray); $this->model->attachConditionToCollection($collection, $rule->getConditions()); - $whereString = 'WHERE (category_id IN (\'3\')))) AND(IFNULL(`e`.`entity_id`, 0) = \'2017-09-15\') ))'; - $this->assertNotFalse(strpos($collection->getSelectSql(true), $whereString)); + $whereString = "/\(category_id IN \('3'\).+\(IFNULL\(`e`\.`entity_id`,.+\) = '2017-09-15'\)/"; + $this->assertNotFalse(preg_match($whereString, $collection->getSelectSql(true))); } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Api/OrderCustomerDelegateInterfaceTest.php b/dev/tests/integration/testsuite/Magento/Sales/Api/OrderCustomerDelegateInterfaceTest.php new file mode 100644 index 0000000000000..459e8fdbf5087 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/Api/OrderCustomerDelegateInterfaceTest.php @@ -0,0 +1,181 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Sales\Api; + +use Magento\Customer\Api\AccountManagementInterface; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Api\Data\CustomerInterfaceFactory; +use Magento\Sales\Api\Data\OrderAddressInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\OrderFactory; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Test for Magento\Sales\Api\OrderCustomerDelegateInterface class. + * + * @magentoAppIsolation enabled + */ +class OrderCustomerDelegateInterfaceTest extends TestCase +{ + /** + * @var OrderCustomerDelegateInterface + */ + private $delegate; + + /** + * @var OrderRepositoryInterface + */ + private $orderRepository; + + /** + * @var CustomerInterfaceFactory + */ + private $customerFactory; + + /** + * @var AccountManagementInterface + */ + private $accountManagement; + + /** + * @var OrderFactory + */ + private $orderFactory; + + /** + * {@inheritdoc} + */ + protected function setUp() + { + $this->delegate = Bootstrap::getObjectManager()->get( + OrderCustomerDelegateInterface::class + ); + $this->orderRepository = Bootstrap::getObjectManager()->get( + OrderRepositoryInterface::class + ); + $this->customerFactory = Bootstrap::getObjectManager()->get( + CustomerInterfaceFactory::class + ); + $this->accountManagement = Bootstrap::getObjectManager()->get( + AccountManagementInterface::class + ); + $this->orderFactory = Bootstrap::getObjectManager()->get( + OrderFactory::class + ); + } + + /** + * @param OrderAddressInterface $orderAddress + * @param AddressInterface $address + * + * @return void + */ + private function compareAddresses( + OrderAddressInterface $orderAddress, + AddressInterface $address + ): void { + $this->assertEquals( + $orderAddress->getFirstname(), + $address->getFirstname() + ); + $this->assertEquals( + $orderAddress->getLastname(), + $address->getLastname() + ); + $this->assertEquals( + $orderAddress->getCompany(), + $address->getCompany() + ); + $this->assertEquals( + $orderAddress->getStreet(), + $address->getStreet() + ); + $this->assertEquals( + $orderAddress->getCity(), + $address->getCity() + ); + if (!$address->getRegionId()) { + $this->assertEmpty($address->getRegionId()); + } else { + $this->assertEquals( + $orderAddress->getRegionId(), + $address->getRegionId() + ); + } + $this->assertEquals( + $orderAddress->getPostcode(), + $address->getPostcode() + ); + $this->assertEquals( + $orderAddress->getCountryId(), + $address->getCountryId() + ); + $this->assertEquals( + $orderAddress->getTelephone(), + $address->getTelephone() + ); + } + + /** + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + * @magentoDataFixture Magento/Sales/_files/order.php + * @return void + */ + public function testDelegateNew(): void + { + $orderAutoincrementId = '100000001'; + /** @var Order $orderModel */ + $orderModel = $this->orderFactory->create(); + $orderModel->loadByIncrementId($orderAutoincrementId); + $orderId = (int)$orderModel->getId(); + unset($orderModel); + + $this->delegate->delegateNew($orderId); + + //Saving new customer with prepared data from order. + /** @var CustomerInterface $customer */ + $customer = $this->customerFactory->create(); + $customer->setWebsiteId(1) + ->setEmail('customer_order_delegate@example.com') + ->setGroupId(1) + ->setStoreId(1) + ->setPrefix('Mr.') + ->setFirstname('John') + ->setMiddlename('A') + ->setLastname('Smith') + ->setSuffix('Esq.') + ->setTaxvat('12') + ->setGender(0); + $createdCustomer = $this->accountManagement->createAccount( + $customer, + '12345abcD' + ); + + //Testing that addresses from order and the order itself are assigned + //to customer. + $order = $this->orderRepository->get($orderId); + $this->assertCount(2, $createdCustomer->getAddresses()); + $this->assertNotNull($createdCustomer->getDefaultBilling()); + $this->assertNotNull($createdCustomer->getDefaultShipping()); + foreach ($createdCustomer->getAddresses() as $address) { + $this->assertTrue( + $address->isDefaultBilling() || $address->isDefaultShipping() + ); + if ($address->isDefaultBilling()) { + $this->compareAddresses($order->getBillingAddress(), $address); + } elseif ($address->isDefaultShipping()) { + $this->compareAddresses($order->getShippingAddress(), $address); + } + } + + $this->assertEquals($order->getCustomerId(), $createdCustomer->getId()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Ui/Component/ConfigurationTest.php b/dev/tests/integration/testsuite/Magento/Ui/Component/ConfigurationTest.php index 8a8ba9db564a2..826afe82e2bb6 100644 --- a/dev/tests/integration/testsuite/Magento/Ui/Component/ConfigurationTest.php +++ b/dev/tests/integration/testsuite/Magento/Ui/Component/ConfigurationTest.php @@ -7,13 +7,17 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Component\ComponentFile; +use Magento\Framework\Component\ComponentRegistrar; use Magento\Framework\Component\DirSearch; +use Magento\Framework\Exception\FileSystemException; use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Directory\ReadInterface; use Magento\TestFramework\Helper\Bootstrap; use Magento\Ui\Config\Reader\DefinitionMap; -use Magento\Framework\Component\ComponentRegistrar; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class ConfigurationTest extends \PHPUnit\Framework\TestCase { /** @@ -26,6 +30,11 @@ class ConfigurationTest extends \PHPUnit\Framework\TestCase */ private $appDir; + /** + * @var ReadInterface + */ + private $rootDir; + /** * @var \DOMDocument */ @@ -67,6 +76,7 @@ public function setUp() /** @var Filesystem $filesystem */ $filesystem = $objectManager->create(Filesystem::class); $this->appDir = $filesystem->getDirectoryRead(DirectoryList::APP); + $this->rootDir = $filesystem->getDirectoryRead(DirectoryList::ROOT); } /** @@ -84,7 +94,14 @@ public function testConfiguration() /** @var ComponentFile $file */ foreach ($uiConfigurationFiles as $file) { $this->currentFile = $file; - $content = $this->appDir->readFile($this->appDir->getRelativePath($file->getFullPath())); + $fullPath = $file->getFullPath(); + // by default search files in `app` directory but Magento can be installed via composer + // or some modules can be in `vendor` directory (like bundled extensions) + try { + $content = $this->appDir->readFile($this->appDir->getRelativePath($fullPath)); + } catch (FileSystemException $e) { + $content = $this->rootDir->readFile($this->rootDir->getRelativePath($fullPath)); + } $this->assertConfigurationSemantic($this->getDom($content), $result); } if (!empty($result)) { diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Bundle/adminhtml/js/components/bundle-checkbox.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Bundle/adminhtml/js/components/bundle-checkbox.test.js index 88c28961d97e1..06206efa2bb3c 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Bundle/adminhtml/js/components/bundle-checkbox.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Bundle/adminhtml/js/components/bundle-checkbox.test.js @@ -56,7 +56,6 @@ define(['Magento_Bundle/js/components/bundle-checkbox', 'uiRegistry'], function unit.changeType('select'); expect(unit.prefer).toBe('radio'); - expect(unit.clearValues).toHaveBeenCalled(); }); }); }); diff --git a/dev/tests/static/framework/Magento/TestFramework/Dependency/DiRule.php b/dev/tests/static/framework/Magento/TestFramework/Dependency/DiRule.php index 2b4497c544ab7..cdaa49e8d37fb 100644 --- a/dev/tests/static/framework/Magento/TestFramework/Dependency/DiRule.php +++ b/dev/tests/static/framework/Magento/TestFramework/Dependency/DiRule.php @@ -40,7 +40,7 @@ private function getPattern() { if ($this->pattern === null) { $this->pattern = '~\b(?<class>(?<module>(' - . implode('_|', Files::init()->getNamespaces()) + . implode('[_\\\\]|', Files::init()->getNamespaces()) . '[_\\\\])[a-zA-Z0-9]+)[a-zA-Z0-9_\\\\]*)\b~'; } diff --git a/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php b/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php index 2df84c579ccbc..800bba2a880bd 100644 --- a/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php +++ b/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php @@ -116,7 +116,7 @@ private function caseClassesAndIdentifiers($currentModule, $file, &$contents) { $pattern = '~\b(?<class>(?<module>(' . implode( - '_|', + '[_\\\\]|', Files::init()->getNamespaces() ) . '[_\\\\])[a-zA-Z0-9]+)' diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ClassesTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ClassesTest.php index b754536fd5b18..6d627574a3a18 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ClassesTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ClassesTest.php @@ -11,20 +11,40 @@ use Magento\Framework\Component\ComponentRegistrar; use Magento\Framework\App\Utility\Files; +/** + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + */ class ClassesTest extends \PHPUnit\Framework\TestCase { + /** + * @var ComponentRegistrar + */ + private $componentRegistrar; + /** * List of already found classes to avoid checking them over and over again * * @var array */ - protected static $_existingClasses = []; + private $existingClasses = []; - protected static $_keywordsBlacklist = ["String", "Array", "Boolean", "Element"]; + /** + * @var array + */ + private static $keywordsBlacklist = ["String", "Array", "Boolean", "Element"]; - protected static $_namespaceBlacklist = null; + /** + * @var array|null + */ + private $referenceBlackList = null; - protected static $_referenceBlackList = null; + /** + * Set Up + */ + protected function setUp() + { + $this->componentRegistrar = new ComponentRegistrar(); + } public function testPhpFiles() { @@ -69,9 +89,9 @@ function ($file) { $classes ); - $this->_collectResourceHelpersPhp($contents, $classes); + $this->collectResourceHelpersPhp($contents, $classes); - $this->_assertClassesExist($classes, $file); + $this->assertClassesExist($classes, $file); }, Files::init()->getPhpFiles( Files::INCLUDE_APP_CODE @@ -89,8 +109,9 @@ function ($file) { * * @param string $contents * @param array &$classes + * @return void */ - protected function _collectResourceHelpersPhp($contents, &$classes) + private function collectResourceHelpersPhp(string $contents, array &$classes): void { $regex = '/(?:\:\:|\->)getResourceHelper\(\s*\'([a-z\d\\\\]+)\'\s*\)/ix'; $matches = Classes::getAllMatches($contents, $regex); @@ -108,7 +129,7 @@ public function testConfigFiles() */ function ($path) { $classes = Classes::collectClassesInConfig(simplexml_load_file($path)); - $this->_assertClassesExist($classes, $path); + $this->assertClassesExist($classes, $path); }, Files::init()->getMainConfigFiles() ); @@ -145,7 +166,7 @@ function ($path) { } $classes = array_merge($classes, Classes::collectLayoutClasses($xml)); - $this->_assertClassesExist(array_unique($classes), $path); + $this->assertClassesExist(array_unique($classes), $path); }, Files::init()->getLayoutFiles() ); @@ -158,10 +179,12 @@ function ($path) { * Suppressing "unused variable" because of the "catch" block * * @param array $classes + * @param string $path + * @return void * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ - protected function _assertClassesExist($classes, $path) + private function assertClassesExist(array $classes, string $path): void { if (!$classes) { return; @@ -177,7 +200,7 @@ protected function _assertClassesExist($classes, $path) } else { $this->assertTrue( isset( - self::$_existingClasses[$class] + $this->existingClasses[$class] ) || Files::init()->classFileExists( $class ) || Classes::isVirtual( @@ -187,7 +210,7 @@ protected function _assertClassesExist($classes, $path) ) ); } - self::$_existingClasses[$class] = 1; + $this->existingClasses[$class] = 1; } catch (\PHPUnit\Framework\AssertionFailedError $e) { $badClasses[] = '\\' . $class; } @@ -230,7 +253,7 @@ function ($file) { $classParts = explode(' ', $classNameMatch[0]); $className = array_pop($classParts); - $this->_assertClassNamespace($file, $relativePath, $contents, $className); + $this->assertClassNamespace($file, $relativePath, $contents, $className); }, Files::init()->getPhpFiles() ); @@ -244,8 +267,9 @@ function ($file) { * @param string $relativePath * @param string $contents * @param string $className + * @return void */ - protected function _assertClassNamespace($file, $relativePath, $contents, $className) + private function assertClassNamespace(string $file, string $relativePath, string $contents, string $className): void { $namespacePattern = '/(Magento|Zend)\/[a-zA-Z]+[^\.]+/'; $formalPattern = '/^namespace\s[a-zA-Z]+(\\\\[a-zA-Z0-9]+)*/m'; @@ -349,7 +373,7 @@ function ($file) { $vendorClasses = array_filter($vendorClasses, 'strlen'); $vendorClasses = $this->referenceBlacklistFilter($vendorClasses); if (!empty($vendorClasses)) { - $this->_assertClassesExist($vendorClasses, $file); + $this->assertClassesExist($vendorClasses, $file); } if (!empty($result3['exception']) && $result3['exception'][0] != "") { @@ -368,7 +392,7 @@ function ($file) { $badClasses = $this->referenceBlacklistFilter($badClasses); $badClasses = $this->removeSpecialCases($badClasses, $file, $contents, $namespacePath); - $this->_assertClassReferences($badClasses, $file); + $this->assertClassReferences($badClasses, $file); }, Files::init()->getPhpFiles() ); @@ -377,10 +401,11 @@ function ($file) { /** * Remove alias class name references that have been identified as 'bad'. * - * @param $aliasClasses - * @param $badClasses + * @param array $aliasClasses + * @param array $badClasses + * @return array */ - protected function handleAliasClasses($aliasClasses, $badClasses) + private function handleAliasClasses(array $aliasClasses, array $badClasses): array { foreach ($aliasClasses as $aliasClass) { foreach ($badClasses as $badClass) { @@ -389,32 +414,44 @@ protected function handleAliasClasses($aliasClasses, $badClasses) } } } + return $badClasses; } /** * This function is to remove legacy code usages according to _files/blacklist/reference.txt - * @param $classes + * + * @param array $classes * @return array */ - protected function referenceBlacklistFilter($classes) + private function referenceBlacklistFilter(array $classes): array { // exceptions made for the files from the blacklist - self::_setReferenceBlacklist(); + $classes = $this->getReferenceBlacklist(); foreach ($classes as $class) { - if (in_array($class, self::$_referenceBlackList)) { + if (in_array($class, $this->referenceBlackList)) { unset($classes[array_search($class, $classes)]); } } + return $classes; } - protected function _setReferenceBlacklist() + /** + * Returns array of class names from black list. + * + * @return array + */ + private function getReferenceBlacklist(): array { - if (!isset(self::$_referenceBlackList)) { - $blackList = file(__DIR__ . '/_files/blacklist/reference.txt', FILE_IGNORE_NEW_LINES); - self::$_referenceBlackList = $blackList; + if (!isset($this->referenceBlackList)) { + $this->referenceBlackList = file( + __DIR__ . '/_files/blacklist/reference.txt', + FILE_IGNORE_NEW_LINES + ); } + + return $this->referenceBlackList; } /** @@ -426,18 +463,21 @@ protected function _setReferenceBlacklist() * @param string $namespacePath * @return array */ - protected function removeSpecialCases($badClasses, $file, $contents, $namespacePath) + private function removeSpecialCases(array $badClasses, string $file, string $contents, string $namespacePath): array { foreach ($badClasses as $badClass) { // Remove valid usages of Magento modules from the list // for example: 'Magento_Sales::actions_edit' - if (preg_match('/Magento_[A-Z0-9][a-z0-9]*/', $badClass)) { - unset($badClasses[array_search($badClass, $badClasses)]); - continue; + if (preg_match('/^[A-Z][a-z]+_[A-Z0-9][a-z0-9]+$/', $badClass)) { + $moduleDir = $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $badClass); + if ($moduleDir !== null) { + unset($badClasses[array_search($badClass, $badClasses)]); + continue; + } } // Remove usage of key words such as "Array", "String", and "Boolean" - if (in_array($badClass, self::$_keywordsBlacklist)) { + if (in_array($badClass, self::$keywordsBlacklist)) { unset($badClasses[array_search($badClass, $badClasses)]); continue; } @@ -468,6 +508,7 @@ protected function removeSpecialCases($badClasses, $file, $contents, $namespaceP continue; } } + return $badClasses; } @@ -482,12 +523,11 @@ protected function removeSpecialCases($badClasses, $file, $contents, $namespaceP */ private function removeSpecialCasesNonFullyQualifiedClassNames($namespacePath, &$badClasses, $badClass) { - $componentRegistrar = new ComponentRegistrar(); $namespaceParts = explode('/', $namespacePath); $moduleDir = null; if (isset($namespaceParts[1])) { $moduleName = array_shift($namespaceParts) . '_' . array_shift($namespaceParts); - $moduleDir = $componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName); + $moduleDir = $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName); } if ($moduleDir) { $fullPath = $moduleDir . '/' . implode('/', $namespaceParts) . '/' . @@ -505,7 +545,7 @@ private function removeSpecialCasesNonFullyQualifiedClassNames($namespacePath, & unset($badClasses[array_search($badClass, $badClasses)]); return true; } else { - return $this->removeSpecialCasesForAllOthers($componentRegistrar, $namespacePath, $badClass, $badClasses); + return $this->removeSpecialCasesForAllOthers($namespacePath, $badClass, $badClasses); } } @@ -516,11 +556,10 @@ private function removeSpecialCasesNonFullyQualifiedClassNames($namespacePath, & * @param string $badClass * @return null|string */ - protected function getLibraryDirByPath($namespacePath, $badClass) + private function getLibraryDirByPath(string $namespacePath, string $badClass) { $libraryDir = null; $fullPath = null; - $componentRegistrar = new ComponentRegistrar(); $namespaceParts = explode('/', $namespacePath); if (isset($namespaceParts[1]) && $namespaceParts[1]) { $vendor = array_shift($namespaceParts); @@ -529,34 +568,43 @@ protected function getLibraryDirByPath($namespacePath, $badClass) $subLib = $namespaceParts[0]; $subLib = strtolower(preg_replace('/(.)([A-Z])/', "$1-$2", $subLib)); $libraryName = $vendor . '/' . $lib . '-' . $subLib; - $libraryDir = $componentRegistrar->getPath(ComponentRegistrar::LIBRARY, strtolower($libraryName)); + $libraryDir = $this->componentRegistrar->getPath( + ComponentRegistrar::LIBRARY, + strtolower($libraryName) + ); if ($libraryDir) { array_shift($namespaceParts); } else { $libraryName = $vendor . '/' . $lib; - $libraryDir = $componentRegistrar->getPath(ComponentRegistrar::LIBRARY, strtolower($libraryName)); + $libraryDir = $this->componentRegistrar->getPath( + ComponentRegistrar::LIBRARY, + strtolower($libraryName) + ); } } else { $lib = strtolower(preg_replace('/(.)([A-Z])/', "$1-$2", $lib)); $libraryName = $vendor . '/' . $lib; - $libraryDir = $componentRegistrar->getPath(ComponentRegistrar::LIBRARY, strtolower($libraryName)); + $libraryDir = $this->componentRegistrar->getPath( + ComponentRegistrar::LIBRARY, + strtolower($libraryName) + ); } } if ($libraryDir) { $fullPath = $libraryDir . '/' . implode('/', $namespaceParts) . '/' . str_replace('\\', '/', $badClass) . '.php'; } + return $fullPath; } /** - * @param ComponentRegistrar $componentRegistrar * @param string $namespacePath * @param string $badClass * @param array $badClasses * @return bool */ - private function removeSpecialCasesForAllOthers($componentRegistrar, $namespacePath, $badClass, &$badClasses) + private function removeSpecialCasesForAllOthers(string $namespacePath, string $badClass, array &$badClasses): bool { // Remove usage of classes that do NOT using fully-qualified class names (possibly under same namespace) $directories = [ @@ -571,16 +619,18 @@ private function removeSpecialCasesForAllOthers($componentRegistrar, $namespaceP BP . '/dev/tests/static/testsuite/', BP . '/setup/src/', ]; - $libraryPaths = $componentRegistrar->getPaths(ComponentRegistrar::LIBRARY); + $libraryPaths = $this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY); $directories = array_merge($directories, $libraryPaths); // Full list of directories where there may be namespace classes foreach ($directories as $directory) { $fullPath = $directory . $namespacePath . '/' . str_replace('\\', '/', $badClass) . '.php'; if (file_exists($fullPath)) { unset($badClasses[array_search($badClass, $badClasses)]); + return true; } } + return false; } @@ -589,8 +639,9 @@ private function removeSpecialCasesForAllOthers($componentRegistrar, $namespaceP * * @param array $badClasses * @param string $file + * @return void */ - protected function _assertClassReferences($badClasses, $file) + private function assertClassReferences(array $badClasses, string $file): void { if (empty($badClasses)) { return; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php index c70cac369af6d..d671efe10fb6e 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php @@ -171,7 +171,9 @@ private function assertMagentoConventions($dir, $packageType, \StdClass $json) switch ($packageType) { case 'magento2-module': $xml = simplexml_load_file("$dir/etc/module.xml"); - $this->assertConsistentModuleName($xml, $json->name); + if ($this->isVendorMagento($json->name)) { + $this->assertConsistentModuleName($xml, $json->name); + } $this->assertDependsOnPhp($json->require); $this->assertPhpVersionInSync($json->name, $json->require->php); $this->assertDependsOnFramework($json->require); @@ -210,6 +212,17 @@ private function assertMagentoConventions($dir, $packageType, \StdClass $json) } } + /** + * Checks if package vendor is Magento. + * + * @param string $packageName + * @return bool + */ + private function isVendorMagento(string $packageName): bool + { + return strpos($packageName, 'magento/') === 0; + } + /** * Assert that component registrar is autoloaded in composer json * @@ -313,12 +326,24 @@ private function assertDependsOnFramework(\StdClass $json) private function assertPhpVersionInSync($name, $phpVersion) { if (isset(self::$rootJson['require']['php'])) { - $this->assertEquals( - self::$rootJson['require']['php'], - $phpVersion, - "PHP version {$phpVersion} in component {$name} is inconsistent with version " - . self::$rootJson['require']['php'] . ' in root composer.json' - ); + if ($this->isVendorMagento($name)) { + $this->assertEquals( + self::$rootJson['require']['php'], + $phpVersion, + "PHP version {$phpVersion} in component {$name} is inconsistent with version " + . self::$rootJson['require']['php'] . ' in root composer.json' + ); + } else { + $composerVersionsPattern = '{\s*\|\|?\s*}'; + $rootPhpVersions = preg_split($composerVersionsPattern, self::$rootJson['require']['php']); + $modulePhpVersions = preg_split($composerVersionsPattern, $phpVersion); + + $this->assertEmpty( + array_diff($rootPhpVersions, $modulePhpVersions), + "PHP version {$phpVersion} in component {$name} is inconsistent with version " + . self::$rootJson['require']['php'] . ' in root composer.json' + ); + } } } diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/DependencyTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/DependencyTest.php index 3e7f7804222e2..a4113abed8030 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/DependencyTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/DependencyTest.php @@ -20,6 +20,7 @@ /** * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DependencyTest extends \PHPUnit\Framework\TestCase { @@ -124,7 +125,7 @@ class DependencyTest extends \PHPUnit\Framework\TestCase * ))) * @var array */ - protected static $_mapDependencies = []; + protected static $mapDependencies = []; /** * Regex pattern for validation file path of theme @@ -410,7 +411,7 @@ private function collectDependency($dependency, $currentModule, &$undeclared) $this->_setDependencies($currentModule, $type, self::MAP_TYPE_REDUNDANT, $module); } - $this->_addDependencies($currentModule, $type, self::MAP_TYPE_FOUND, $nsModule); + $this->addDependency($currentModule, $type, self::MAP_TYPE_FOUND, $nsModule); } /** @@ -421,7 +422,7 @@ private function collectDependency($dependency, $currentModule, &$undeclared) */ public function collectRedundant() { - foreach (array_keys(self::$_mapDependencies) as $module) { + foreach (array_keys(self::$mapDependencies) as $module) { $declared = $this->_getDependencies($module, self::TYPE_HARD, self::MAP_TYPE_DECLARED); $found = array_merge( $this->_getDependencies($module, self::TYPE_HARD, self::MAP_TYPE_FOUND), @@ -440,7 +441,7 @@ public function collectRedundant() public function testRedundant() { $output = []; - foreach (array_keys(self::$_mapDependencies) as $module) { + foreach (array_keys(self::$mapDependencies) as $module) { $result = []; $redundant = $this->_getDependencies($module, self::TYPE_HARD, self::MAP_TYPE_REDUNDANT); if (count($redundant)) { @@ -687,37 +688,40 @@ protected static function _getTypes() * Converts a composer json component name into the Magento Module form * * @param string $jsonName The name of a composer json component or dependency e.g. 'magento/module-theme' + * @param array $packageModuleMap Mapping package name with module namespace. * @return string The corresponding Magento Module e.g. 'Magento\Theme' */ - protected static function convertModuleName($jsonName) + protected static function convertModuleName(string $jsonName, array $packageModuleMap): string { - if (strpos($jsonName, 'magento/module') !== false) { - $moduleName = str_replace('-', ' ', $jsonName); - $moduleName = ucwords($moduleName); - $moduleName = str_replace('module ', '', $moduleName); - $moduleName = str_replace(' ', '', $moduleName); - $moduleName = str_replace('/', '\\', $moduleName); - return $moduleName; - } elseif (strpos($jsonName, 'magento/magento') !== false || strpos($jsonName, 'magento/framework') !== false) { + if (isset($packageModuleMap[$jsonName])) { + return $packageModuleMap[$jsonName]; + } + + if (strpos($jsonName, 'magento/magento') !== false || strpos($jsonName, 'magento/framework') !== false) { $moduleName = str_replace('/', "\t", $jsonName); $moduleName = str_replace('framework-', "Framework\t", $moduleName); $moduleName = str_replace('-', ' ', $moduleName); $moduleName = ucwords($moduleName); $moduleName = str_replace("\t", '\\', $moduleName); $moduleName = str_replace(' ', '', $moduleName); + return $moduleName; } + return $jsonName; } /** - * Initialise map of dependencies + * Initialise map of dependencies. * + * @return void * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) + * @throws \Exception */ protected static function _initDependencies() { + $packageModuleMap = self::getPackageModuleMapping(); $jsonFiles = Files::init()->getComposerFiles(ComponentRegistrar::MODULE, false); foreach ($jsonFiles as $file) { $contents = file_get_contents($file); @@ -726,12 +730,13 @@ protected static function _initDependencies() throw new \Exception("Invalid Json: $file"); } $json = new \Magento\Framework\Config\Composer\Package(json_decode($contents)); - $moduleName = self::convertModuleName($json->get('name')); - self::$_mapDependencies[$moduleName] = @(self::$_mapDependencies[$moduleName] ?: []); - + $moduleName = self::convertModuleName($json->get('name'), $packageModuleMap); + if (!isset(self::$mapDependencies[$moduleName])) { + self::$mapDependencies[$moduleName] = []; + } foreach (self::_getTypes() as $type) { - if (!isset(self::$_mapDependencies[$moduleName][$type])) { - self::$_mapDependencies[$moduleName][$type] = [ + if (!isset(self::$mapDependencies[$moduleName][$type])) { + self::$mapDependencies[$moduleName][$type] = [ self::MAP_TYPE_DECLARED => [], self::MAP_TYPE_FOUND => [], self::MAP_TYPE_REDUNDANT => [], @@ -739,59 +744,86 @@ protected static function _initDependencies() } } - $require = $json->get('require'); - if (isset($require) && !empty($require)) { - foreach ($require as $requiredModule => $version) { - if (0 === strpos($requiredModule, 'magento/') - && 'magento/magento-composer-installer' != $requiredModule - ) { - $type = self::TYPE_HARD; - self::_addDependencies( - $moduleName, - $type, - self::MAP_TYPE_DECLARED, - self::convertModuleName($requiredModule) - ); - } - } - } - $suggest = $json->get('suggest'); - if (isset($suggest) && !empty($suggest)) { - foreach ($suggest as $requiredModule => $version) { - if (0 === strpos($requiredModule, 'magento/') - && 'magento/magento-composer-installer' != $requiredModule - ) { - $type = self::TYPE_SOFT; - self::_addDependencies( - $moduleName, - $type, - self::MAP_TYPE_DECLARED, - self::convertModuleName($requiredModule) - ); - } - } - } + $require = array_keys((array)$json->get('require')); + self::addDependencies($moduleName, $require, self::TYPE_HARD, $packageModuleMap); + + $suggest = array_keys((array)$json->get('suggest')); + self::addDependencies($moduleName, $suggest, self::TYPE_SOFT, $packageModuleMap); } } /** - * Add dependency map items + * Add dependencies to dependency list. * - * @param $module - * @param $type - * @param $mapType - * @param $dependencies + * @param string $moduleName + * @param array $packageNames + * @param string $type + * @param array $packageModuleMap + * + * @return void + */ + private static function addDependencies( + string $moduleName, + array $packageNames, + string $type, + array $packageModuleMap + ): void { + $packageNames = array_filter($packageNames, function ($packageName) use ($packageModuleMap) { + return isset($packageModuleMap[$packageName]) || + 0 === strpos($packageName, 'magento/') && 'magento/magento-composer-installer' != $packageName; + }); + + foreach ($packageNames as $packageName) { + self::addDependency( + $moduleName, + $type, + self::MAP_TYPE_DECLARED, + self::convertModuleName($packageName, $packageModuleMap) + ); + } + } + + /** + * Add dependency map items. + * + * @param string $module + * @param string $type + * @param string $mapType + * @param string $dependency + * + * @return void */ - protected static function _addDependencies($module, $type, $mapType, $dependencies) + private static function addDependency(string $module, string $type, string $mapType, string $dependency): void { - if (!is_array($dependencies)) { - $dependencies = [$dependencies]; + if (isset(self::$mapDependencies[$module][$type][$mapType])) { + self::$mapDependencies[$module][$type][$mapType][$dependency] = $dependency; } - foreach ($dependencies as $dependency) { - if (isset(self::$_mapDependencies[$module][$type][$mapType])) { - self::$_mapDependencies[$module][$type][$mapType][$dependency] = $dependency; + } + + /** + * Returns package name on module name mapping. + * + * @return array + * @throws \Exception + */ + private static function getPackageModuleMapping(): array + { + $jsonFiles = Files::init()->getComposerFiles(ComponentRegistrar::MODULE, false); + + $packageModuleMapping = []; + foreach ($jsonFiles as $file) { + $contents = file_get_contents($file); + $composerJson = json_decode($contents); + if (null == $composerJson) { + throw new \Exception("Invalid Json: $file"); } + $moduleXml = simplexml_load_file(dirname($file) . '/etc/module.xml'); + $moduleName = str_replace('_', '\\', (string)$moduleXml->module->attributes()->name); + $packageName = $composerJson->name; + $packageModuleMapping[$packageName] = $moduleName; } + + return $packageModuleMapping; } /** @@ -804,9 +836,10 @@ protected static function _addDependencies($module, $type, $mapType, $dependenci */ protected function _getDependencies($module, $type, $mapType) { - if (isset(self::$_mapDependencies[$module][$type][$mapType])) { - return self::$_mapDependencies[$module][$type][$mapType]; + if (isset(self::$mapDependencies[$module][$type][$mapType])) { + return self::$mapDependencies[$module][$type][$mapType]; } + return []; } @@ -823,8 +856,8 @@ protected function _setDependencies($module, $type, $mapType, $dependencies) if (!is_array($dependencies)) { $dependencies = [$dependencies]; } - if (isset(self::$_mapDependencies[$module][$type][$mapType])) { - self::$_mapDependencies[$module][$type][$mapType] = $dependencies; + if (isset(self::$mapDependencies[$module][$type][$mapType])) { + self::$mapDependencies[$module][$type][$mapType] = $dependencies; } } @@ -836,6 +869,6 @@ protected function _setDependencies($module, $type, $mapType, $dependencies) */ protected function _isFake($module) { - return isset(self::$_mapDependencies[$module]) ? false : true; + return isset(self::$mapDependencies[$module]) ? false : true; } } diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ExceptionHierarchyTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ExceptionHierarchyTest.php deleted file mode 100644 index 7556ab2c1b47c..0000000000000 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ExceptionHierarchyTest.php +++ /dev/null @@ -1,113 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Test\Integrity; - -use Magento\Framework\App\Utility\Files as UtilityFiles; - -/** - * Checks that all Exceptions inherit LocalizedException - */ -class ExceptionHierarchyTest extends \PHPUnit\Framework\TestCase -{ - /** - * @param \ReflectionClass $reflectionException - * @dataProvider isInheritedLocalizedExceptionDataProvider - */ - public function testIsInheritedLocalizedException(\ReflectionClass $reflectionException) - { - $this->assertTrue( - $reflectionException->isSubclassOf(\Magento\Framework\Exception\LocalizedException::class), - "{$reflectionException->name} is not inherited LocalizedException" - ); - } - - /** - * @return array - */ - public function isInheritedLocalizedExceptionDataProvider() - { - $files = UtilityFiles::init()->getPhpFiles(UtilityFiles::INCLUDE_APP_CODE | UtilityFiles::INCLUDE_LIBS); - $blacklistExceptions = $this->getBlacklistExceptions(); - - $data = []; - foreach ($files as $file) { - $className = $this->convertPathToClassName($file); - try { - $reflectionClass = new \ReflectionClass($className); - if ($reflectionClass->isSubclassOf('Exception') && !in_array($className, $blacklistExceptions)) { - $data[$className] = [$reflectionClass]; - } - } catch (\Exception $e) { - $this->fail("File name and class name '{$className}' is not appropriate"); - } - } - return $data; - } - - /** - * @param string $filePath - * @return string - */ - protected function convertPathToClassName($filePath) - { - $componentRegistrar = new \Magento\Framework\Component\ComponentRegistrar(); - $foundItems = null; - $moduleNamespace = null; - $foundItems = array_filter( - $componentRegistrar->getPaths(\Magento\Framework\Component\ComponentRegistrar::MODULE), - function ($item) use ($filePath) { - if (strpos($filePath, $item . '/') !== false) { - return true; - } else { - return false; - } - } - ); - if ($foundItems) { - $moduleNamespace = str_replace('_', '\\', array_keys($foundItems)[0]); - $classPath = str_replace('/', '\\', str_replace(array_shift($foundItems), '', $filePath)); - } else { - $foundItems = array_filter( - $componentRegistrar->getPaths(\Magento\Framework\Component\ComponentRegistrar::LIBRARY), - function ($item) use ($filePath) { - if (strpos($filePath, $item . '/') !== false) { - return true; - } else { - return false; - } - } - ); - $libName = array_keys($foundItems)[0]; - $libName = str_replace('framework-', 'framework/', $libName); - $namespaceParts = explode('/', $libName); - $namespaceParts = array_map( - function ($item) { - return str_replace(' ', '', ucwords(str_replace('-', ' ', $item))); - }, - $namespaceParts - ); - $moduleNamespace = implode('\\', $namespaceParts); - $classPath = str_replace('/', '\\', str_replace(array_shift($foundItems), '', $filePath)); - } - - $className = '\\' . $moduleNamespace . $classPath; - $className = str_replace('.php', '', $className); - return $className; - } - - /** - * @return array - */ - protected function getBlacklistExceptions() - { - $blacklistFiles = str_replace('\\', '/', realpath(__DIR__)) . '/_files/blacklist/exception_hierarchy*.txt'; - $exceptions = []; - foreach (glob($blacklistFiles) as $fileName) { - $exceptions = array_merge($exceptions, file($fileName, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)); - } - return $exceptions; - } -} diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt index 2348a3b974b20..8920d44e04319 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt @@ -30,18 +30,18 @@ TestSuite DbTest Model1 Model3 -\Magento\Wonderland\Api\Data\FakeRegionInterface -\Magento\Wonderland\Api\Data\FakeAddressInterface -\Magento\Wonderland\Api\Data\FakeExtensibleOneInterface -\Magento\Wonderland\Api\Data\FakeExtensibleTwoInterface -\Magento\Wonderland\Api\Data\FakeAttributeMetadataInterface -\Magento\Wonderland\Api\Data\FakeCustomerInterface -\Magento\Wonderland\Model\Data\FakeRegion -\Magento\Wonderland\Model\Data\FakeAddress -\Magento\Wonderland\Model\Data\FakeAttributeMetadata -\Magento\Wonderland\Model\Data\FakeCustomer -\Magento\Wonderland\Model\Data\FakeExtensibleOne -\Magento\Wonderland\Model\Data\FakeExtensibleTwo +\Magento\TestModuleExtensionAttributes\Api\Data\FakeRegionInterface +\Magento\TestModuleExtensionAttributes\Api\Data\FakeAddressInterface +\Magento\TestModuleExtensionAttributes\Api\Data\FakeExtensibleOneInterface +\Magento\TestModuleExtensionAttributes\Api\Data\FakeExtensibleTwoInterface +\Magento\TestModuleExtensionAttributes\Api\Data\FakeAttributeMetadataInterface +\Magento\TestModuleExtensionAttributes\Api\Data\FakeCustomerInterface +\Magento\TestModuleExtensionAttributes\Model\Data\FakeRegion +\Magento\TestModuleExtensionAttributes\Model\Data\FakeAddress +\Magento\TestModuleExtensionAttributes\Model\Data\FakeAttributeMetadata +\Magento\TestModuleExtensionAttributes\Model\Data\FakeCustomer +\Magento\TestModuleExtensionAttributes\Model\Data\FakeExtensibleOne +\Magento\TestModuleExtensionAttributes\Model\Data\FakeExtensibleTwo \Magento\Framework\Error\Processor \Magento\TestModule3\Service\V1\Entity\Parameter \Magento\TestModule3\Service\V1\Entity\ParameterBuilder @@ -120,4 +120,8 @@ DoubleColon \Magento\Mtf\Client\ElementInterface BarFactory PartialNamespace\BarFactory -Product\OptionFactory \ No newline at end of file +Product\OptionFactory +Magento_Module +Magento_Framework +Magento_TestModule +Magento_Test diff --git a/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php b/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php index 3ea43cbccd24f..7b2b94cbd0973 100644 --- a/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php +++ b/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php @@ -9,9 +9,8 @@ /** * Base Class for extensible data Objects - * @SuppressWarnings(PHPMD.NumberOfChildren) - * TODO: This class can be split into Custom attribute and Extension attribute implementation classes * + * @SuppressWarnings(PHPMD.NumberOfChildren) * @api */ abstract class AbstractExtensibleObject extends AbstractSimpleObject implements CustomAttributesDataInterface @@ -51,6 +50,9 @@ public function __construct( $this->extensionFactory = $extensionFactory; $this->attributeValueFactory = $attributeValueFactory; parent::__construct($data); + if (isset($data[self::EXTENSION_ATTRIBUTES_KEY]) && is_array($data[self::EXTENSION_ATTRIBUTES_KEY])) { + $this->populateExtensionAttributes($data[self::EXTENSION_ATTRIBUTES_KEY]); + } } /** @@ -160,9 +162,24 @@ protected function getEavAttributesCodes(\Magento\Framework\Api\MetadataServiceI */ protected function _getExtensionAttributes() { + if (!$this->_get(self::EXTENSION_ATTRIBUTES_KEY)) { + $this->populateExtensionAttributes([]); + } return $this->_get(self::EXTENSION_ATTRIBUTES_KEY); } + /** + * Instantiate extension attributes object and populate it with the provided data. + * + * @param array $extensionAttributesData + * @return void + */ + private function populateExtensionAttributes(array $extensionAttributesData = []) + { + $extensionAttributes = $this->extensionFactory->create(get_class($this), $extensionAttributesData); + $this->_setExtensionAttributes($extensionAttributes); + } + /** * Set an extension attributes object. * diff --git a/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php b/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php index 01c09a160aece..2d5d4f751f5a7 100644 --- a/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php +++ b/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php @@ -42,7 +42,7 @@ public function __construct(\Magento\Framework\ObjectManagerInterface $objectMan * * @param string $extensibleClassName * @param array $data - * @return object + * @return \Magento\Framework\Api\ExtensionAttributesInterface */ public function create($extensibleClassName, $data = []) { diff --git a/lib/internal/Magento/Framework/App/Filesystem/DirectoryResolver.php b/lib/internal/Magento/Framework/App/Filesystem/DirectoryResolver.php index 2bc76198bf37f..5ad3d888ffb57 100644 --- a/lib/internal/Magento/Framework/App/Filesystem/DirectoryResolver.php +++ b/lib/internal/Magento/Framework/App/Filesystem/DirectoryResolver.php @@ -3,8 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Framework\App\Filesystem; +use Magento\Framework\Filesystem; + /** * Magento directories resolver. */ @@ -15,12 +19,19 @@ class DirectoryResolver */ private $directoryList; + /** + * @var \Magento\Framework\Filesystem + */ + private $filesystem; + /** * @param DirectoryList $directoryList + * @param Filesystem $filesystem */ - public function __construct(DirectoryList $directoryList) + public function __construct(DirectoryList $directoryList, Filesystem $filesystem) { $this->directoryList = $directoryList; + $this->filesystem = $filesystem; } /** @@ -38,8 +49,9 @@ public function __construct(DirectoryList $directoryList) */ public function validatePath($path, $directoryConfig = DirectoryList::MEDIA) { - $realPath = realpath($path); - $root = realpath($this->directoryList->getPath($directoryConfig)); + $directory = $this->filesystem->getDirectoryWrite($directoryConfig); + $realPath = $directory->getDriver()->getRealPathSafety($path); + $root = $this->directoryList->getPath($directoryConfig); return strpos($realPath, $root) === 0; } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Filesystem/DirectoryResolverTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Filesystem/DirectoryResolverTest.php new file mode 100644 index 0000000000000..955765455df16 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Filesystem/DirectoryResolverTest.php @@ -0,0 +1,85 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\App\Test\Unit\Filesystem; + +/** + * Unit tests for the \Magento\Framework\App\Filesystem\DirectoryResolver class. + */ +class DirectoryResolverTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\App\Filesystem\DirectoryList|\PHPUnit_Framework_MockObject_MockObject + */ + private $directoryList; + + /** + * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject + */ + private $filesystem; + + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->directoryList = $this->getMockBuilder(\Magento\Framework\App\Filesystem\DirectoryList::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->filesystem = $this->getMockBuilder(\Magento\Framework\Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->directoryResolver = new \Magento\Framework\App\Filesystem\DirectoryResolver( + $this->directoryList, + $this->filesystem + ); + } + + /** + * @dataProvider validatePathDataProvider + * @param string $path + * @param bool $expectedResult + * @return void + */ + public function testValidatePath(string $path, bool $expectedResult): void + { + $rootPath = '/path/root'; + $directoryConfig = 'directory_config'; + $directory = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\WriteInterface::class) + ->setMethods(['getDriver']) + ->getMockForAbstractClass(); + $driver = $this->getMockBuilder(\Magento\Framework\Filesystem\DriverInterface::class) + ->setMethods(['getRealPathSafety']) + ->getMockForAbstractClass(); + $directory->expects($this->atLeastOnce())->method('getDriver')->willReturn($driver); + $driver->expects($this->atLeastOnce())->method('getRealPathSafety')->with($path) + ->willReturnArgument(0); + $this->filesystem->expects($this->atLeastOnce())->method('getDirectoryWrite')->with($directoryConfig) + ->willReturn($directory); + $this->directoryList->expects($this->atLeastOnce())->method('getPath')->with($directoryConfig) + ->willReturn($rootPath); + $this->assertEquals($expectedResult, $this->directoryResolver->validatePath($path, $directoryConfig)); + } + + /** + * @return array + */ + public function validatePathDataProvider() + { + return [ + ['/path/root/for/validation', true], + ['/path/invalid/for/validation', false], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php b/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php index db919c80e251c..e7ffcde03ff64 100644 --- a/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php +++ b/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php @@ -69,6 +69,9 @@ public function __construct( if (isset($data['id'])) { $this->setId($data['id']); } + if (isset($data[self::EXTENSION_ATTRIBUTES_KEY]) && is_array($data[self::EXTENSION_ATTRIBUTES_KEY])) { + $this->populateExtensionAttributes($data[self::EXTENSION_ATTRIBUTES_KEY]); + } } /** @@ -338,9 +341,24 @@ protected function _setExtensionAttributes(\Magento\Framework\Api\ExtensionAttri */ protected function _getExtensionAttributes() { + if (!$this->getData(self::EXTENSION_ATTRIBUTES_KEY)) { + $this->populateExtensionAttributes([]); + } return $this->getData(self::EXTENSION_ATTRIBUTES_KEY); } + /** + * Instantiate extension attributes object and populate it with the provided data. + * + * @param array $extensionAttributesData + * @return void + */ + private function populateExtensionAttributes(array $extensionAttributesData = []) + { + $extensionAttributes = $this->extensionAttributesFactory->create(get_class($this), $extensionAttributesData); + $this->_setExtensionAttributes($extensionAttributes); + } + /** * @inheritdoc */ diff --git a/pub/errors/default/report.phtml b/pub/errors/default/report.phtml index f907e73149d41..546b96605ec1b 100644 --- a/pub/errors/default/report.phtml +++ b/pub/errors/default/report.phtml @@ -36,25 +36,25 @@ </div> <div class="field lastname required"> <label for="lastname" class="label">Last Name</label> - <div class=control"> + <div class="control"> <input type="text" name="lastname" id="lastname" value="<?= $this->postData['lastName'] ?>" title="Last Name" class="required-entry input-text" /> </div> </div> <div class="field email required"> <label for="email_address" class="label">Email Address</label> - <div class=control"> + <div class="control"> <input type="text" name="email" id="email_address" value="<?= $this->postData['email'] ?>" title="Email Address" class="validate-email required-entry input-text" /> </div> </div> <div class="field telephone"> <label for="telephone" class="label">Telephone</label> - <div class=control"> + <div class="control"> <input type="text" name="telephone" id="telephone" value="<?= $this->postData['telephone'] ?>" title="Telephone" class="input-text" /> </div> </div> <div class="field comment"> <label for="comment" class="label">Comment</label> - <div class=control"> + <div class="control"> <textarea name="comment" cols="5" rows="3" class="textarea"><?= $this->postData['comment'] ?></textarea> </div> </div>