diff --git a/app/code/Magento/Authorizenet/Model/Authorizenet.php b/app/code/Magento/Authorizenet/Model/Authorizenet.php index 9ab3317a43bb97d950ab32196ce1f9596ba8f7e4..4408c68436707cbfae7332f32cf7d3c902b531f0 100644 --- a/app/code/Magento/Authorizenet/Model/Authorizenet.php +++ b/app/code/Magento/Authorizenet/Model/Authorizenet.php @@ -332,7 +332,7 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc ->setXCity($billing->getCity()) ->setXState($billing->getRegion()) ->setXZip($billing->getPostcode()) - ->setXCountry($billing->getCountry()) + ->setXCountry($billing->getCountryId()) ->setXPhone($billing->getTelephone()) ->setXFax($billing->getFax()) ->setXCustId($order->getCustomerId()) @@ -352,7 +352,7 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc ->setXShipToCity($shipping->getCity()) ->setXShipToState($shipping->getRegion()) ->setXShipToZip($shipping->getPostcode()) - ->setXShipToCountry($shipping->getCountry()); + ->setXShipToCountry($shipping->getCountryId()); } $request->setXPoNum($payment->getPoNumber()) diff --git a/app/code/Magento/Authorizenet/Model/Directpost/Request.php b/app/code/Magento/Authorizenet/Model/Directpost/Request.php index 8be7ed5da15ac1dd627ce691ef1cd6eaf9455824..4d5da3e76dc1c3eb4ff204e9ec388f9cece87865 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost/Request.php +++ b/app/code/Magento/Authorizenet/Model/Directpost/Request.php @@ -123,7 +123,7 @@ class Request extends AuthorizenetRequest ->setXCity(strval($billing->getCity())) ->setXState(strval($billing->getRegion())) ->setXZip(strval($billing->getPostcode())) - ->setXCountry(strval($billing->getCountry())) + ->setXCountry(strval($billing->getCountryId())) ->setXPhone(strval($billing->getTelephone())) ->setXFax(strval($billing->getFax())) ->setXCustId(strval($billing->getCustomerId())) @@ -151,7 +151,7 @@ class Request extends AuthorizenetRequest )->setXShipToZip( strval($shipping->getPostcode()) )->setXShipToCountry( - strval($shipping->getCountry()) + strval($shipping->getCountryId()) ); } diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Text.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Text.php index 1427cec7604e88935f53d6c108d77bb58357bdfa..11aa6bf86257cad79ea7698e6c9fdf893ba7082b 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Text.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Text.php @@ -3,14 +3,13 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ +namespace Magento\Backend\Block\Widget\Grid\Column\Renderer; + +use Magento\Framework\DataObject; /** * Backend grid item renderer - * - * @author Magento Core Team <core@magentocommerce.com> */ -namespace Magento\Backend\Block\Widget\Grid\Column\Renderer; - class Text extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRenderer { /** @@ -21,30 +20,53 @@ class Text extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRe protected $_variablePattern = '/\\$([a-z0-9_]+)/i'; /** - * Renders grid column + * Get value for the cel * - * @param \Magento\Framework\DataObject $row - * @return mixed + * @param DataObject $row + * @return string */ - public function _getValue(\Magento\Framework\DataObject $row) + public function _getValue(DataObject $row) { - $format = $this->getColumn()->getFormat() ? $this->getColumn()->getFormat() : null; - $defaultValue = $this->getColumn()->getDefault(); - if ($format === null) { - // If no format and it column not filtered specified return data as is. - $data = parent::_getValue($row); - $string = $data === null ? $defaultValue : $data; - return $this->escapeHtml($string); - } elseif (preg_match_all($this->_variablePattern, $format, $matches)) { - // Parsing of format string - $formattedString = $format; - foreach ($matches[0] as $matchIndex => $match) { - $value = $row->getData($matches[1][$matchIndex]); - $formattedString = str_replace($match, $value, $formattedString); + if (null === $this->getColumn()->getFormat()) { + return $this->getSimpleValue($row); + } + return $this->getFormattedValue($row); + } + + /** + * Get simple value + * + * @param DataObject $row + * @return string + */ + private function getSimpleValue(DataObject $row) + { + $data = parent::_getValue($row); + $value = null === $data ? $this->getColumn()->getDefault() : $data; + if (true === $this->getColumn()->getTranslate()) { + $value = __($value); + } + return $this->escapeHtml($value); + } + + /** + * Replace placeholders in the string with values + * + * @param DataObject $row + * @return string + */ + private function getFormattedValue(DataObject $row) + { + $value = $this->getColumn()->getFormat() ?: null; + if (true === $this->getColumn()->getTranslate()) { + $value = __($value); + } + if (preg_match_all($this->_variablePattern, $value, $matches)) { + foreach ($matches[0] as $index => $match) { + $replacement = $row->getData($matches[1][$index]); + $value = str_replace($match, $replacement, $value); } - return $formattedString; - } else { - return $this->escapeHtml($format); } + return $this->escapeHtml($value); } } diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml index 3e61fec077c6e3fcfccfb62b5ecad98248e9b41d..decc26f331c8298d16b4a76d4a74d82c5808c651 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml @@ -48,6 +48,7 @@ <argument name="width" xsi:type="string">180</argument> <argument name="align" xsi:type="string">left</argument> <argument name="sortable" xsi:type="string">0</argument> + <argument name="translate" xsi:type="boolean">true</argument> </arguments> </block> <block class="Magento\Backend\Block\Widget\Grid\Column" as="description"> @@ -57,6 +58,7 @@ <argument name="type" xsi:type="string">text</argument> <argument name="align" xsi:type="string">left</argument> <argument name="sortable" xsi:type="string">0</argument> + <argument name="translate" xsi:type="boolean">true</argument> </arguments> </block> <block class="Magento\Backend\Block\Widget\Grid\Column" as="tags"> diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js index ea832acb537e0051e34f976c050c9b8bd7d289b7..14729714b4e608f8c422da8c220b9ea1ed115ffb 100644 --- a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js +++ b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js @@ -28,7 +28,7 @@ define([ self.$selector = $('#' + self.selector); self.$container = $('#' + self.container); self.$selector.on( - 'setVaultNotActive', + 'setVaultNotActive.' + self.getCode(), function () { self.$selector.off('submitOrder.' + self.getCode()); } diff --git a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php index 7789f79d907f85d2402a82899af1de3f63db29de..4059f06bccded2f5dbaec98de627a0dc90407eb9 100644 --- a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php +++ b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php @@ -491,7 +491,7 @@ class Price extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\D null )->join( ['e' => $this->getTable('catalog_product_entity')], - "i.entity_id=e.$linkField", + "i.entity_id=e.entity_id", [] )->where( 'e.type_id=?', @@ -502,7 +502,7 @@ class Price extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\D $select = $connection->select()->from( ['tp' => $this->getTable('catalog_product_entity_tier_price')], - [$linkField] + ['e.entity_id'] )->join( ['e' => $this->getTable('catalog_product_entity')], "tp.{$linkField} = e.{$linkField}", @@ -523,11 +523,11 @@ class Price extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\D )->columns( new \Zend_Db_Expr('MIN(tp.value)') )->group( - ["tp.{$linkField}", 'cg.customer_group_id', 'cw.website_id'] + ['e.entity_id', 'cg.customer_group_id', 'cw.website_id'] ); if (!empty($entityIds)) { - $select->where("tp.{$linkField} IN(?)", $entityIds); + $select->where('e.entity_id IN(?)', $entityIds); } $query = $select->insertFromSelect($this->_getTierPriceIndexTable()); diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/GalleryManagement.php b/app/code/Magento/Catalog/Model/Product/Gallery/GalleryManagement.php index 950e2253a95dc21218ee666bb5d747b3991d3118..d2a3196868543db0fb9832aca40529df2c32f965 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/GalleryManagement.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/GalleryManagement.php @@ -94,13 +94,16 @@ class GalleryManagement implements \Magento\Catalog\Api\ProductAttributeMediaGal } $found = false; foreach ($existingMediaGalleryEntries as $key => $existingEntry) { + $entryTypes = (array)$entry->getTypes(); + $existingEntryTypes = (array)$existingMediaGalleryEntries[$key]->getTypes(); + $existingMediaGalleryEntries[$key]->setTypes(array_diff($existingEntryTypes, $entryTypes)); + if ($existingEntry->getId() == $entry->getId()) { $found = true; if ($entry->getFile()) { $entry->setId(null); } $existingMediaGalleryEntries[$key] = $entry; - break; } } if (!$found) { diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php index 3c757f8a05a2daf0ab30c9efb2031c15cefa1d4f..ec2521350d14d991e9c8deff2a74f5ff4865fbfc 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php @@ -298,11 +298,11 @@ class Processor if (is_array($mediaAttribute)) { foreach ($mediaAttribute as $attribute) { if (in_array($attribute, $mediaAttributeCodes)) { - $product->setData($attribute, null); + $product->setData($attribute, 'no_selection'); } } } elseif (in_array($mediaAttribute, $mediaAttributeCodes)) { - $product->setData($mediaAttribute, null); + $product->setData($mediaAttribute, 'no_selection'); } return $this; diff --git a/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php b/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php index a940e09bd57b56a026bba1a45312b94b7f1c80e3..c144daf8c71bd3dc035338af0283df31009e0126 100644 --- a/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php +++ b/app/code/Magento/Catalog/Pricing/Render/FinalPriceBox.php @@ -29,18 +29,8 @@ class FinalPriceBox extends BasePriceBox } $result = parent::_toHtml(); - - try { - /** @var MsrpPrice $msrpPriceType */ - $msrpPriceType = $this->getSaleableItem()->getPriceInfo()->getPrice('msrp_price'); - } catch (\InvalidArgumentException $e) { - $this->_logger->critical($e); - return $this->wrapResult($result); - } - //Renders MSRP in case it is enabled - $product = $this->getSaleableItem(); - if ($msrpPriceType->canApplyMsrp($product) && $msrpPriceType->isMinimalPriceLessMsrp($product)) { + if ($this->isMsrpPriceApplicable()) { /** @var BasePriceBox $msrpBlock */ $msrpBlock = $this->rendererPool->createPriceRender( MsrpPrice::PRICE_CODE, @@ -56,6 +46,25 @@ class FinalPriceBox extends BasePriceBox return $this->wrapResult($result); } + /** + * Check is MSRP applicable for the current product. + * + * @return bool + */ + protected function isMsrpPriceApplicable() + { + try { + /** @var MsrpPrice $msrpPriceType */ + $msrpPriceType = $this->getSaleableItem()->getPriceInfo()->getPrice('msrp_price'); + } catch (\InvalidArgumentException $e) { + $this->_logger->critical($e); + return false; + } + + $product = $this->getSaleableItem(); + return $msrpPriceType->canApplyMsrp($product) && $msrpPriceType->isMinimalPriceLessMsrp($product); + } + /** * Wrap with standard required container * diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/GalleryManagementTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/GalleryManagementTest.php index fb2d197749e01bdd15b1574d2fca4831a04e4583..e3845a2b51cec716d37e27430023ee2be2409bef 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/GalleryManagementTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/GalleryManagementTest.php @@ -191,20 +191,33 @@ class GalleryManagementTest extends \PHPUnit_Framework_TestCase $productSku = 'testProduct'; $entryMock = $this->getMock(\Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class); $entryId = 42; + $entrySecondId = 43; $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) ->willReturn($this->productMock); $existingEntryMock = $this->getMock( \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class ); + $existingSecondEntryMock = $this->getMock( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + ); + $existingEntryMock->expects($this->once())->method('getId')->willReturn($entryId); + $existingEntryMock->expects($this->once())->method('getTypes')->willReturn(['small_image']); + $existingEntryMock->expects($this->once())->method('setTypes')->with(['small_image']); + $existingSecondEntryMock->expects($this->once())->method('getId')->willReturn($entrySecondId); + $existingSecondEntryMock->expects($this->once())->method('getTypes')->willReturn(['image']); + $existingSecondEntryMock->expects($this->once())->method('setTypes')->with([]); $this->productMock->expects($this->once())->method('getMediaGalleryEntries') - ->willReturn([$existingEntryMock]); - $entryMock->expects($this->once())->method('getId')->willReturn($entryId); + ->willReturn([$existingEntryMock, $existingSecondEntryMock]); + + $entryMock->expects($this->exactly(2))->method('getId')->willReturn($entryId); $entryMock->expects($this->once())->method('getFile')->willReturn("base64"); $entryMock->expects($this->once())->method('setId')->with(null); + $entryMock->expects($this->exactly(2))->method('getTypes')->willReturn(['image']); $this->productMock->expects($this->once())->method('setMediaGalleryEntries') - ->willReturn([$entryMock]); + ->with([$entryMock, $existingSecondEntryMock]) + ->willReturnSelf(); $this->productRepositoryMock->expects($this->once())->method('save')->with($this->productMock); $this->assertTrue($this->model->update($productSku, $entryMock)); } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/ProcessorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/ProcessorTest.php index 61d4e3a5c76d5a3fdf57438c082a210c9b60ac5a..50c3c4ad0122c5490fa535c07fa7d677514d91c9 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/ProcessorTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/ProcessorTest.php @@ -197,4 +197,56 @@ class ProcessorTest extends \PHPUnit_Framework_TestCase [false] ]; } + + /** + * @param int $setDataExpectsCalls + * @param string|null $setDataArgument + * @param array|string $mediaAttribute + * @dataProvider clearMediaAttributeDataProvider + */ + public function testClearMediaAttribute($setDataExpectsCalls, $setDataArgument, $mediaAttribute) + { + $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + + $productMock->expects($this->exactly($setDataExpectsCalls)) + ->method('setData') + ->with($setDataArgument, 'no_selection'); + + $this->mediaConfig->expects($this->once()) + ->method('getMediaAttributeCodes') + ->willReturn(['image', 'small_image']); + + $this->assertSame($this->model, $this->model->clearMediaAttribute($productMock, $mediaAttribute)); + } + + /** + * @return array + */ + public function clearMediaAttributeDataProvider() + { + return [ + [ + 'setDataExpectsCalls' => 1, + 'setDataArgument' => 'image', + 'mediaAttribute' => 'image', + ], + [ + 'setDataExpectsCalls' => 1, + 'setDataArgument' => 'image', + 'mediaAttribute' => ['image'], + ], + [ + 'setDataExpectsCalls' => 0, + 'setDataArgument' => null, + 'mediaAttribute' => 'some_image', + ], + [ + 'setDataExpectsCalls' => 0, + 'setDataArgument' => null, + 'mediaAttribute' => ['some_image'], + ], + ]; + } } diff --git a/app/code/Magento/CatalogWidget/Block/Product/Widget/Conditions.php b/app/code/Magento/CatalogWidget/Block/Product/Widget/Conditions.php index d57db33131b9d3cbe16f60119b9e97b82d72cdad..9a407b118461c19e0db02b92ad2b16a8eb8f5816 100644 --- a/app/code/Magento/CatalogWidget/Block/Product/Widget/Conditions.php +++ b/app/code/Magento/CatalogWidget/Block/Product/Widget/Conditions.php @@ -85,7 +85,7 @@ class Conditions extends Template implements RendererInterface $widget = $this->registry->registry('current_widget_instance'); if ($widget) { $widgetParameters = $widget->getWidgetParameters(); - } elseif($widgetOptions = $this->getLayout()->getBlock('wysiwyg_widget.options')) { + } elseif ($widgetOptions = $this->getLayout()->getBlock('wysiwyg_widget.options')) { $widgetParameters = $widgetOptions->getWidgetValues(); } @@ -100,6 +100,7 @@ class Conditions extends Template implements RendererInterface public function render(AbstractElement $element) { $this->element = $element; + $this->rule->getConditions()->setJsFormObject($this->getHtmlId()); return $this->toHtml(); } diff --git a/app/code/Magento/CatalogWidget/Test/Unit/Block/Product/Widget/ConditionsTest.php b/app/code/Magento/CatalogWidget/Test/Unit/Block/Product/Widget/ConditionsTest.php index 8d87c0ebf0d21768bbe05f5903aded09011e1663..b825e92bab1c2ef2eea4d2c08cd8da1ac1e9e192 100644 --- a/app/code/Magento/CatalogWidget/Test/Unit/Block/Product/Widget/ConditionsTest.php +++ b/app/code/Magento/CatalogWidget/Test/Unit/Block/Product/Widget/ConditionsTest.php @@ -15,6 +15,7 @@ use Magento\Framework\View\Element\BlockInterface; /** * Test class for \Magento\CatalogWidget\Block\Product\Widget\Conditions + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ConditionsTest extends \PHPUnit_Framework_TestCase { @@ -175,4 +176,116 @@ class ConditionsTest extends \PHPUnit_Framework_TestCase ] ); } + + /** + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testRender() + { + $data = ['area' => 'backend']; + $abstractElementMock = $this->getMock( + \Magento\Framework\Data\Form\Element\AbstractElement::class, + ['getContainer'], + [], + '', + false + ); + $eventManagerMock = $this->getMock( + \Magento\Framework\Event\ManagerInterface::class, + [], + [], + '', + false + ); + $scopeConfigMock = $this->getMock( + \Magento\Framework\App\Config\ScopeConfigInterface::class, + [], + [], + '', + false + ); + $fieldsetMock = $this->getMock( + \Magento\Framework\Data\Form\Element\Fieldset::class, + [], + [], + '', + false + ); + $combineMock = $this->getMock( + \Magento\Rule\Model\Condition\Combine::class, + [], + [], + '', + false + ); + $resolverMock = $this->getMock( + \Magento\Framework\View\Element\Template\File\Resolver::class, + [], + [], + '', + false + ); + $filesystemMock = $this->getMock( + \Magento\Framework\Filesystem::class, + ['getDirectoryRead'], + [], + '', + false + ); + $validatorMock = $this->getMock( + \Magento\Framework\View\Element\Template\File\Validator::class, + [], + [], + '', + false + ); + $templateEnginePoolMock = $this->getMock( + \Magento\Framework\View\TemplateEnginePool::class, + [], + [], + '', + false + ); + $templateEngineMock = $this->getMock( + \Magento\Framework\View\TemplateEngineInterface::class, + [], + [], + '', + false + ); + $directoryReadMock = $this->getMock( + \Magento\Framework\Filesystem\Directory\ReadInterface::class, + [], + [], + '', + false + ); + + $this->ruleMock->expects($this->once())->method('getConditions')->willReturn($combineMock); + $combineMock->expects($this->once())->method('setJsFormObject')->willReturnSelf(); + $abstractElementMock->expects($this->any())->method('getContainer')->willReturn($fieldsetMock); + $filesystemMock->expects($this->once())->method('getDirectoryRead')->willReturn($directoryReadMock); + $validatorMock->expects($this->once())->method('isValid')->willReturn(true); + $this->contextMock->expects($this->once())->method('getEnginePool')->willReturn($templateEnginePoolMock); + $templateEnginePoolMock->expects($this->once())->method('get')->willReturn($templateEngineMock); + $templateEngineMock->expects($this->once())->method('render')->willReturn('html'); + + $this->widgetConditions = $this->objectManagerHelper->getObject( + Conditions::class, + [ + 'context' => $this->contextMock, + 'registry' => $this->registryMock, + 'rule' => $this->ruleMock, + '_eventManager' => $eventManagerMock, + '_filesystem' => $filesystemMock, + '_scopeConfig' => $scopeConfigMock, + 'validator' => $validatorMock, + 'resolver' => $resolverMock, + 'data' => $data + ] + ); + + $this->assertEquals($this->widgetConditions->render($abstractElementMock), 'html'); + } } diff --git a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php index 51c68145b24cf5e72061a51647d4b311f39e60bf..a5f85df1c96f66bb911bf92303c40d14c3be49b6 100644 --- a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php @@ -193,6 +193,7 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView $config = [ 'attributes' => $attributesData['attributes'], 'template' => str_replace('%s', '<%- data.price %>', $store->getCurrentCurrency()->getOutputFormat()), + 'currencyFormat' => $store->getCurrentCurrency()->getOutputFormat(), 'optionPrices' => $this->getOptionPrices(), 'prices' => [ 'oldPrice' => [ @@ -229,7 +230,17 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView { $prices = []; foreach ($this->getAllowProducts() as $product) { + $tierPrices = []; $priceInfo = $product->getPriceInfo(); + $tierPriceModel = $priceInfo->getPrice('tier_price'); + $tierPricesList = $tierPriceModel->getTierPriceList(); + foreach ($tierPricesList as $tierPrice) { + $tierPrices[] = [ + 'qty' => $this->_registerJsPrice($tierPrice['price_qty']), + 'price' => $this->_registerJsPrice($tierPrice['price']->getValue()), + 'percentage' => $this->_registerJsPrice($tierPriceModel->getSavePercent($tierPrice['price'])), + ]; + } $prices[$product->getId()] = [ @@ -247,8 +258,9 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView 'amount' => $this->_registerJsPrice( $priceInfo->getPrice('final_price')->getAmount()->getValue() ), - ] - ]; + ], + 'tierPrices' => $tierPrices, + ]; } return $prices; } @@ -263,4 +275,14 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView { return str_replace(',', '.', $price); } + + /** + * Should we generate "As low as" block or not + * + * @return bool + */ + public function showMinimalPrice() + { + return true; + } } diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Render/TierPriceBox.php b/app/code/Magento/ConfigurableProduct/Pricing/Render/TierPriceBox.php new file mode 100644 index 0000000000000000000000000000000000000000..af2414204fd1a3aea6acecceb34f28c613f3c6dc --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Pricing/Render/TierPriceBox.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\ConfigurableProduct\Pricing\Render; + +/** + * Responsible for displaying tier price box on configurable product page. + * + * @package Magento\ConfigurableProduct\Pricing\Render + */ +class TierPriceBox extends FinalPriceBox +{ + /** + * @inheritdoc + */ + public function toHtml() + { + // Hide tier price block in case of MSRP. + if (!$this->isMsrpPriceApplicable()) { + return parent::toHtml(); + } + } +} diff --git a/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml b/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml index 47fe31681b5bf0d96ba4cf4935283d415de23ce7..545b04dc0a3279c92100166bda0ff3922b820bb9 100644 --- a/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml +++ b/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml @@ -10,6 +10,10 @@ <arguments> <argument name="configurable" xsi:type="array"> <item name="prices" xsi:type="array"> + <item name="tier_price" xsi:type="array"> + <item name="render_class" xsi:type="string">Magento\ConfigurableProduct\Pricing\Render\TierPriceBox</item> + <item name="render_template" xsi:type="string">Magento_ConfigurableProduct::product/price/tier_price.phtml</item> + </item> <item name="final_price" xsi:type="array"> <item name="render_class" xsi:type="string">Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox</item> <item name="render_template" xsi:type="string">Magento_ConfigurableProduct::product/price/final_price.phtml</item> diff --git a/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/tier_price.phtml b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/tier_price.phtml new file mode 100644 index 0000000000000000000000000000000000000000..01e6bb4222fd3cf6b178a350b0a3c0667c0263ca --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/tier_price.phtml @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +?> +<script type="text/x-magento-template" id="tier-prices-template"> + <ul class="prices-tier items"> + <% _.each(tierPrices, function(item, key) { %> + <% var priceStr = '<span class="price-container price-tier_price">' + + '<span data-price-amount="' + priceUtils.formatPrice(item.price, currencyFormat) + '"' + + ' data-price-type=""' + ' class="price-wrapper ">' + + '<span class="price">' + priceUtils.formatPrice(item.price, currencyFormat) + '</span>' + + '</span>' + + '</span>'; %> + <li class="item"> + <%= $t('Buy %1 for %2 each and').replace('%1', item.qty).replace('%2', priceStr) %> + <strong class="benefit"> + <%= $t('save') %><span class="percent tier-<%= key %>"> <%= item.percentage %></span>% + </strong> + </li> + <% }); %> + </ul> +</script> +<div data-role="tier-price-block"></div> diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js index 59b313bcb497ddb64e1fdca9bc480afdbbb2f1d9..0c7157f920d9c5f97ec6429fea11bc2aa0af9403 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js @@ -7,11 +7,12 @@ define([ 'jquery', 'underscore', 'mage/template', + 'mage/translate', 'priceUtils', 'priceBox', 'jquery/ui', 'jquery/jquery.parsequery' -], function ($, _, mageTemplate) { +], function ($, _, mageTemplate, $t, priceUtils) { 'use strict'; $.widget('mage.configurable', { @@ -38,7 +39,10 @@ define([ * * @type {String} */ - gallerySwitchStrategy: 'replace' + gallerySwitchStrategy: 'replace', + tierPriceTemplateSelector: '#tier-prices-template', + tierPriceBlockSelector: '[data-role="tier-price-block"]', + tierPriceTemplate: '' }, /** @@ -84,6 +88,7 @@ define([ options.priceFormat = priceBoxOptions.priceFormat; } options.optionTemplate = mageTemplate(options.optionTemplate); + options.tierPriceTemplate = $(this.options.tierPriceTemplateSelector).html(); options.settings = options.spConfig.containerId ? $(options.spConfig.containerId).find(options.superSelector) : @@ -259,6 +264,7 @@ define([ } this._reloadPrice(); this._displayRegularPriceBlock(this.simpleProduct); + this._displayTierPriceBlock(this.simpleProduct); this._changeProductImage(); }, @@ -513,6 +519,31 @@ define([ var galleryObject = element.data('gallery'); this.options.mediaGalleryInitial = galleryObject.returnCurrentImages(); + }, + + /** + * Show or hide tier price block + * + * @param {*} optionId + * @private + */ + _displayTierPriceBlock: function (optionId) { + if (typeof optionId != 'undefined' && + this.options.spConfig.optionPrices[optionId].tierPrices != [] + ) { + var options = this.options.spConfig.optionPrices[optionId]; + if (this.options.tierPriceTemplate) { + var tierPriceHtml = mageTemplate(this.options.tierPriceTemplate, { + 'tierPrices': options.tierPrices, + '$t': $t, + 'currencyFormat': this.options.spConfig.currencyFormat, + 'priceUtils': priceUtils + }); + $(this.options.tierPriceBlockSelector).html(tierPriceHtml).show(); + } + } else { + $(this.options.tierPriceBlockSelector).hide(); + } } }); diff --git a/app/code/Magento/Indexer/view/adminhtml/layout/indexer_indexer_list_grid.xml b/app/code/Magento/Indexer/view/adminhtml/layout/indexer_indexer_list_grid.xml index 6def568e9cbbd83fec74955430834f7538418ab9..63ef028238393bbbbcebaeff4c50caa1e94b44db 100644 --- a/app/code/Magento/Indexer/view/adminhtml/layout/indexer_indexer_list_grid.xml +++ b/app/code/Magento/Indexer/view/adminhtml/layout/indexer_indexer_list_grid.xml @@ -46,6 +46,7 @@ <argument name="index" xsi:type="string">title</argument> <argument name="sortable" xsi:type="string">0</argument> <argument name="column_css_class" xsi:type="string">indexer-title</argument> + <argument name="translate" xsi:type="boolean">true</argument> </arguments> </block> <block class="Magento\Backend\Block\Widget\Grid\Column" as="indexer_description"> @@ -54,6 +55,7 @@ <argument name="index" xsi:type="string">description</argument> <argument name="sortable" xsi:type="string">0</argument> <argument name="column_css_class" xsi:type="string">indexer-description</argument> + <argument name="translate" xsi:type="boolean">true</argument> </arguments> </block> <block class="Magento\Backend\Block\Widget\Grid\Column" as="indexer_mode"> diff --git a/app/code/Magento/OfflineShipping/Model/Quote/Address/FreeShipping.php b/app/code/Magento/OfflineShipping/Model/Quote/Address/FreeShipping.php index d2febaccb2fdf3644774f89626e6224bf6e89415..cf9eed3e84d26860792c4d3751e138ad84863eb8 100644 --- a/app/code/Magento/OfflineShipping/Model/Quote/Address/FreeShipping.php +++ b/app/code/Magento/OfflineShipping/Model/Quote/Address/FreeShipping.php @@ -5,8 +5,6 @@ */ namespace Magento\OfflineShipping\Model\Quote\Address; -use Magento\Quote\Model\Quote\Address; - class FreeShipping implements \Magento\Quote\Model\Quote\Address\FreeShippingInterface { /** @@ -48,7 +46,8 @@ class FreeShipping implements \Magento\Quote\Model\Quote\Address\FreeShippingInt $quote->getCustomerGroupId(), $quote->getCouponCode() ); - + $shippingAddress = $quote->getShippingAddress(); + $shippingAddress->setFreeShipping(0); /** @var \Magento\Quote\Api\Data\CartItemInterface $item */ foreach ($items as $item) { if ($item->getNoDiscount()) { @@ -66,10 +65,14 @@ class FreeShipping implements \Magento\Quote\Model\Quote\Address\FreeShippingInt $itemFreeShipping = (bool)$item->getFreeShipping(); $addressFreeShipping = $addressFreeShipping && $itemFreeShipping; + if ($addressFreeShipping && !$item->getAddress()->getFreeShipping()) { + $item->getAddress()->setFreeShipping(true); + } + /** Parent free shipping we apply to all children*/ $this->applyToChildren($item, $itemFreeShipping); } - return $addressFreeShipping; + return (bool)$shippingAddress->getFreeShipping(); } /** diff --git a/app/code/Magento/OfflineShipping/Test/Unit/Model/Quote/Address/FreeShippingTest.php b/app/code/Magento/OfflineShipping/Test/Unit/Model/Quote/Address/FreeShippingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..27f3c375c91c5a70de74c3ed620838ec358144db --- /dev/null +++ b/app/code/Magento/OfflineShipping/Test/Unit/Model/Quote/Address/FreeShippingTest.php @@ -0,0 +1,111 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\OfflineShipping\Test\Unit\Model\Quote\Address; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class FreeShippingTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\OfflineShipping\Model\Quote\Address\FreeShipping + */ + private $model; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Store\Model\StoreManagerInterface + */ + private $storeManagerMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\OfflineShipping\Model\SalesRule\Calculator + */ + private $calculatorMock; + + protected function setUp() + { + $this->storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class); + $this->calculatorMock = $this->getMock( + \Magento\OfflineShipping\Model\SalesRule\Calculator::class, + [], + [], + '', + false + ); + + $this->model = new \Magento\OfflineShipping\Model\Quote\Address\FreeShipping( + $this->storeManagerMock, + $this->calculatorMock + ); + } + + public function testIsFreeShippingIfNoItems() + { + $quoteMock = $this->getMock(\Magento\Quote\Model\Quote::class, [], [], '', false); + $this->assertFalse($this->model->isFreeShipping($quoteMock, [])); + } + + public function testIsFreeShipping() + { + $storeId = 100; + $websiteId = 200; + $customerGroupId = 300; + $objectManagerMock = new ObjectManagerHelper($this); + $quoteMock = $this->getMock( + \Magento\Quote\Model\Quote::class, + ['getShippingAddress', 'getStoreId', 'getCustomerGroupId', 'getCouponCode'], + [], + '', + false + ); + $itemMock = $this->getMock( + \Magento\Quote\Model\Quote\Item::class, + [ + 'getNoDiscount', + 'getParentItemId', + 'getFreeShipping', + 'getAddress', + 'isChildrenCalculated', + 'getHasChildren', + 'getChildren' + ], + [], + '', + false + ); + + $quoteMock->expects($this->once())->method('getStoreId')->willReturn($storeId); + $storeMock = $this->getMock(\Magento\Store\Api\Data\StoreInterface::class); + $storeMock->expects($this->once())->method('getWebsiteId')->willReturn($websiteId); + $this->storeManagerMock->expects($this->once())->method('getStore')->with($storeId)->willReturn($storeMock); + + $quoteMock->expects($this->once())->method('getCustomerGroupId')->willReturn($customerGroupId); + $quoteMock->expects($this->once())->method('getCouponCode')->willReturn(null); + + $this->calculatorMock->expects($this->once()) + ->method('init') + ->with($websiteId, $customerGroupId, null) + ->willReturnSelf(); + + $itemMock->expects($this->once())->method('getNoDiscount')->willReturn(false); + $itemMock->expects($this->once())->method('getParentItemId')->willReturn(false); + $this->calculatorMock->expects($this->exactly(2))->method('processFreeShipping')->willReturnSelf(); + $itemMock->expects($this->once())->method('getFreeShipping')->willReturn(true); + + $addressMock = $objectManagerMock->getObject(\Magento\Quote\Model\Quote\Address::class); + $quoteMock->expects($this->once())->method('getShippingAddress')->willReturn($addressMock); + $itemMock->expects($this->exactly(2))->method('getAddress')->willReturn($addressMock); + + $itemMock->expects($this->once())->method('getHasChildren')->willReturn(true); + $itemMock->expects($this->once())->method('isChildrenCalculated')->willReturn(true); + + $childMock = $this->getMock(\Magento\Quote\Model\Quote\Item::class, ['setFreeShipping'], [], '', false); + $childMock->expects($this->once())->method('setFreeShipping')->with(true)->willReturnSelf(); + $itemMock->expects($this->once())->method('getChildren')->willReturn([$childMock]); + + $this->assertTrue($this->model->isFreeShipping($quoteMock, [$itemMock])); + } +} diff --git a/app/code/Magento/Sales/Block/Status/Grid/Column/State.php b/app/code/Magento/Sales/Block/Status/Grid/Column/State.php index cd049799e7b497b5b657bd03122a2dcf4e2986ab..ae9ea20fd35fd110e796d87564409cadcd8fe57e 100644 --- a/app/code/Magento/Sales/Block/Status/Grid/Column/State.php +++ b/app/code/Magento/Sales/Block/Status/Grid/Column/State.php @@ -49,8 +49,9 @@ class State extends \Magento\Backend\Block\Widget\Grid\Column */ public function decorateState($value, $row, $column, $isExport) { + $status = $row->getStatus(); if ($value) { - $cell = $value . '[' . $this->_config->getStateLabel($value) . ']'; + $cell = $value . '[' . $this->_config->getStateLabelByStateAndStatus($value, $status) . ']'; } else { $cell = $value; } diff --git a/app/code/Magento/Sales/Model/Order/Config.php b/app/code/Magento/Sales/Model/Order/Config.php index 8c6f2e55f55acfa9ea8b0c26e25efac97f330f30..535e2975ee13da8458cba83666ba49abb942a89a 100644 --- a/app/code/Magento/Sales/Model/Order/Config.php +++ b/app/code/Magento/Sales/Model/Order/Config.php @@ -256,4 +256,22 @@ class Config } return $this->statuses[(bool) $visibility]; } + + /** + * Retrieve label by state and status + * + * @param string $state + * @param string $status + * @return \Magento\Framework\Phrase|string + */ + public function getStateLabelByStateAndStatus($state, $status) + { + foreach ($this->_getCollection() as $item) { + if ($item->getData('state') == $state && $item->getData('status') == $status) { + $label = $item->getData('label'); + return __($label); + } + } + return $state; + } } diff --git a/app/code/Magento/Sales/Setup/UpgradeSchema.php b/app/code/Magento/Sales/Setup/UpgradeSchema.php index d35825242fb291a41961eb882ad93f7d24c58ee9..288e8085a0dab51947905ed0254e69c8479e79ff 100644 --- a/app/code/Magento/Sales/Setup/UpgradeSchema.php +++ b/app/code/Magento/Sales/Setup/UpgradeSchema.php @@ -76,8 +76,9 @@ class UpgradeSchema implements UpgradeSchemaInterface 'sales_shipment_grid', ]; foreach ($tables as $table) { - $setup->getConnection()->modifyColumn( - $setup->getTable($table), + $salesConnection = $setup->getConnection(self::$connectionName); + $salesConnection->modifyColumn( + $installer->getTable($table, self::$connectionName), 'customer_group_id', ['type' => 'integer'] ); diff --git a/app/code/Magento/Sales/Test/Unit/Block/Status/Grid/Column/StateTest.php b/app/code/Magento/Sales/Test/Unit/Block/Status/Grid/Column/StateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..59e7accb583d051a62821276a3c6521c8abb54f2 --- /dev/null +++ b/app/code/Magento/Sales/Test/Unit/Block/Status/Grid/Column/StateTest.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Sales\Test\Unit\Block\Status\Grid\Column; + +class StateTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Sales\Block\Status\Grid\Column\State + */ + private $stateColumn; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $orderStatusCollectionFactoryMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $configMock; + + protected function setUp() + { + $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->orderStatusCollectionFactoryMock = $this->getMock( + \Magento\Sales\Model\ResourceModel\Order\Status\CollectionFactory::class, + ['create'], + [], + '', + false, + false + ); + $this->configMock = $helper->getObject( + \Magento\Sales\Model\Order\Config::class, + [ + 'orderStatusCollectionFactory' => $this->orderStatusCollectionFactoryMock + ] + ); + $this->stateColumn = $helper + ->getObject( + \Magento\Sales\Block\Status\Grid\Column\State::class, + [ + 'config' => $this->configMock, + ] + ); + } + + public function testDecorateState() + { + $rowMock = $this->getMock(\Magento\Sales\Model\Order\Status::class, [], [], '', false); + $rowMock->expects($this->any())->method('getStatus')->willReturn('fraud'); + $columnMock = $this->getMock(\Magento\Backend\Block\Widget\Grid\Column::class, [], [], '', false); + $statuses = [ + new \Magento\Framework\DataObject( + [ + 'status' => 'fraud', + 'state' => 'processing', + 'label' => 'Suspected Fraud', + ] + ), + new \Magento\Framework\DataObject( + [ + 'status' => 'processing', + 'state' => 'processing', + 'label' => 'Processing', + ] + ) + ]; + $collectionMock = $this->getMock( + \Magento\Sales\Model\ResourceModel\Order\Status\Collection::class, + ['create', 'joinStates'], + [], + '', + false, + false + ); + $this->orderStatusCollectionFactoryMock->expects($this->once()) + ->method('create') + ->will($this->returnValue($collectionMock)); + $collectionMock->expects($this->once()) + ->method('joinStates') + ->will($this->returnValue($statuses)); + + $result = $this->stateColumn->decorateState('processing', $rowMock, $columnMock, false); + $this->assertSame('processing[processing]', $result); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ConfigTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ConfigTest.php index 1f29235efaef29a790daccd7cf16447d9254adac..7ee4f745cde8f75de23147c956ca0bf039ab2e3a 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ConfigTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ConfigTest.php @@ -5,8 +5,6 @@ */ namespace Magento\Sales\Test\Unit\Model\Order; -use \Magento\Sales\Model\Order\Config; - /** * Class ConfigTest */ @@ -95,4 +93,40 @@ class ConfigTest extends \PHPUnit_Framework_TestCase $result = $this->salesConfig->getInvisibleOnFrontStatuses(); $this->assertSame($expectedResult, $result); } + + public function testGetStateLabelByStateAndStatus() + { + $statuses = [ + new \Magento\Framework\DataObject( + [ + 'status' => 'fraud', + 'state' => 'processing', + 'label' => 'Suspected Fraud', + ] + ), + new \Magento\Framework\DataObject( + [ + 'status' => 'processing', + 'state' => 'processing', + 'label' => 'Processing', + ] + ) + ]; + $collectionMock = $this->getMock( + \Magento\Sales\Model\ResourceModel\Order\Status\Collection::class, + ['create', 'joinStates'], + [], + '', + false, + false + ); + $this->orderStatusCollectionFactoryMock->expects($this->once()) + ->method('create') + ->will($this->returnValue($collectionMock)); + $collectionMock->expects($this->once()) + ->method('joinStates') + ->will($this->returnValue($statuses)); + $result = $this->salesConfig->getStateLabelByStateAndStatus('processing', 'fraud'); + $this->assertSame('Suspected Fraud', $result->getText()); + } } diff --git a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js index 8af48829df438261aaed469c88245fc50a349853..c1d2fd3f910518ddcf15ae50122db3e5f30cd098 100644 --- a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js +++ b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js @@ -6,11 +6,14 @@ define([ 'jquery', 'underscore', + 'mage/template', 'mage/smart-keyboard-handler', + 'mage/translate', + 'priceUtils', 'jquery/ui', 'jquery/jquery.parsequery', 'mage/validation/validation' -], function ($, _, keyboardHandler) { +], function ($, _, mageTemplate, keyboardHandler, $t, priceUtils) { 'use strict'; /** @@ -254,7 +257,13 @@ define([ gallerySwitchStrategy: 'replace', // whether swatches are rendered in product list or on product page - inProductList: false + inProductList: false, + + // tier prise selectors start + tierPriceTemplateSelector: '#tier-prices-template', + tierPriceBlockSelector: '[data-role="tier-price-block"]', + tierPriceTemplate: '' + // tier prise selectors end }, /** @@ -279,6 +288,7 @@ define([ } else { console.log('SwatchRenderer: No input data received'); } + this.options.tierPriceTemplate = $(this.options.tierPriceTemplateSelector).html(); }, /** @@ -809,7 +819,8 @@ define([ $product = $widget.element.parents($widget.options.selectorProduct), $productPrice = $product.find(this.options.selectorProductPrice), options = _.object(_.keys($widget.optionsMap), {}), - result; + result, + tierPriceHtml; $widget.element.find('.' + $widget.options.classes.attributeClass + '[option-selected]').each(function () { var attributeId = $(this).attr('attribute-id'); @@ -825,6 +836,23 @@ define([ 'prices': $widget._getPrices(result, $productPrice.priceBox('option').prices) } ); + + if (result.tierPrices.length) { + if (this.options.tierPriceTemplate) { + tierPriceHtml = mageTemplate( + this.options.tierPriceTemplate, + { + 'tierPrices': result.tierPrices, + '$t': $t, + 'currencyFormat': this.options.jsonConfig.currencyFormat, + 'priceUtils': priceUtils + } + ); + $(this.options.tierPriceBlockSelector).html(tierPriceHtml).show(); + } + } else { + $(this.options.tierPriceBlockSelector).hide(); + } }, /** diff --git a/app/code/Magento/Ui/Component/MassAction/Filter.php b/app/code/Magento/Ui/Component/MassAction/Filter.php index c24b77198030d7ebe1889ed3586b01becf6677ad..c23466ef0844e5237e2ae577cada08dd19086390 100644 --- a/app/code/Magento/Ui/Component/MassAction/Filter.php +++ b/app/code/Magento/Ui/Component/MassAction/Filter.php @@ -11,6 +11,7 @@ use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\App\RequestInterface; use Magento\Framework\View\Element\UiComponentInterface; use Magento\Framework\Data\Collection\AbstractDb; +use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; /** * Class Filter @@ -43,6 +44,11 @@ class Filter */ protected $filterBuilder; + /** + * @var DataProviderInterface + */ + private $dataProvider; + /** * @param UiComponentFactory $factory * @param RequestInterface $request @@ -74,23 +80,33 @@ class Filter } /** + * Adds filters to collection using DataProvider filter results + * * @param AbstractDb $collection * @return AbstractDb * @throws LocalizedException */ public function getCollection(AbstractDb $collection) { - $component = $this->getComponent(); - $this->prepareComponent($component); - $dataProvider = $component->getContext()->getDataProvider(); - $dataProvider->setLimit(0, false); - $ids = []; - foreach ($dataProvider->getSearchResult()->getItems() as $document) { - $ids[] = $document->getId(); - } + $selected = $this->request->getParam(static::SELECTED_PARAM); + $excluded = $this->request->getParam(static::EXCLUDED_PARAM); - $collection->addFieldToFilter($collection->getIdFieldName(), ['in' => $ids]); - return $this->applySelection($collection); + $isExcludedIdsValid = (is_array($excluded) && !empty($excluded)); + $isSelectedIdsValid = (is_array($selected) && !empty($selected)); + + if ('false' !== $excluded) { + if (!$isExcludedIdsValid && !$isSelectedIdsValid) { + throw new LocalizedException(__('Please select item(s).')); + } + } + $idsArray = $this->getFilterIds(); + if (!empty($idsArray)) { + $collection->addFieldToFilter( + $collection->getIdFieldName(), + ['in' => $idsArray] + ); + } + return $collection; } /** @@ -106,9 +122,7 @@ class Filter if ('false' === $excluded) { return; } - $component = $this->getComponent(); - $this->prepareComponent($component); - $dataProvider = $component->getContext()->getDataProvider(); + $dataProvider = $this->getDataProvider(); try { if (is_array($excluded) && !empty($excluded)) { $this->filterBuilder->setConditionType('nin') @@ -127,6 +141,8 @@ class Filter } /** + * Applies selection to collection from POST parameters + * * @param AbstractDb $collection * @return AbstractDb * @throws LocalizedException @@ -169,7 +185,7 @@ class Filter } /** - * Returns RefererUrl + * Returns Referrer Url * * @return string|null */ @@ -178,4 +194,33 @@ class Filter $data = $this->getComponent()->getContext()->getDataProvider()->getConfigData(); return (isset($data['referer_url'])) ? $data['referer_url'] : null; } + + /** + * Get data provider + * + * @return DataProviderInterface + */ + private function getDataProvider() + { + if (!$this->dataProvider) { + $component = $this->getComponent(); + $this->prepareComponent($component); + $this->dataProvider = $component->getContext()->getDataProvider(); + } + return $this->dataProvider; + } + + /** + * Get filter ids as array + * + * @return int[] + */ + private function getFilterIds() + { + $this->applySelectionOnTargetProvider(); + if ($this->getDataProvider()->getSearchResult()) { + return $this->getDataProvider()->getSearchResult()->getAllIds(); + } + return []; + } } diff --git a/app/code/Magento/Ui/Test/Unit/Component/MassAction/FilterTest.php b/app/code/Magento/Ui/Test/Unit/Component/MassAction/FilterTest.php new file mode 100644 index 0000000000000000000000000000000000000000..604febecde041df3e62aeae3cf135bb5e57e5398 --- /dev/null +++ b/app/code/Magento/Ui/Test/Unit/Component/MassAction/FilterTest.php @@ -0,0 +1,289 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Ui\Test\Unit\Component\MassAction; + +use Magento\Ui\Component\MassAction\Filter; +use Magento\Framework\Api\Filter as ApiFilter; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Data\Collection\AbstractDb; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\View\Element\UiComponentInterface; +use Magento\Framework\Api\Search\SearchResultInterface; +use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; + +class FilterTest extends \PHPUnit_Framework_TestCase +{ + /** + *\PHPUnit_Framework_MockObject_MockObject + */ + private $requestMock; + + /** + * \PHPUnit_Framework_MockObject_MockObject + */ + private $uiComponentFactoryMock; + + /** + * \PHPUnit_Framework_MockObject_MockObject + */ + private $filterBuilderMock; + + /** @var \Magento\Ui\Component\MassAction\Filter */ + private $filter; + + /** + * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + */ + private $objectManager; + + /** + *\PHPUnit_Framework_MockObject_MockObject + */ + private $dataProviderMock; + + /** + *\PHPUnit_Framework_MockObject_MockObject + */ + private $abstractDbMock; + + /** + * \PHPUnit_Framework_MockObject_MockObject + */ + private $searchResultMock; + + /** + * \PHPUnit_Framework_MockObject_MockObject + */ + private $uiComponentMock; + + /** + * Set up + */ + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->uiComponentFactoryMock = $this->getMock(UiComponentFactory::class, [], [], '', false); + $this->filterBuilderMock = $this->getMock(FilterBuilder::class, [], [], '', false); + $this->requestMock = $this->getMock(RequestInterface::class); + $this->dataProviderMock = $this->getMock(DataProviderInterface::class); + $this->uiComponentMock = $this->getMock(UiComponentInterface::class); + $this->abstractDbMock = $this->getMock(AbstractDb::class, [], [], '', false); + $contextMock = $this->getMock(ContextInterface::class); + $this->searchResultMock = $this->getMock(SearchResultInterface::class); + $uiComponentMockTwo = $this->getMock(UiComponentInterface::class); + $this->filter = $this->objectManager->getObject( + Filter::class, + [ + 'factory' => $this->uiComponentFactoryMock, + 'request' => $this->requestMock, + 'filterBuilder' => $this->filterBuilderMock + ] + ); + $this->uiComponentFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($this->uiComponentMock); + $this->uiComponentMock->expects($this->any()) + ->method('getChildComponents') + ->willReturn([$uiComponentMockTwo]); + $uiComponentMockTwo->expects($this->any()) + ->method('getChildComponents') + ->willReturn([]); + $this->uiComponentMock->expects($this->any()) + ->method('getContext') + ->willReturn($contextMock); + $contextMock->expects($this->any()) + ->method('getDataProvider') + ->willReturn($this->dataProviderMock); + $this->dataProviderMock->expects($this->any()) + ->method('setLimit'); + $this->dataProviderMock->expects($this->any()) + ->method('searchResultMock') + ->willReturn($this->searchResultMock); + $this->searchResultMock->expects($this->any()) + ->method('getAllIds') + ->willReturn([]); + } + + /** + * Run test for applySelectionOnTargetProvider method + * + * @param int[]|bool $selectedIds + * @param int[]|bool $excludedIds + * @param int $filterExpected + * @param string $conditionExpected + * @dataProvider applySelectionOnTargetProviderDataProvider + */ + public function testApplySelectionOnTargetProvider($selectedIds, $excludedIds, $filterExpected, $conditionExpected) + { + $this->setUpApplySelection($selectedIds, $excludedIds, $filterExpected, $conditionExpected); + $this->filter->applySelectionOnTargetProvider(); + } + + /** + * Data provider for testApplySelectionOnTargetProvider + */ + public function applySelectionOnTargetProviderDataProvider() + { + return [ + [[1, 2, 3], 'false' , 0, 'in'], + [[1, 2, 3], [1, 2, 3] , 1, 'nin'], + ['false', [1, 2, 3] , 1, 'nin'], + ['false', 'false' , 0, ''] + ]; + } + + /** + * @throws \Exception + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testApplySelectionOnTargetProviderException() + { + $filterMock = $this->getMock(ApiFilter::class, [], [], '', false); + $this->filterBuilderMock->expects($this->any()) + ->method('setConditionType') + ->willReturn($this->filterBuilderMock); + $this->filterBuilderMock->expects($this->any()) + ->method('create') + ->willReturn($filterMock); + $this->filterBuilderMock->expects($this->any()) + ->method('setField') + ->willReturn($this->filterBuilderMock); + $this->requestMock->expects($this->at(0)) + ->method('getParam') + ->with(Filter::SELECTED_PARAM) + ->willReturn([1]); + $this->requestMock->expects($this->at(1)) + ->method('getParam') + ->with(Filter::EXCLUDED_PARAM) + ->willReturn([]); + $this->dataProviderMock->expects($this->any()) + ->method('addFilter') + ->with($filterMock) + ->willThrowException(new \Exception('exception')); + $this->filter->applySelectionOnTargetProvider(); + } + + /** + * Run test for getCollection method + * + * @param int[]|bool $selectedIds + * @param int[]|bool $excludedIds + * @param int $filterExpected + * @param string $conditionExpected + * @dataProvider applySelectionOnTargetProviderDataProvider + */ + public function testGetCollection($selectedIds, $excludedIds, $filterExpected, $conditionExpected) + { + $this->setUpApplySelection($selectedIds, $excludedIds, $filterExpected, $conditionExpected); + $this->requestMock->expects($this->at(4)) + ->method('getParam') + ->with('namespace') + ->willReturn(''); + $this->requestMock->expects($this->at(2)) + ->method('getParam') + ->with(Filter::SELECTED_PARAM) + ->willReturn($selectedIds); + $this->requestMock->expects($this->at(3)) + ->method('getParam') + ->with(Filter::EXCLUDED_PARAM) + ->willReturn($excludedIds); + $this->assertEquals($this->abstractDbMock, $this->filter->getCollection($this->abstractDbMock)); + } + + /** + * This tests the method prepareComponent() + */ + public function testPrepareComponent() + { + $this->filter->prepareComponent($this->uiComponentMock); + } + + /** + * This tests the method getComponent() + */ + public function testGetComponent() + { + $this->requestMock->expects($this->at(0)) + ->method('getParam') + ->with('namespace') + ->willReturn(''); + $this->assertEquals($this->uiComponentMock, $this->filter->getComponent()); + } + + /** + * This tests the method getComponentRefererUrl() + */ + public function testGetComponentRefererUrlIsNotNull() + { + $returnArray = [ + 'referer_url' => 'referer_url' + ]; + $this->dataProviderMock->expects($this->once()) + ->method('getConfigData') + ->willReturn($returnArray); + $this->assertEquals('referer_url', $this->filter->getComponentRefererUrl()); + } + + /** + * This tests the method getComponentRefererUrl() + */ + public function testGetComponentRefererUrlIsNull() + { + $this->assertNull($this->filter->getComponentRefererUrl()); + } + + /** + * Apply mocks for current parameters from datasource + * + * @param int[]|bool $selectedIds + * @param int[]|bool $excludedIds + * @param int $filterExpected + * @param string $conditionExpected + */ + private function setUpApplySelection($selectedIds, $excludedIds, $filterExpected, $conditionExpected) + { + $filterMock = $this->getMock(ApiFilter::class, [], [], '', false); + $this->requestMock->expects($this->at(0)) + ->method('getParam') + ->with(Filter::SELECTED_PARAM) + ->willReturn($selectedIds); + $this->requestMock->expects($this->at(1)) + ->method('getParam') + ->with(Filter::EXCLUDED_PARAM) + ->willReturn($excludedIds); + $this->dataProviderMock->expects($this->exactly($filterExpected)) + ->method('addFilter') + ->with($filterMock); + $this->filterBuilderMock->expects($this->exactly($filterExpected)) + ->method('setConditionType') + ->with($conditionExpected) + ->willReturnSelf(); + $this->filterBuilderMock->expects($this->any()) + ->method('setField') + ->willReturnSelf(); + $this->filterBuilderMock->expects($this->any()) + ->method('value') + ->willReturnSelf(); + $this->filterBuilderMock->expects($this->any()) + ->method('create') + ->willReturn($filterMock); + $this->filterBuilderMock->expects($this->any()) + ->method('setConditionType') + ->willReturnSelf(); + $this->filterBuilderMock->expects($this->any()) + ->method('setField') + ->willReturnSelf(); + $this->filterBuilderMock->expects($this->any()) + ->method('value') + ->willReturnSelf(); + $this->filterBuilderMock->expects($this->any()) + ->method('create') + ->willReturn($filterMock); + } +} diff --git a/app/code/Magento/Vault/Setup/UpgradeData.php b/app/code/Magento/Vault/Setup/UpgradeData.php index 757b5f4d3167cb00254e8f2ef20fad3addc1cb27..1c3f113ba9831de6123cbf0c0af361a0f520a1fb 100644 --- a/app/code/Magento/Vault/Setup/UpgradeData.php +++ b/app/code/Magento/Vault/Setup/UpgradeData.php @@ -20,9 +20,11 @@ use Magento\Vault\Model\CreditCardTokenFactory; class UpgradeData implements UpgradeDataInterface { /** - * @var AdapterInterface + * Predefined name for sales connection + * + * @var string */ - private $connection; + private static $salesConnectionName = 'sales'; /** * @inheritdoc @@ -30,12 +32,11 @@ class UpgradeData implements UpgradeDataInterface public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { $setup->startSetup(); - $connection = $this->getConnection(); // data update for Vault module < 2.0.1 if (version_compare($context->getVersion(), '2.0.1', '<')) { // update sets credit card as default token type - $connection->update($setup->getTable(InstallSchema::PAYMENT_TOKEN_TABLE), [ + $setup->getConnection()->update($setup->getTable(InstallSchema::PAYMENT_TOKEN_TABLE), [ PaymentTokenInterface::TYPE => CreditCardTokenFactory::TOKEN_TYPE_CREDIT_CARD ], PaymentTokenInterface::TYPE . ' = ""'); } @@ -43,12 +44,13 @@ class UpgradeData implements UpgradeDataInterface // data update for Vault module < 2.0.2 if (version_compare($context->getVersion(), '2.0.2', '<')) { // update converts additional info with token metadata to single dimensional array - $select = $connection->select() + $salesConnection = $setup->getConnection(self::$salesConnectionName); + $select = $salesConnection->select() ->from($setup->getTable('sales_order_payment'), 'entity_id') ->columns(['additional_information']) ->where('additional_information LIKE ?', '%token_metadata%'); - $items = $connection->fetchAll($select); + $items = $salesConnection->fetchAll($select); foreach ($items as $item) { $additionalInfo = unserialize($item['additional_information']); $additionalInfo[PaymentTokenInterface::CUSTOMER_ID] = @@ -57,7 +59,7 @@ class UpgradeData implements UpgradeDataInterface $additionalInfo['token_metadata'][PaymentTokenInterface::PUBLIC_HASH]; unset($additionalInfo['token_metadata']); - $connection->update( + $salesConnection->update( $setup->getTable('sales_order_payment'), ['additional_information' => serialize($additionalInfo)], ['entity_id = ?' => $item['entity_id']] @@ -67,23 +69,4 @@ class UpgradeData implements UpgradeDataInterface $setup->endSetup(); } - - /** - * Tries to get connection for scalable sales DB, otherwise returns default connection - * @return AdapterInterface - */ - private function getConnection() - { - if ($this->connection === null) { - /** @var ResourceConnection $conn */ - $conn = ObjectManager::getInstance()->get(ResourceConnection::class); - try { - $this->connection = $conn->getConnectionByName('sales'); - } catch (\DomainException $e) { - $this->connection = $conn->getConnection(); - } - } - - return $this->connection; - } } diff --git a/app/code/Magento/Vault/view/adminhtml/web/js/vault.js b/app/code/Magento/Vault/view/adminhtml/web/js/vault.js index 560e65c007f8ab22c2b5b1e76bac0c9062e2af78..66c17801ec02edb262434bc807988bed1bece940 100644 --- a/app/code/Magento/Vault/view/adminhtml/web/js/vault.js +++ b/app/code/Magento/Vault/view/adminhtml/web/js/vault.js @@ -33,8 +33,8 @@ define([ .observe(['active']); // re-init payment method events - self.$selector.off('changePaymentMethod.' + this.code) - .on('changePaymentMethod.' + this.code, this.changePaymentMethod.bind(this)); + self.$selector.off('changePaymentMethod.' + this.getCode()) + .on('changePaymentMethod.' + this.getCode(), this.changePaymentMethod.bind(this)); if (this.active()) { $('#' + this.fieldset + ' input:radio:first').trigger('click'); @@ -50,7 +50,7 @@ define([ * @returns {exports.changePaymentMethod} */ changePaymentMethod: function (event, method) { - this.active(method === this.code); + this.active(method === this.getCode()); return this; }, @@ -61,13 +61,21 @@ define([ */ onActiveChange: function (isActive) { if (!isActive) { - this.$selector.trigger('setVaultNotActive'); + this.$selector.trigger('setVaultNotActive.' + this.getCode()); return; } $('#' + this.fieldset + ' input:radio:first').trigger('click'); - window.order.addExcludedPaymentMethod(this.code); + window.order.addExcludedPaymentMethod(this.getCode()); + }, + + /** + * Get payment method code + * @returns {String} + */ + getCode: function () { + return this.code; } }); }); diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php index 324404ead6c9f5845526512ed6ed39e87f94157c..0f5a0a425a5a5358cf98715827a7950d5e0489fd 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php @@ -237,8 +237,8 @@ class ProductAttributeMediaGalleryManagementInterfaceTest extends \Magento\TestF $targetProduct = $this->getTargetSimpleProduct(); $this->assertEquals('/m/a/magento_image.jpg', $targetProduct->getData('thumbnail')); - $this->assertNull($targetProduct->getData('image')); - $this->assertNull($targetProduct->getData('small_image')); + $this->assertEquals('no_selection', $targetProduct->getData('image')); + $this->assertEquals('no_selection', $targetProduct->getData('small_image')); $mediaGallery = $targetProduct->getData('media_gallery'); $this->assertCount(1, $mediaGallery['images']); $updatedImage = array_shift($mediaGallery['images']); diff --git a/dev/tests/functional/credentials.xml.dist b/dev/tests/functional/credentials.xml.dist index 88794d183e8781d5cea1c9199370c67daae1585c..78186091a568ddba7368126c4b9217714e35d127 100644 --- a/dev/tests/functional/credentials.xml.dist +++ b/dev/tests/functional/credentials.xml.dist @@ -32,10 +32,15 @@ <field path="payment/authorizenet_directpost/trans_key" value="" /> <field path="payment/authorizenet_directpost/trans_md5" value="" /> - <field path="payment/braintree_section/braintree/braintree_advanced/merchant_account_id" value="" /> - <field path="payment/braintree_section/braintree/braintree_required/merchant_id" value="" /> - <field path="payment/braintree_section/braintree/braintree_required/public_key" value="" /> - <field path="payment/braintree_section/braintree/braintree_required/private_key" value="" /> + <field replace="braintree_enabled_fraud_merchant_account_id" value="" /> + <field replace="braintree_enabled_fraud_merchant_id" value="" /> + <field replace="braintree_enabled_fraud_public_key" value="" /> + <field replace="braintree_enabled_fraud_private_key" value="" /> + + <field replace="braintree_disabled_fraud_merchant_account_id" value="" /> + <field replace="braintree_disabled_fraud_merchant_id" value="" /> + <field replace="braintree_disabled_fraud_public_key" value="" /> + <field replace="braintree_disabled_fraud_private_key" value="" /> <field path="payment/paypal_group_all_in_one/wpp_usuk/wpp_required_settings/wpp_and_express_checkout/business_account" value="" /> <field path="payment/paypal_group_all_in_one/wpp_usuk/wpp_required_settings/wpp_and_express_checkout/api_username" value="" /> diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml index 7f01e4f46106c020c10457a8f3e0fb0a7f1de8d7..268ce5795221dbbe3f545891c4d2e420bc87440e 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml @@ -11,26 +11,26 @@ <field name="payment/braintree_section/braintree/braintree_required/merchant_id" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> <item name="scope_id" xsi:type="number">1</item> - <item name="label" xsi:type="string">PAYMENT_BRAINTREE_MERCHANT_ID</item> - <item name="value" xsi:type="string">PAYMENT_BRAINTREE_MERCHANT_ID</item> + <item name="label" xsi:type="string">Merchant ID</item> + <item name="value" xsi:type="string">%braintree_disabled_fraud_merchant_id%</item> </field> <field name="payment/braintree_section/braintree/braintree_required/public_key" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> <item name="scope_id" xsi:type="number">1</item> - <item name="label" xsi:type="string">PAYMENT_PAYMENT_BRAINTREE_PUBLIC_KEY</item> - <item name="value" xsi:type="string">PAYMENT_PAYMENT_BRAINTREE_PUBLIC_KEY</item> + <item name="label" xsi:type="string">Public Key</item> + <item name="value" xsi:type="string">%braintree_disabled_fraud_public_key%</item> </field> <field name="payment/braintree_section/braintree/braintree_required/private_key" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> <item name="scope_id" xsi:type="number">1</item> - <item name="label" xsi:type="string">PAYMENT_BRAINTREE_PRIVATE_KEY</item> - <item name="value" xsi:type="string">PAYMENT_BRAINTREE_PRIVATE_KEY</item> + <item name="label" xsi:type="string">Private Key</item> + <item name="value" xsi:type="string">%braintree_disabled_fraud_private_key%</item> </field> <field name="payment/braintree_section/braintree/braintree_advanced/merchant_account_id" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> <item name="scope_id" xsi:type="number">1</item> - <item name="label" xsi:type="string">PAYMENT_BRAINTREE_MERCHANT_ACCOUNT_ID</item> - <item name="value" xsi:type="string">PAYMENT_BRAINTREE_MERCHANT_ACCOUNT_ID</item> + <item name="label" xsi:type="string">Merchant Account ID</item> + <item name="value" xsi:type="string">%braintree_disabled_fraud_merchant_account_id%</item> </field> <field name="payment/braintree_section/braintree/braintree_required/payment_action" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -51,6 +51,7 @@ <item name="value" xsi:type="number">1</item> </field> </dataset> + <dataset name="braintree_rollback"> <field name="payment/braintree/active" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -59,6 +60,16 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + + <dataset name="braintree_incorrect_merchant_account_id"> + <field name="payment/braintree_section/braintree/braintree_advanced/merchant_account_id" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Merchant Account ID</item> + <item name="value" xsi:type="string">incorrect</item> + </field> + </dataset> + <dataset name="braintree_sale"> <field name="payment/braintree/payment_action" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -67,6 +78,7 @@ <item name="value" xsi:type="string">authorize_capture</item> </field> </dataset> + <dataset name="braintree_3d_secure"> <field name="payment/braintree_section/braintree/braintree_3dsecure/verify_3dsecure" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -75,6 +87,7 @@ <item name="value" xsi:type="number">1</item> </field> </dataset> + <dataset name="braintree_3d_secure_rollback"> <field name="payment/braintree_section/braintree/braintree_3dsecure/verify_3dsecure" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -83,6 +96,7 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + <dataset name="braintree_3d_secure_uk"> <field name="payment/braintree/verify_3dsecure" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -107,6 +121,7 @@ </item> </field> </dataset> + <dataset name="braintree_3d_secure_uk_rollback"> <field name="payment/braintree_section/braintree/braintree_3dsecure/verify_3dsecure" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -121,6 +136,7 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + <dataset name="braintree_3d_secure_not_triggered_due_threshold"> <field name="payment/braintree/verify_3dsecure" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -135,6 +151,7 @@ <item name="value" xsi:type="number">300</item> </field> </dataset> + <dataset name="braintree_3d_secure_not_triggered_due_threshold_rollback"> <field name="payment/braintree/verify_3dsecure" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -143,6 +160,7 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + <dataset name="braintree_use_vault"> <field name="payment/braintree_section/braintree/braintree_cc_vault_active" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -151,6 +169,7 @@ <item name="value" xsi:type="number">1</item> </field> </dataset> + <dataset name="braintree_use_vault_rollback"> <field name="payment/braintree_section/braintree/braintree_cc_vault_active" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -159,6 +178,7 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + <dataset name="braintree_paypal"> <field name="payment/braintree_section/braintree/active_braintree_paypal" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -173,6 +193,7 @@ <item name="value" xsi:type="string">authorize</item> </field> </dataset> + <dataset name="braintree_paypal_rollback"> <field name="payment/braintree_section/braintree/active_braintree_paypal" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -181,7 +202,14 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + <dataset name="braintree_paypal_sale"> + <field name="payment/braintree_section/braintree/active_braintree_paypal" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> <field name="payment/braintree_section/braintree/braintree_paypal/payment_action" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> <item name="scope_id" xsi:type="number">1</item> @@ -189,6 +217,16 @@ <item name="value" xsi:type="string">authorize_capture</item> </field> </dataset> + + <dataset name="braintree_paypal_sale_rollback"> + <field name="payment/braintree_section/braintree/active_braintree_paypal" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">No</item> + <item name="value" xsi:type="number">0</item> + </field> + </dataset> + <dataset name="braintree_paypal_skip_order_review"> <field name="payment/braintree_section/braintree/braintree_paypal/skip_order_review" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -197,6 +235,7 @@ <item name="value" xsi:type="number">1</item> </field> </dataset> + <dataset name="braintree_paypal_skip_order_review_rollback"> <field name="payment/braintree_section/braintree/braintree_paypal/skip_order_review" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -205,6 +244,7 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + <dataset name="braintree_paypal_use_vault"> <field name="payment/braintree_section/braintree/braintree_paypal/braintree_paypal_vault_active" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -213,6 +253,7 @@ <item name="value" xsi:type="number">1</item> </field> </dataset> + <dataset name="braintree_paypal_use_vault_rollback"> <field name="payment/braintree_section/braintree/braintree_paypal/braintree_paypal_vault_active" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -221,6 +262,7 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + <dataset name="braintree_fraudprotection"> <field name="payment/braintree/fraudprotection" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -229,6 +271,7 @@ <item name="value" xsi:type="number">1</item> </field> </dataset> + <dataset name="braintree_fraudprotection_rollback"> <field name="payment/braintree/fraudprotection" xsi:type="array"> <item name="scope" xsi:type="string">payment</item> @@ -237,5 +280,59 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + + <dataset name="braintree_fraud_tool_enabled_account"> + <field name="payment/braintree_section/braintree/braintree_required/merchant_id" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Merchant ID</item> + <item name="value" xsi:type="string">%braintree_enabled_fraud_merchant_id%</item> + </field> + <field name="payment/braintree_section/braintree/braintree_required/public_key" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Public Key</item> + <item name="value" xsi:type="string">%braintree_enabled_fraud_public_key%</item> + </field> + <field name="payment/braintree_section/braintree/braintree_required/private_key" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Private Key</item> + <item name="value" xsi:type="string">%braintree_enabled_fraud_private_key%</item> + </field> + <field name="payment/braintree_section/braintree/braintree_advanced/merchant_account_id" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Merchant Account ID</item> + <item name="value" xsi:type="string">%braintree_enabled_fraud_merchant_account_id%</item> + </field> + <field name="payment/braintree_section/braintree/braintree_required/payment_action" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Authorize</item> + <item name="value" xsi:type="string">authorize</item> + </field> + <field name="payment/braintree_section/braintree/braintree_advanced/debug" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + <field name="payment/braintree_section/braintree/active" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + </dataset> + + <dataset name="braintree_fraud_tool_enabled_account_rollback"> + <field name="payment/braintree/active" xsi:type="array"> + <item name="scope" xsi:type="string">payment</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">No</item> + <item name="value" xsi:type="number">0</item> + </field> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/CreditCard.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/CreditCard.xml index e750aa9cb423444e2cc17b8e269a7a62b9289f20..6aa9383ff2bd1051364b1498d799ebb681714aca 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/CreditCard.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/CreditCard.xml @@ -13,17 +13,26 @@ <field name="credit_card_exp_year" xsi:type="string">2020</field> <field name="cvv" xsi:type="string">123</field> </dataset> + <dataset name="visa_braintree_3dsecure"> <field name="credit_card_number" xsi:type="string">4000000000000002</field> <field name="credit_card_exp_month" xsi:type="string">01</field> <field name="credit_card_exp_year" xsi:type="string">20</field> <field name="cvv" xsi:type="string">123</field> </dataset> + <dataset name="visa_braintree_3dsecure_failed"> <field name="credit_card_number" xsi:type="string">4000000000000028</field> <field name="credit_card_exp_month" xsi:type="string">01</field> <field name="credit_card_exp_year" xsi:type="string">2020</field> <field name="cvv" xsi:type="string">123</field> </dataset> + + <dataset name="visa_braintree_fraud_rejected"> + <field name="credit_card_number" xsi:type="string">4000111111111511</field> + <field name="credit_card_exp_month" xsi:type="string">01</field> + <field name="credit_card_exp_year" xsi:type="string">2020</field> + <field name="cvv" xsi:type="string">123</field> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderBackendTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderBackendTest.xml index 9614923691c6c097702c3a222bfc52edfcd2489a..083bd33feca7b133903b9f83eb12c4d5b3f1fcfa 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderBackendTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderBackendTest.xml @@ -64,5 +64,28 @@ <constraint name="Magento\Sales\Test\Constraint\AssertCaptureInCommentsHistory" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderInOrdersGridOnFrontend" /> </variation> + <variation name="CreateOrderBackendTestBraintreeVariation3" summary="Checkout with Braintree Credit Card from Admin (Basic Fraud Protection)" ticketId="MAGETWO-46470"> + <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S0</data> + <data name="products/0" xsi:type="string">catalogProductSimple::product_10_dollar</data> + <data name="products/1" xsi:type="string">configurableProduct::with_one_option</data> + <data name="products/2" xsi:type="string">bundleProduct::bundle_fixed_100_dollar_product</data> + <data name="customer/dataset" xsi:type="string">default</data> + <data name="taxRule" xsi:type="string">us_ca_ny_rule</data> + <data name="billingAddress/dataset" xsi:type="string">US_address_1_without_email</data> + <data name="saveAddress" xsi:type="string">No</data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="prices" xsi:type="array"> + <item name="grandTotal" xsi:type="string">145.98</item> + </data> + <data name="payment/method" xsi:type="string">braintree</data> + <data name="creditCardClass" xsi:type="string">credit_card_braintree</data> + <data name="creditCard/dataset" xsi:type="string">visa_braintree_fraud_rejected</data> + <data name="configData" xsi:type="string">braintree</data> + <data name="status" xsi:type="string">Processing</data> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderSuccessCreateMessage" /> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderStatusIsCorrect" /> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderInOrdersGridOnFrontend" /> + </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDeclinedTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDeclinedTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..4a2aa551a18170002045f821de2d492ddb7a2082 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDeclinedTest.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Checkout\Test\TestCase\OnePageCheckoutDeclinedTest" summary="Error message during OnePageCheckout"> + <variation name="OnePageCheckoutBraintreeDeclinedTestVariation1" summary="Registered Checkout with Braintree Credit Card from Storefront with Advanced Fraud Protection failed" ticketId="MAGETWO-46469"> + <data name="products/0" xsi:type="string">catalogProductSimple::product_10_dollar</data> + <data name="customer/dataset" xsi:type="string">default</data> + <data name="shippingAddress/dataset" xsi:type="string">US_address_1_without_email</data> + <data name="checkoutMethod" xsi:type="string">login</data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="payment/method" xsi:type="string">braintree</data> + <data name="creditCardClass" xsi:type="string">credit_card_braintree</data> + <data name="creditCard/dataset" xsi:type="string">visa_braintree_fraud_rejected</data> + <data name="expectedErrorMessage" xsi:type="string">Transaction has been declined. Please try again later.</data> + <data name="configData" xsi:type="string">braintree_fraud_tool_enabled_account, braintree_fraudprotection</data> + <data name="status" xsi:type="string">Processing</data> + <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S1</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertCheckoutErrorMessage" /> + </variation> + <variation name="OnePageCheckoutBraintreeDeclinedTestVariation2" summary="Checkout with Braintree Credit Card configured with incorrect credentials" ticketId="MAGETWO-46244"> + <data name="products/0" xsi:type="string">catalogProductSimple::product_10_dollar</data> + <data name="customer/dataset" xsi:type="string">default</data> + <data name="shippingAddress/dataset" xsi:type="string">US_address_1</data> + <data name="checkoutMethod" xsi:type="string">guest</data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="payment/method" xsi:type="string">braintree</data> + <data name="creditCardClass" xsi:type="string">credit_card_braintree</data> + <data name="creditCard/dataset" xsi:type="string">visa_braintree</data> + <data name="expectedErrorMessage" xsi:type="string">Sorry, but something went wrong</data> + <data name="configData" xsi:type="string">braintree, braintree_incorrect_merchant_account_id</data> + <data name="status" xsi:type="string">Processing</data> + <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S1</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertCheckoutErrorMessage" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutTest.xml index 920047e7037e135115424a192b9c9cb3267982d5..54fdfc96dc947db330c37b701132bfc0e3fcbeb0 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutTest.xml @@ -23,7 +23,7 @@ <data name="payment/method" xsi:type="string">braintree</data> <data name="creditCardClass" xsi:type="string">credit_card_braintree</data> <data name="creditCard/dataset" xsi:type="string">visa_braintree_3dsecure</data> - <data name="isVaultEnabled" xsi:type="boolean">false</data> + <data name="isVaultPresent" xsi:type="boolean">false</data> <data name="configData" xsi:type="string">braintree, braintree_3d_secure_not_triggered_due_threshold</data> <data name="status" xsi:type="string">Processing</data> <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S1</data> @@ -47,7 +47,7 @@ <data name="payment/method" xsi:type="string">braintree</data> <data name="creditCardClass" xsi:type="string">credit_card_braintree</data> <data name="creditCard/dataset" xsi:type="string">visa_braintree_3dsecure</data> - <data name="isVaultEnabled" xsi:type="boolean">false</data> + <data name="isVaultPresent" xsi:type="boolean">false</data> <data name="configData" xsi:type="string">braintree, braintree_3d_secure_uk</data> <data name="status" xsi:type="string">Processing</data> <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S1</data> @@ -71,7 +71,7 @@ <data name="payment/method" xsi:type="string">braintree</data> <data name="creditCardClass" xsi:type="string">credit_card_braintree</data> <data name="creditCard/dataset" xsi:type="string">visa_braintree</data> - <data name="isVaultEnabled" xsi:type="boolean">false</data> + <data name="isVaultPresent" xsi:type="boolean">false</data> <data name="configData" xsi:type="string">braintree</data> <data name="status" xsi:type="string">Processing</data> <data name="tag" xsi:type="string">test_type:extended_acceptance_test, test_type:3rd_party_test, severity:S0</data> @@ -99,7 +99,7 @@ <data name="payment/method" xsi:type="string">braintree</data> <data name="creditCardClass" xsi:type="string">credit_card_braintree</data> <data name="creditCard/dataset" xsi:type="string">visa_braintree</data> - <data name="isVaultEnabled" xsi:type="boolean">false</data> + <data name="isVaultPresent" xsi:type="boolean">false</data> <data name="configData" xsi:type="string">braintree, braintree_sale</data> <data name="status" xsi:type="string">Processing</data> <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S0</data> diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0f21b8f219cb13dd426c1aad3cdb0f6ba24b06a6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Braintree\Test\TestCase; + +use Magento\Mtf\TestCase\Scenario; + +/** + * Preconditions: + * 1. Configure payment method. + * 2. Create products. + * + * Steps: + * 1. Log in Storefront. + * 2. Add products to the Shopping Cart. + * 5. Click the 'Proceed to Checkout' button. + * 6. Fill shipping information. + * 7. Select shipping method. + * 8. Select payment method. + * 9. Verify order total on review step. + * 10. Click 'Place Order' button. + * 11. Specify password in 3D Secure popup. + * 12. Click 'Submit'. + * 13. Perform assertions. + * + * @group Braintree + * @ZephyrId MAGETWO-46477 + */ +class OnePageCheckoutWith3dSecureFailedTest extends Scenario +{ + /* tags */ + const MVP = 'yes'; + const TEST_TYPE = '3rd_party_test'; + const SEVERITY = 'S1'; + /* end tags */ + + /** + * Verifies error message on Onepage Checkout if 3d secure validation is failed. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..2a17d1496a72dfb1bb63073ccd982abf3522ca9f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Braintree\Test\TestCase\OnePageCheckoutWith3dSecureFailedTest" summary="Onepage checkout with Braintree payment method with 3D Secure enabled."> + <variation name="OnePageCheckoutBraintree3dSecureFailedTestVariation1" summary="Guest Checkout with Braintree Credit Card from Storefront with 3D Secure verification failed" ticketId="MAGETWO-46477"> + <data name="products/0" xsi:type="string">catalogProductSimple::product_10_dollar</data> + <data name="customer/dataset" xsi:type="string">default</data> + <data name="shippingAddress/dataset" xsi:type="string">US_address_1</data> + <data name="checkoutMethod" xsi:type="string">guest</data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="payment/method" xsi:type="string">braintree</data> + <data name="creditCardClass" xsi:type="string">credit_card_braintree</data> + <data name="creditCard/dataset" xsi:type="string">visa_braintree_3dsecure_failed</data> + <data name="secure3d/dataset" xsi:type="string">secure3d_braintree</data> + <data name="configData" xsi:type="string">braintree, braintree_3d_secure</data> + <data name="expectedErrorMessage" xsi:type="string">Please try again with another form of payment.</data> + <data name="status" xsi:type="string">Processing</data> + <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S1</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertCheckoutErrorMessage" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml index ad4d5cc06e92e260aed4c90e6f534f2540d25034..5f5e2f50594bf8d0473b65ee584e50f47bc852a4 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml @@ -7,7 +7,7 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Vault\Test\TestCase\ReorderUsingVaultTest" summary="Reorder from Admin with saved within Braintree credit card"> - <variation name="ReorderUsingVaultBraintreeTestVariation1" summary="Reorder from Admin with saved within Braintree credit card for Guest Customer" ticketId="MAGETWO-54870"> + <variation name="ReorderUsingVaultBraintreeTestVariation1" summary="Reorder from Admin with saved within Braintree credit card for Guest Customer" ticketId="MAGETWO-54869, MAGETWO-54870"> <data name="description" xsi:type="string">Reorder from Admin with saved within Braintree credit card for Guest Customer</data> <data name="products/0" xsi:type="string">catalogProductSimple::product_10_dollar</data> <data name="customer/dataset" xsi:type="string">default</data> @@ -20,6 +20,7 @@ </data> <data name="payment/method" xsi:type="string">braintree</data> <data name="vault/method" xsi:type="string">braintree_cc_vault</data> + <data name="isVaultPresent" xsi:type="boolean">false</data> <data name="creditCardClass" xsi:type="string">credit_card_braintree</data> <data name="creditCard/dataset" xsi:type="string">visa_braintree</data> <data name="configData" xsi:type="string">braintree, braintree_use_vault</data> diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/PlaceOrderWith3dSecureFailedStep.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/PlaceOrderWith3dSecureFailedStep.php new file mode 100644 index 0000000000000000000000000000000000000000..00a8fce571617e5cd643d9b05bd914dc24e3eb43 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/PlaceOrderWith3dSecureFailedStep.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Braintree\Test\TestStep; + +use Magento\Checkout\Test\Page\CheckoutOnepage; +use Magento\Mtf\TestStep\TestStepInterface; +use Magento\Braintree\Test\Fixture\Secure3dBraintree; + +/** + * Click 'Place order' button and submit 3D secure verification step. + */ +class PlaceOrderWith3dSecureFailedStep implements TestStepInterface +{ + /** + * Onepage checkout page. + * + * @var CheckoutOnepage + */ + private $checkoutOnepage; + + /** + * 3D Secure fixture. + * + * @var Secure3dBraintree + */ + private $secure3d; + + /** + * @param CheckoutOnepage $checkoutOnepage + * @param Secure3dBraintree $secure3d + */ + public function __construct( + CheckoutOnepage $checkoutOnepage, + Secure3dBraintree $secure3d + ) { + $this->checkoutOnepage = $checkoutOnepage; + $this->secure3d = $secure3d; + } + + /** + * Click 'Place order' button and submit 3D secure verification. + * + * @return array + */ + public function run() + { + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + + $this->checkoutOnepage->getBraintree3dSecureBlock()->fill($this->secure3d); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml index 12aa92d35064d457cef4a544daace01314723d99..6ad46774f0f765b01761f6227465c63b695535d6 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml @@ -21,6 +21,19 @@ <step name="fillBillingInformation" module="Magento_Checkout" next="placeOrderWith3dSecure" /> <step name="placeOrderWith3dSecure" module="Magento_Braintree" /> </scenario> + <scenario name="OnePageCheckoutWith3dSecureFailedTest" firstStep="setupConfiguration"> + <step name="setupConfiguration" module="Magento_Config" next="createProducts" /> + <step name="createProducts" module="Magento_Catalog" next="addProductsToTheCart" /> + <step name="addProductsToTheCart" module="Magento_Checkout" next="proceedToCheckout" /> + <step name="proceedToCheckout" module="Magento_Checkout" next="createCustomer" /> + <step name="createCustomer" module="Magento_Customer" next="selectCheckoutMethod" /> + <step name="selectCheckoutMethod" module="Magento_Checkout" next="fillShippingAddress" /> + <step name="fillShippingAddress" module="Magento_Checkout" next="fillShippingMethod" /> + <step name="fillShippingMethod" module="Magento_Checkout" next="selectPaymentMethod" /> + <step name="selectPaymentMethod" module="Magento_Checkout" next="fillBillingInformation" /> + <step name="fillBillingInformation" module="Magento_Checkout" next="placeOrderWith3dSecureFailed" /> + <step name="placeOrderWith3dSecureFailed" module="Magento_Braintree" /> + </scenario> <scenario name="UseVaultWith3dSecureOnCheckoutTest" firstStep="setupConfiguration"> <step name="setupConfiguration" module="Magento_Config" next="createProducts" /> <step name="createProducts" module="Magento_Catalog" next="addProductsToTheCart" /> diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..a34bf44d38cae01f46f711fd6181c1ae8895ae68 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Sales\Test\TestCase\MoveRecentlyComparedProductsOnOrderPageTest"> + <variation name="MoveRecentlyComparedProductsOnOrderPageTestVariationWithBundleProduct1"> + <data name="products/0" xsi:type="string">bundleProduct::bundle_dynamic_product</data> + <data name="products/1" xsi:type="string">bundleProduct::bundle_dynamic_product</data> + <data name="productsIsConfigured" xsi:type="boolean">true</data> + <constraint name="Magento\Sales\Test\Constraint\AssertProductInItemsOrderedGrid" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/di.xml index 402dcca44c9485a46d9c40b5103f1cac50b86122..61eac871df9722550fff8735930febc339e4ea4d 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/di.xml @@ -11,4 +11,17 @@ <argument name="severity" xsi:type="string">S2</argument> </arguments> </type> + <type name="Magento\Sales\Test\Block\Adminhtml\Order\Create\CustomerActivities\Sidebar\RecentlyComparedProducts"> + <arguments> + <argument name="config" xsi:type="array"> + <item name="renders" xsi:type="array"> + <item name="bundle" xsi:type="array"> + <item name="class" xsi:type="string">\Magento\Bundle\Test\Block\Adminhtml\Product\Composite\Configure</item> + <item name="locator" xsi:type="string">//ancestor::body//*[contains(@class, "modal-slide") and contains(@class, "_show")]</item> + <item name="strategy" xsi:type="string">xpath</item> + </item> + </item> + </argument> + </arguments> + </type> </config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php index de6adb0efd8b21df23cf0531624fa0b90983225d..5baf4a4cb7c3e273588d85c1217e6824cdefad92 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php @@ -522,14 +522,16 @@ class View extends AbstractConfigureBlock } /** - * Check id media gallery is visible for the product. + * Check if media gallery is visible for the product. * * @return bool */ public function isGalleryVisible() { $this->waitForElementNotVisible($this->galleryLoader); - return $this->_rootElement->find($this->mediaGallery)->isVisible(); + $this->waitForElementVisible($this->mediaGallery); + + return true; } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPage.php index e99b63d5b8ce7727b93cc3ef2898ef6ba95caf01..fd6f99d13f40fb8bce3f99142d6004f8652087d1 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPage.php @@ -31,6 +31,11 @@ class AssertProductPage extends AbstractAssertForm */ protected $product; + /** + * @var CatalogProductView + */ + protected $pageView; + /** * Assert that displayed product data on product page(front-end) equals passed from fixture: * 1. Product Name @@ -53,6 +58,7 @@ class AssertProductPage extends AbstractAssertForm $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); $this->product = $product; + $this->pageView = $catalogProductView; $this->productView = $catalogProductView->getViewBlock(); $errors = $this->verify(); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/CheckoutData.xml index 180da27ca2a099ab36c00473ac35572c45a31ffd..a1f34f46b0a7cb89342a17a382a0ba1c86de9059 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/CheckoutData.xml @@ -137,6 +137,14 @@ </field> </dataset> + <dataset name="simple_order_tier_price_5"> + <field name="qty" xsi:type="string">5</field> + <field name="cartItem" xsi:type="array"> + <item name="price" xsi:type="string">40</item> + <item name="subtotal" xsi:type="string">40</item> + </field> + </dataset> + <dataset name="simple_order_10_dollar_product"> <field name="qty" xsi:type="string">1</field> <field name="cartItem" xsi:type="array"> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Login.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Login.php index 49b900e4eedce313df7809a574e150f3c63c4787..507bb5673effc80e7525b238d0b14b2ee6d40c11 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Login.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Login.php @@ -6,6 +6,7 @@ namespace Magento\Checkout\Test\Block\Onepage; use Magento\Checkout\Test\Fixture\Checkout; +use Magento\Customer\Test\Fixture\Customer; use Magento\Mtf\Block\Form; use Magento\Mtf\Fixture\FixtureInterface; @@ -93,14 +94,15 @@ class Login extends Form /** * Fill required fields for guest checkout. * - * @param FixtureInterface $customer + * @param Customer $customer * @return void */ - public function fillGuestFields(FixtureInterface $customer) + public function fillGuestFields(Customer $customer) { $mapping = $this->dataMapping(); $this->_rootElement->find($mapping['email']['selector'], $mapping['email']['strategy']) ->setValue($customer->getEmail()); + $this->waitForElementNotVisible($this->loadingMask); } /** diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/Method.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/Method.php index cce29d23f63b18fc2c469e3df964cb2dd81188e0..24bddf79c1a07c9205e0b22426946e11b92d0489 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/Method.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/Method.php @@ -22,26 +22,49 @@ class Method extends Block protected $shippingMethod = './/tbody//tr[td[contains(., "%s")] and td[contains(., "%s")]]//input'; /** - * Continue checkout button + * Continue checkout button. * * @var string */ protected $continue = '#shipping-method-buttons-container button'; /** - * Wait element + * Wait element. * * @var string */ protected $waitElement = '.loading-mask'; /** - * Block wait element + * Block wait element. * * @var string */ protected $blockWaitElement = '._block-content-loading'; + /** + * Wait until shipping rates will appear. + * + * @return void + */ + private function waitForShippingRates() + { + // Code under test uses JavaScript setTimeout at this point as well. + sleep(3); + $this->waitForElementNotVisible($this->blockWaitElement); + } + + /** + * Retrieve if the shipping methods loader appears. + * + * @return bool|null + */ + public function isLoaderAppeared() + { + $this->_rootElement->click(); + return $this->waitForElementVisible($this->waitElement); + } + /** * Select shipping method. * @@ -50,15 +73,26 @@ class Method extends Block */ public function selectShippingMethod(array $method) { - // Code under test uses JavaScript setTimeout at this point as well. - sleep(3); + $this->waitForShippingRates(); $selector = sprintf($this->shippingMethod, $method['shipping_method'], $method['shipping_service']); - $this->waitForElementNotVisible($this->blockWaitElement); $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->click(); } /** - * Click continue button + * Check whether shipping method is available in the shipping rates. + * + * @param array $method + * @return bool + */ + public function isShippingMethodAvaiable(array $method) + { + $this->waitForShippingRates(); + $selector = sprintf($this->shippingMethod, $method['shipping_method'], $method['shipping_service']); + return $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->isVisible(); + } + + /** + * Click continue button. * * @return void */ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php new file mode 100644 index 0000000000000000000000000000000000000000..24fc2419721b51e3b16c4bcc25e88d13497591c2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Test\Constraint; + +use Magento\Checkout\Test\Page\CheckoutOnepage; +use Magento\Mtf\Constraint\AbstractConstraint; + +/** + * Assert that error message is correct. + */ +class AssertCheckoutErrorMessage extends AbstractConstraint +{ + /** + * Assert that error message is correct. + * + * @param CheckoutOnepage $checkoutOnepage + * @param string $expectedErrorMessage + * @return void + */ + public function processAssert(CheckoutOnepage $checkoutOnepage, $expectedErrorMessage) + { + \PHPUnit_Framework_Assert::assertEquals( + $expectedErrorMessage, + $checkoutOnepage->getMessagesBlock()->getErrorMessage(), + 'Wrong error message is displayed.' + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Error message on Checkout onepage page is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepage.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepage.xml index 0ab3bbb2c2cfcb01330fecd582bb235ed7805068..00ac573da2e7e658b2dc3a9de50a7185bb2512fb 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepage.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepage.xml @@ -17,7 +17,7 @@ <block name="paymentBlock" class="Magento\Checkout\Test\Block\Onepage\Payment" locator="#checkout-step-payment" strategy="css selector" /> <block name="discountCodesBlock" class="Magento\Checkout\Test\Block\Onepage\Payment\DiscountCodes" locator=".discount-code" strategy="css selector" /> <block name="reviewBlock" class="Magento\Checkout\Test\Block\Onepage\Review" locator=".opc-block-summary" strategy="css selector" /> - <block name="messagesBlock" class="Magento\Backend\Test\Block\Messages" locator=".page.messages" strategy="css selector" /> + <block name="messagesBlock" class="Magento\Backend\Test\Block\Messages" locator="//*[@id='checkout']//div[@data-role='checkout-messages' and .//div]" strategy="xpath" /> <block name="customAddressBlock" class="Magento\Checkout\Test\Block\Onepage\CustomAddress" locator=".checkout-billing-address" strategy="css selector" /> </page> </config> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutDeclinedTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutDeclinedTest.php new file mode 100644 index 0000000000000000000000000000000000000000..990c3df13e9b1f00e6a2171dfb8f2216b38f0ec3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutDeclinedTest.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Test\TestCase; + +use Magento\Mtf\TestCase\Scenario; + +/** + * Preconditions: + * 1. Configure payment method. + * 2. Create products. + * + * Steps: + * 1. Log in Storefront. + * 2. Add products to the Shopping Cart. + * 3. Click the 'Proceed to Checkout' button. + * 4. Fill shipping information. + * 5. Select shipping method. + * 6. Select payment method. + * 7. Click 'Place Order' button. + * 8. Perform assertions. + * + * @group Checkout + * @ZephyrId MAGETWO-46469 + */ +class OnePageCheckoutDeclinedTest extends Scenario +{ + /* tags */ + const MVP = 'yes'; + const TEST_TYPE = '3rd_party_test'; + const SEVERITY = 'S1'; + /* end tags */ + + /** + * Verifies error message on Onepage Checkout. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickPlaceOrderButtonStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickPlaceOrderButtonStep.php new file mode 100644 index 0000000000000000000000000000000000000000..cf086e55d5a305f716f4b64513190b32c7708cba --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickPlaceOrderButtonStep.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Test\TestStep; + +use Magento\Checkout\Test\Page\CheckoutOnepage; +use Magento\Mtf\TestStep\TestStepInterface; + +/** + * Click 'Place order' button. + */ +class ClickPlaceOrderButtonStep implements TestStepInterface +{ + /** + * Onepage checkout page. + * + * @var CheckoutOnepage + */ + private $checkoutOnepage; + + /** + * @param CheckoutOnepage $checkoutOnepage + */ + public function __construct(CheckoutOnepage $checkoutOnepage) + { + $this->checkoutOnepage = $checkoutOnepage; + } + + /** + * Click 'Place order' button. + * + * @return array + */ + public function run() + { + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php index cb32e5f0ddfe61d9e97e8ef211ce71bfa46ee71a..3af915e22bfcb1c85ebb53b84872ef4ed255fac2 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php @@ -59,13 +59,6 @@ class SelectCheckoutMethodStep implements TestStepInterface */ private $customerAccountCreatePage; - /** - * Shipping carrier and method. - * - * @var array - */ - protected $shipping; - /** * @constructor * @param CheckoutOnepage $checkoutOnepage @@ -74,7 +67,6 @@ class SelectCheckoutMethodStep implements TestStepInterface * @param LogoutCustomerOnFrontendStep $logoutCustomerOnFrontend * @param ClickProceedToCheckoutStep $clickProceedToCheckoutStep * @param string $checkoutMethod - * @param array $shipping */ public function __construct( CheckoutOnepage $checkoutOnepage, @@ -82,8 +74,7 @@ class SelectCheckoutMethodStep implements TestStepInterface Customer $customer, LogoutCustomerOnFrontendStep $logoutCustomerOnFrontend, ClickProceedToCheckoutStep $clickProceedToCheckoutStep, - $checkoutMethod, - array $shipping = [] + $checkoutMethod ) { $this->checkoutOnepage = $checkoutOnepage; $this->customerAccountCreatePage = $customerAccountCreatePage; @@ -91,7 +82,6 @@ class SelectCheckoutMethodStep implements TestStepInterface $this->logoutCustomerOnFrontend = $logoutCustomerOnFrontend; $this->clickProceedToCheckoutStep = $clickProceedToCheckoutStep; $this->checkoutMethod = $checkoutMethod; - $this->shipping = $shipping; } /** @@ -120,9 +110,7 @@ class SelectCheckoutMethodStep implements TestStepInterface $this->checkoutOnepage->getLoginBlock()->loginCustomer($this->customer); } } elseif ($this->checkoutMethod === 'guest') { - if (empty($this->shipping)) { - $this->checkoutOnepage->getLoginBlock()->fillGuestFields($this->customer); - } + $this->checkoutOnepage->getLoginBlock()->fillGuestFields($this->customer); } elseif ($this->checkoutMethod === 'sign_in') { $this->checkoutOnepage->getAuthenticationWrapperBlock()->signInLinkClick(); $this->checkoutOnepage->getAuthenticationWrapperBlock()->loginCustomer($this->customer); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/di.xml index 24b369200e71d99df604457603969594b40862ca..d7a61b0eaaa2fece41b7d1f464f0e56bdb80d159 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/di.xml @@ -22,4 +22,9 @@ <argument name="severity" xsi:type="string">S0</argument> </arguments> </type> + <type name="Magento\Checkout\Test\Constraint\AssertCheckoutErrorMessage"> + <arguments> + <argument name="severity" xsi:type="string">S1</argument> + </arguments> + </type> </config> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml index 24eb96c0a9347741384ffd6718bf349eeb452c85..e9b49babbba1936aae49b20339a56732b5b2531b 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml @@ -28,4 +28,17 @@ <step name="addProductsToTheCart" module="Magento_Checkout" next="ProceedToCheckout" /> <step name="ProceedToCheckout" module="Magento_Checkout" /> </scenario> + <scenario name="OnePageCheckoutDeclinedTest" firstStep="setupConfiguration"> + <step name="setupConfiguration" module="Magento_Config" next="createProducts" /> + <step name="createProducts" module="Magento_Catalog" next="addProductsToTheCart" /> + <step name="addProductsToTheCart" module="Magento_Checkout" next="proceedToCheckout" /> + <step name="proceedToCheckout" module="Magento_Checkout" next="createCustomer" /> + <step name="createCustomer" module="Magento_Customer" next="selectCheckoutMethod" /> + <step name="selectCheckoutMethod" module="Magento_Checkout" next="fillShippingAddress" /> + <step name="fillShippingAddress" module="Magento_Checkout" next="fillShippingMethod" /> + <step name="fillShippingMethod" module="Magento_Checkout" next="selectPaymentMethod" /> + <step name="selectPaymentMethod" module="Magento_Checkout" next="fillBillingInformation" /> + <step name="fillBillingInformation" module="Magento_Checkout" next="clickPlaceOrderButton" /> + <step name="clickPlaceOrderButton" module="Magento_Checkout" /> + </scenario> </config> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Product/View/ConfigurableOptions.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Product/View/ConfigurableOptions.php index d5279557ec5af84902fbc2a57548df2dcf0aadf6..4edee00a57dbefd8a15846731fa7e888b66186ad 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Product/View/ConfigurableOptions.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Product/View/ConfigurableOptions.php @@ -34,6 +34,13 @@ class ConfigurableOptions extends CustomOptions */ protected $priceBlock = '//*[@class="product-info-main"]//*[contains(@class,"price-box")]'; + /** + * Selector for tier prices. + * + * @var string + */ + private $tierPricesSelector = '.prices-tier li'; + /** * Get configurable product options * @@ -93,11 +100,16 @@ class ConfigurableOptions extends CustomOptions } $productVariations = array_keys($productVariations); - $result = []; foreach ($productVariations as $variation) { $variationOptions = explode(' ', $variation); - $result[$variation]['price'] = $this->getOptionPrice($variationOptions, $attributesData); + //Select all options specified in variation + $this->chooseOptions($variationOptions, $attributesData); + $result[$variation]['price'] = $this->getOptionPrice(); + $tierPrices = $this->getOptionTierPrices(); + if (count($tierPrices) > 0) { + $result[$variation]['tierPrices'] = $tierPrices; + } } return $result; @@ -106,25 +118,34 @@ class ConfigurableOptions extends CustomOptions /** * Get option price * - * @param array $variationOptions - * @param array $attributesData * @return null|string */ - protected function getOptionPrice($variationOptions, $attributesData) + protected function getOptionPrice() { - //Select all options specified in variation - foreach ($variationOptions as $variationSelection) { - list ($attribute, $option) = explode(':', $variationSelection); - $attributeTitle = $attributesData[$attribute]['label']; - $optionTitle = $attributesData[$attribute]['options'][$option]['label']; - $this->selectOption($attributeTitle, $optionTitle); - } - $priceBlock = $this->getPriceBlock(); $price = ($priceBlock->isOldPriceVisible()) ? $priceBlock->getOldPrice() : $priceBlock->getPrice(); return $price; } + /** + * Get tier prices of all variations + * + * @return array + */ + private function getOptionTierPrices() + { + $prices = []; + $tierPricesNodes = $this->_rootElement->getElements($this->tierPricesSelector); + foreach ($tierPricesNodes as $node) { + preg_match('#^[^\d]+(\d+)[^\d]+(\d+(?:(?:,\d+)*)+(?:.\d+)*).*#i', $node->getText(), $matches); + $prices[] = [ + 'qty' => isset($matches[1]) ? $matches[1] : null, + 'price_qty' => isset($matches[2]) ? $matches[2] : null, + ]; + } + return $prices; + } + /** * Get block price. * @@ -139,6 +160,8 @@ class ConfigurableOptions extends CustomOptions } /** + * Select option from the select element. + * * @param string $attributeTitle * @param string $optionTitle */ @@ -147,4 +170,22 @@ class ConfigurableOptions extends CustomOptions $this->_rootElement->find(sprintf($this->optionSelector, $attributeTitle), Locator::SELECTOR_XPATH, 'select') ->setValue($optionTitle); } + + /** + * Choose options of the configurable product + * + * @param $variationOptions + * @param $attributesData + * @return void + */ + protected function chooseOptions($variationOptions, $attributesData) + { + //Select all options specified in variation + foreach ($variationOptions as $variationSelection) { + list ($attribute, $option) = explode(':', $variationSelection); + $attributeTitle = $attributesData[$attribute]['label']; + $optionTitle = $attributesData[$attribute]['options'][$option]['label']; + $this->selectOption($attributeTitle, $optionTitle); + } + } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductTierPriceOnProductPage.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductTierPriceOnProductPage.php new file mode 100644 index 0000000000000000000000000000000000000000..74c885a727880edffd79717f5f30689135a3704d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductTierPriceOnProductPage.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\ConfigurableProduct\Test\Constraint; + +use Magento\Catalog\Test\Constraint\AssertProductPage; +use Magento\ConfigurableProduct\Test\Block\Product\View\ConfigurableOptions; + +/** + * Open created configurble product on frontend and choose variation with tier price + */ +class AssertProductTierPriceOnProductPage extends AssertProductPage +{ + /** + * Verify that tier prices configured for all variations of configured product displayed as expected. + * + * @return array + */ + public function verify() + { + $errors = []; + /** @var ConfigurableOptions $optionsBlock */ + $optionsBlock = $this->pageView->getConfigurableAttributesBlock(); + $formTierPrices = $optionsBlock->getOptionsPrices($this->product); + $products = ($this->product->getDataFieldConfig('configurable_attributes_data')['source'])->getProducts(); + foreach ($products as $key => $product) { + $configuredTierPrice = []; + $actualTierPrices = isset($formTierPrices[$key]['tierPrices']) ? $formTierPrices[$key]['tierPrices'] : []; + $tierPrices = $product->getTierPrice() ?: []; + foreach ($tierPrices as $tierPrice) { + $configuredTierPrice[] = [ + 'qty' => $tierPrice['price_qty'], + 'price_qty' => $tierPrice['price'], + ]; + } + + if ($configuredTierPrice != $actualTierPrices) { + $errors[] = sprintf('Tier prices for variation %s doesn\'t equals to configured.', $key); + } + } + + return $errors; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/OrderCreateIndex.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/OrderCreateIndex.xml index a67119cbf19aa5ac5aa1541672a30242edd29a93..97809af4bff7875f1bb4c90fe0f3a9c05d037b24 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/OrderCreateIndex.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/OrderCreateIndex.xml @@ -6,9 +6,9 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/pages.xsd"> - <page name="OrderCreateIndex" area="Adminhtml" mca="sales/order_create/index"> - <block name="configureProductBlock"> - <render name="configurable" class="Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Composite\Configure"/> - </block> - </page> + <page name="OrderCreateIndex" area="Adminhtml" mca="sales/order_create/index"> + <block name="configureProductBlock"> + <render name="configurable" class="Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Composite\Configure" /> + </block> + </page> </config> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Product/CatalogProductView.xml index c2c5d8428b480dd5ccae46f67d2065bc203b8331..c825f733de1790ef5e8f0a81ad38c37a493df12f 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Product/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Product/CatalogProductView.xml @@ -10,6 +10,6 @@ <block name="viewBlock"> <render name="configurable" class="Magento\ConfigurableProduct\Test\Block\Product\View"/> </block> - <block name="configurableAttributesBlock" class="Magento\ConfigurableProduct\Test\Block\Product\View\ConfigurableOptions" locator="#product-options-wrapper" strategy="css selector"/> + <block name="configurableAttributesBlock" class="Magento\ConfigurableProduct\Test\Block\Product\View\ConfigurableOptions" locator=".product-info-main" strategy="css selector"/> </page> </config> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml index bb9f7a4ae03b19500b954e187a8765121579acf7..949c6dc065c494a18e2ae617ef859f6663dd05d4 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml @@ -154,6 +154,22 @@ </field> </dataset> + <dataset name="configurable_two_new_options_with_tier_price"> + <field name="options" xsi:type="array"> + <item name="configurable_options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">attribute_key_0</item> + <item name="value" xsi:type="string">option_key_1</item> + </item> + </item> + </field> + <field name="cartItem" xsi:type="array"> + <item name="price" xsi:type="string">9</item> + <item name="qty" xsi:type="string">1</item> + <item name="subtotal" xsi:type="string">9</item> + </field> + </dataset> + <dataset name="configurable_two_options_with_assigned_product"> <field name="options" xsi:type="array"> <item name="configurable_options" xsi:type="array"> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml index cf9d73d3dcd2e727dc7cdb290ecf74d17a453c31..44e2e14545db02103bfe2fa2613f196937cfc558 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml @@ -440,6 +440,42 @@ </field> </dataset> + <dataset name="two_options_with_assigned_product_tier_price"> + <field name="attributes_data" xsi:type="array"> + <item name="attribute_key_0" xsi:type="array"> + <item name="options" xsi:type="array"> + <item name="option_key_0" xsi:type="array"> + <item name="label" xsi:type="string">option_key_1_%isolation%</item> + <item name="pricing_value" xsi:type="string">560</item> + <item name="include" xsi:type="string">Yes</item> + </item> + <item name="option_key_1" xsi:type="array"> + <item name="label" xsi:type="string">option_key_2_%isolation%</item> + <item name="pricing_value" xsi:type="string">10</item> + <item name="include" xsi:type="string">Yes</item> + </item> + </item> + </item> + </field> + <field name="attributes" xsi:type="array"> + <item name="attribute_key_0" xsi:type="string">catalogProductAttribute::attribute_type_dropdown_two_options</item> + </field> + <field name="products" xsi:type="array"> + <item name="attribute_key_0:option_key_0" xsi:type="string">catalogProductSimple::default</item> + <item name="attribute_key_0:option_key_1" xsi:type="string">catalogProductSimple::simple_with_tier_price</item> + </field> + <field name="matrix" xsi:type="array"> + <item name="attribute_key_0:option_key_0" xsi:type="array"> + <item name="qty" xsi:type="string">10</item> + <item name="weight" xsi:type="string">1</item> + </item> + <item name="attribute_key_0:option_key_1" xsi:type="array"> + <item name="qty" xsi:type="string">20</item> + <item name="weight" xsi:type="string">1</item> + </item> + </field> + </dataset> + <dataset name="color_and_size"> <field name="attributes_data" xsi:type="array"> <item name="attribute_key_0" xsi:type="array"> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml index 14ff24f18908da187a0631662cf74bfdaad5db6f..42277101cfbdaf5622efb6b4347dafb75bb113aa 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml @@ -159,5 +159,19 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" /> <constraint name="Magento\Catalog\Test\Constraint\AssertProductOnCustomWebsite" /> </variation> + <variation name="CreateConfigurableProductEntityTestVariation10" summary="Create configurable product with tier price for one item"> + <data name="product/data/url_key" xsi:type="string">configurable-product-%isolation%</data> + <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_options_with_assigned_product_tier_price</data> + <data name="product/data/checkout_data/dataset" xsi:type="string">configurable_two_new_options_with_special_price</data> + <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> + <data name="product/data/sku" xsi:type="string">configurable_sku_%isolation%</data> + <data name="product/data/price/value" xsi:type="string">1</data> + <data name="product/data/weight" xsi:type="string">2</data> + <data name="product/data/category_ids/dataset" xsi:type="string">default_subcategory</data> + <data name="product/data/short_description" xsi:type="string">Configurable short description</data> + <data name="product/data/description" xsi:type="string">Configurable Product description %isolation%</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" /> + <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertProductTierPriceOnProductPage" /> + </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml index dd92edc82b3310ad9610c70138578a220e4358cd..8a8195db638d565564ae0e2bdf20ad46fbb05bbd 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml @@ -14,6 +14,7 @@ <data name="order/dataset" xsi:type="string">default</data> <data name="order/data/entity_id/products" xsi:type="string">configurableProduct::configurable_with_qty_1</data> <data name="order/data/price/dataset" xsi:type="string">full_refund</data> + <data name="configData" xsi:type="string"/> <constraint name="Magento\Sales\Test\Constraint\AssertRefundSuccessCreateMessage" /> <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertProductQtyDecreasedAfterCreditmemo" /> </variation> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..aaa9b3e1f88f918aa63f852b28a5ac653f94cdef --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Sales\Test\TestCase\MoveRecentlyComparedProductsOnOrderPageTest"> + <variation name="MoveRecentlyComparedProductsOnOrderPageTestVariationWithConfigurableProduct1"> + <data name="products/0" xsi:type="string">configurableProduct::configurable_with_qty_1</data> + <data name="products/1" xsi:type="string">configurableProduct::configurable_with_qty_1</data> + <constraint name="Magento\Sales\Test\Constraint\AssertProductInItemsOrderedGrid" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/di.xml index 002ccfc4ed80ca48fb1b851558efa909b2e1c503..8bdf098cea58341cf83b081fca7bc946281e4884 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/di.xml @@ -26,4 +26,17 @@ <argument name="severity" xsi:type="string">high</argument> </arguments> </type> + <type name="Magento\Sales\Test\Block\Adminhtml\Order\Create\CustomerActivities\Sidebar\RecentlyComparedProducts"> + <arguments> + <argument name="config" xsi:type="array"> + <item name="renders" xsi:type="array"> + <item name="configurable" xsi:type="array"> + <item name="class" xsi:type="string">Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Composite\Configure</item> + <item name="locator" xsi:type="string">//ancestor::body//*[contains(@class, "modal-slide") and contains(@class, "_show")]</item> + <item name="strategy" xsi:type="string">xpath</item> + </item> + </item> + </argument> + </arguments> + </type> </config> diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.xml index 8baa7ce0d9310f7e2d7a17fab8c904530cf25629..ba85d0d13bfc68761ea562802f259dcda28ff738 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.xml @@ -241,6 +241,40 @@ <field name="telephone" xsi:type="string">333-33-333-33</field> </dataset> + <dataset name="DE_address_Frankfurt"> + <field name="firstname" xsi:type="string">Jan</field> + <field name="lastname" xsi:type="string">Jansen</field> + <field name="company" xsi:type="string">Magento %isolation%</field> + <field name="city" xsi:type="string">Frankfurt</field> + <field name="street" xsi:type="string">Marzellenstrasse 13-17</field> + <field name="postcode" xsi:type="string">10789</field> + <field name="country_id" xsi:type="string">Germany</field> + <field name="region" xsi:type="string">Hessen</field> + <field name="telephone" xsi:type="string">333-33-333-33</field> + </dataset> + + <dataset name="KE_Nairobi"> + <field name="firstname" xsi:type="string">John</field> + <field name="lastname" xsi:type="string">Doe</field> + <field name="company" xsi:type="string">Magento %isolation%</field> + <field name="city" xsi:type="string">Nairobi</field> + <field name="street" xsi:type="string">6161 West Centinela Avenue</field> + <field name="telephone" xsi:type="string">555-55-555-55</field> + <field name="country_id" xsi:type="string">Kenya</field> + <field name="postcode" xsi:type="string">12345</field> + </dataset> + + <dataset name="KE_Mombasa"> + <field name="firstname" xsi:type="string">John</field> + <field name="lastname" xsi:type="string">Doe</field> + <field name="company" xsi:type="string">Magento %isolation%</field> + <field name="city" xsi:type="string">Mombasa</field> + <field name="street" xsi:type="string">6161 West Centinela Avenue</field> + <field name="telephone" xsi:type="string">555-55-555-55</field> + <field name="country_id" xsi:type="string">Kenya</field> + <field name="postcode" xsi:type="string">12345</field> + </dataset> + <dataset name="customer_UK_US_addresses"> <field name="firstname" xsi:type="string">John</field> <field name="lastname" xsi:type="string">Doe%isolation%</field> diff --git a/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/CityBasedShippingRateTest.xml b/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/CityBasedShippingRateTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..e54439c8cd05c5537542d1769d58714d89fc4fb2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/CityBasedShippingRateTest.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Shipping\Test\TestCase\CityBasedShippingRateTest" summary="Shipping rates can be reloaded based on changes in City field value"> + <variation name="CityBasedShippingRateDHLTestVariation" summary="Shipping rates can be reloaded based on changes in City field value for DHL shipping method" ticketId="MAGETWO-56124"> + <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S1</data> + <data name="products/0" xsi:type="string">catalogProductSimple::default</data> + <data name="checkoutMethod" xsi:type="string">guest</data> + <data name="customer/dataset" xsi:type="string">default</data> + <data name="shippingMethod/shipping_service" xsi:type="string">DHL</data> + <data name="shippingMethod/shipping_method" xsi:type="string">Express easy</data> + <data name="clearShippingAddress/postcode" xsi:type="string" /> + <data name="clearShippingAddress/city" xsi:type="string" /> + <data name="clearShippingAddress/country_id" xsi:type="string" /> + <data name="shippingAddresses/0/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/1/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/1/postcode" xsi:type="string">12345</data> + <data name="shippingAddresses/2/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/2/postcode" xsi:type="string">12345</data> + <data name="shippingAddresses/2/city" xsi:type="string">Nairobi</data> + <data name="shippingAddresses/3/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/3/postcode" xsi:type="string">12345</data> + <data name="shippingAddresses/3/city" xsi:type="string">Mombasa</data> + <data name="shippingAddresses/4/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/4/city" xsi:type="string">Mombasa</data> + <data name="shippingAddresses/5/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/5/city" xsi:type="string">Nairobi</data> + <data name="isShippingAvailable" xsi:type="array"> + <item name="0" xsi:type="boolean">false</item> + <item name="1" xsi:type="boolean">false</item> + <item name="2" xsi:type="boolean">true</item> + <item name="3" xsi:type="boolean">true</item> + <item name="4" xsi:type="boolean">true</item> + <item name="5" xsi:type="boolean">true</item> + </data> + <data name="configData" xsi:type="string">dhl_eu, shipping_origin_CH, config_base_currency_ch</data> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/CityBasedShippingRateTest.xml b/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/CityBasedShippingRateTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..b6a2fd5776a27d307e7c0f8372438b42f38fd7f5 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/CityBasedShippingRateTest.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Shipping\Test\TestCase\CityBasedShippingRateTest" summary="Shipping rates can be reloaded based on changes in City field value"> + <variation name="CityBasedShippingRateFedexTestVariation" summary="Shipping rates can be reloaded based on changes in City field value for Fedex shipping method" ticketId="MAGETWO-56124"> + <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S1</data> + <data name="products/0" xsi:type="string">catalogProductSimple::default</data> + <data name="checkoutMethod" xsi:type="string">guest</data> + <data name="customer/dataset" xsi:type="string">default</data> + <data name="shippingMethod/shipping_service" xsi:type="string">Federal Express</data> + <data name="shippingMethod/shipping_method" xsi:type="string">International Economy</data> + <data name="clearShippingAddress/postcode" xsi:type="string" /> + <data name="clearShippingAddress/city" xsi:type="string" /> + <data name="clearShippingAddress/country_id" xsi:type="string" /> + <data name="shippingAddresses/0/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/1/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/1/postcode" xsi:type="string">12345</data> + <data name="shippingAddresses/2/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/2/postcode" xsi:type="string">12345</data> + <data name="shippingAddresses/2/city" xsi:type="string">Nairobi</data> + <data name="shippingAddresses/3/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/3/postcode" xsi:type="string">12345</data> + <data name="shippingAddresses/3/city" xsi:type="string">Mombasa</data> + <data name="shippingAddresses/4/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/4/city" xsi:type="string">Mombasa</data> + <data name="shippingAddresses/5/country_id" xsi:type="string">Kenya</data> + <data name="shippingAddresses/5/city" xsi:type="string">Nairobi</data> + <data name="isShippingAvailable" xsi:type="array"> + <item name="0" xsi:type="boolean">false</item> + <item name="1" xsi:type="boolean">true</item> + <item name="2" xsi:type="boolean">true</item> + <item name="3" xsi:type="boolean">true</item> + <item name="4" xsi:type="boolean">false</item> + <item name="5" xsi:type="boolean">false</item> + </data> + <data name="configData" xsi:type="string">fedex, shipping_origin_US_CA</data> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Composite/Configure.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Composite/Configure.xml index 04a918c3bf8d9598b74b0f53ebd41b9f477e778f..676ae6a64f3d820b4d65d821053d6d0ab7971542 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Composite/Configure.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Composite/Configure.xml @@ -8,7 +8,7 @@ <mapping strict="0"> <fields> <qty> - <selector>//tr[contains(.,"%product_name%")]//input[contains(@class,"qty")]</selector> + <selector>.//tr[contains(.,"%product_name%")]//input[contains(@class,"qty")]</selector> <strategy>xpath</strategy> </qty> </fields> diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertProductInItemsOrderedGrid.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertProductInItemsOrderedGrid.php new file mode 100644 index 0000000000000000000000000000000000000000..918c86f93340730e19ac576c1cda37255d86f0b3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertProductInItemsOrderedGrid.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\GroupedProduct\Test\Constraint; + +/** + * Assert product was added to Items Ordered grid in customer account on Order creation page backend. + */ +class AssertProductInItemsOrderedGrid extends \Magento\Sales\Test\Constraint\AssertProductInItemsOrderedGrid +{ + /** + * Prepare data. + * + * @param array $data + * @param \Magento\Sales\Test\Block\Adminhtml\Order\Create\Items $itemsBlock + * @return array + */ + protected function prepareData(array $data, \Magento\Sales\Test\Block\Adminhtml\Order\Create\Items $itemsBlock) + { + $fixtureData = []; + foreach ($data as $product) { + $fixtureData = array_merge($fixtureData, $this->getOptionsDetails($product)); + } + $pageData = $itemsBlock->getProductsDataByFields($this->fields); + $preparePageData = $this->arraySort($fixtureData, $pageData); + return ['fixtureData' => $fixtureData, 'pageData' => $preparePageData]; + } + + /** + * Get product options details. + * + * @param \Magento\Mtf\Fixture\FixtureInterface $product + * @return array + */ + private function getOptionsDetails(\Magento\Mtf\Fixture\FixtureInterface $product) + { + /** @var \Magento\GroupedProduct\Test\Fixture\GroupedProduct $product */ + $fixtureProducts = []; + $optionsPrices = $this->getProductPrice($product); + $optionsQtys = $product->getCheckoutData()['cartItem']['qty']; + $assignedProducts = $product->getAssociated()['assigned_products']; + + foreach ($assignedProducts as $key => $assignedProduct) { + $fixtureProducts[] = [ + 'name' => $assignedProduct['name'], + 'price' => number_format($optionsPrices['product_key_' . $key], 2), + 'checkout_data' => [ + 'qty' => $this->productsIsConfigured ? $optionsQtys['product_key_' . $key] : 1 + ] + ]; + } + return $fixtureProducts; + } +} diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..1de8aeda4e9a4415b476d73c8b454b17ad4f5824 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Sales\Test\TestCase\MoveRecentlyComparedProductsOnOrderPageTest"> + <variation name="MoveRecentlyComparedProductsOnOrderPageTestVariationWithGroupedProduct1"> + <data name="products/0" xsi:type="string">groupedProduct::three_simple_products</data> + <data name="products/1" xsi:type="string">groupedProduct::three_simple_products</data> + <data name="productsIsConfigured" xsi:type="boolean">true</data> + <constraint name="Magento\GroupedProduct\Test\Constraint\AssertProductInItemsOrderedGrid" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..5b12a012749fb6feb0e90b1910d964a19394ca8d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/di.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\Sales\Test\Block\Adminhtml\Order\Create\CustomerActivities\Sidebar\RecentlyComparedProducts"> + <arguments> + <argument name="config" xsi:type="array"> + <item name="renders" xsi:type="array"> + <item name="grouped" xsi:type="array"> + <item name="class" xsi:type="string">\Magento\GroupedProduct\Test\Block\Adminhtml\Product\Composite\Configure</item> + <item name="locator" xsi:type="string">//ancestor::body//*[contains(@class, "modal-slide") and contains(@class, "_show")]</item> + <item name="strategy" xsi:type="string">xpath</item> + </item> + </item> + </argument> + </arguments> + </type> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutTest.xml index f6ac4ac4f0a3c4591c12de7215600010c5fb857c..11f9d9d5270e679df9cd5237b4a51139cb51475e 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutTest.xml @@ -21,7 +21,7 @@ </data> <data name="creditCardClass" xsi:type="string">credit_card</data> <data name="creditCard/dataset" xsi:type="string">visa_default</data> - <data name="isVaultEnabled" xsi:type="boolean">false</data> + <data name="isVaultPresent" xsi:type="boolean">false</data> <data name="configData" xsi:type="string">payflowpro</data> <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S1</data> <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml index b1da43e473bc5d78d4bfaf0fbcbb718dac6acd3e..ad937cf472de7145429b16983288df69bb851134 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml @@ -7,7 +7,7 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Vault\Test\TestCase\ReorderUsingVaultTest" summary="Reorder from Admin with saved within PayPal Payflow Pro credit card"> - <variation name="ReorderUsingVaultPayflowProTestVariation1" summary="Reorder from Admin with saved within PayPal Payflow Pro credit card for Guest Customer" ticketId="MAGETWO-54872"> + <variation name="ReorderUsingVaultPayflowProTestVariation1" summary="Reorder from Admin with saved within PayPal Payflow Pro credit card for Guest Customer" ticketId="MAGETWO-34217, MAGETWO-54872"> <data name="description" xsi:type="string">Reorder from Admin with saved within PayPal Payflow Pro credit card for Guest Customer</data> <data name="products/0" xsi:type="string">catalogProductSimple::product_10_dollar</data> <data name="customer/dataset" xsi:type="string">default</data> diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/CustomerActivities/Sidebar.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/CustomerActivities/Sidebar.php index 050f797d83825e99eaf08728c2dc69149f8faaae..3fc41e0db1785d06eb29bd58b7343b02a274ee00 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/CustomerActivities/Sidebar.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/CustomerActivities/Sidebar.php @@ -21,6 +21,13 @@ abstract class Sidebar extends Block */ protected $addToOrder = './/tr[td[.="%s"]]//input[contains(@name,"add")]'; + /** + * 'Add to order' configure. + * + * @var string + */ + protected $addToOrderConfigure = './/tr[td[contains(.,"%s")]]//a[contains(@class, "icon-configure")]'; + /** * 'Add to order' checkbox. * @@ -39,9 +46,18 @@ abstract class Sidebar extends Block foreach ($products as $product) { $name = $product->getName(); $this->_rootElement->find(sprintf($this->addToOrderProductName, $name), Locator::SELECTOR_XPATH)->click(); - $this->_rootElement->click(); - $this->_rootElement->find(sprintf($this->addToOrder, $name), Locator::SELECTOR_XPATH, 'checkbox') - ->setValue('Yes'); + + $dataConfig = $product->getDataConfig(); + $typeId = isset($dataConfig['type_id']) ? $dataConfig['type_id'] : null; + + if ($this->hasRender($typeId)) { + $this->_rootElement->find(sprintf($this->addToOrderConfigure, $name), Locator::SELECTOR_XPATH)->click(); + $this->callRender($typeId, 'configProduct', ['product' => $product]); + } else { + $this->_rootElement->click(); + $this->_rootElement->find(sprintf($this->addToOrder, $name), Locator::SELECTOR_XPATH, 'checkbox') + ->setValue('Yes'); + } } } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Invoices/Grid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Invoices/Grid.php index d1f27d14a6619f71fc2e459adad23888d4fb51b7..4b3768295799695fbb45db1a17e75acb193b91f7 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Invoices/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Invoices/Grid.php @@ -9,7 +9,7 @@ namespace Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Invoices; /** * Invoices grid on order view page. */ -class Grid extends \Magento\Backend\Test\Block\Widget\Grid +class Grid extends \Magento\Ui\Test\Block\Adminhtml\DataGrid { /** * Locator value for link in action column. @@ -34,6 +34,9 @@ class Grid extends \Magento\Backend\Test\Block\Widget\Grid 'id' => [ 'selector' => 'input[name="increment_id"]', ], + 'order_id' => [ + 'selector' => 'input[name="order_increment_id"]', + ], 'status' => [ 'selector' => 'select[name="state"]', 'input' => 'select', diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php new file mode 100644 index 0000000000000000000000000000000000000000..6695786923b5c00c71e12101855421554e940281 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Sales\Test\Constraint; + +use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; +use Magento\Mtf\Constraint\AbstractConstraint; + +/** + * Assert invoice status on order page in Admin. + */ +class AssertInvoiceStatusInOrdersGrid extends AbstractConstraint +{ + /** + * Assert invoice status on order page in Admin. + * + * @param SalesOrderView $salesOrderView + * @param string $invoiceStatus + * @param string $orderId + * @return void + */ + public function processAssert( + SalesOrderView $salesOrderView, + $invoiceStatus, + $orderId + ) { + $salesOrderView->open(['order_id' => $orderId]); + $salesOrderView->getOrderForm()->openTab('invoices'); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Invoices\Grid $grid */ + $grid = $salesOrderView->getOrderForm()->getTab('invoices')->getGridBlock(); + $filter = [ + 'order_id' => $orderId, + 'status' => $invoiceStatus, + ]; + \PHPUnit_Framework_Assert::assertTrue( + $grid->isRowVisible($filter), + 'Invoice status is incorrect.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Invoice status is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.php index 49487ff1b2e8ea9b9e23543a44a2878b797c4f2c..a501ec3cd228d8c60a5225027719e463dbf6c688 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.php @@ -142,9 +142,10 @@ class MoveRecentlyComparedProductsOnOrderPageTest extends Injectable * * @param Customer $customer * @param string $products + * @param bool $productsIsConfigured * @return array */ - public function test(Customer $customer, $products) + public function test(Customer $customer, $products, $productsIsConfigured = false) { // Preconditions // Create product @@ -168,6 +169,6 @@ class MoveRecentlyComparedProductsOnOrderPageTest extends Injectable $activitiesBlock->getRecentlyComparedProductsBlock()->addProductsToOrder($products); $activitiesBlock->updateChanges(); - return ['products' => $products, 'productsIsConfigured' => false]; + return ['products' => $products, 'productsIsConfigured' => $productsIsConfigured]; } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml index 601f550e4588bfd3c613ef8a50e8615174b298ae..76282ff3eec53867d257029f5184b941899ac2db 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml @@ -7,17 +7,10 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Sales\Test\TestCase\MoveRecentlyComparedProductsOnOrderPageTest" summary="Add Products to Order from Recently Compared Products Section" ticketId="MAGETWO-28109"> - <variation name="MoveRecentlyComparedProductsOnOrderPageTestVariation1"> - <data name="tag" xsi:type="string">stable:no</data> + <variation name="MoveRecentlyComparedProductsOnOrderPageTestVariationWithSimpleProduct1"> <data name="products/0" xsi:type="string">catalogProductSimple::default</data> <data name="products/1" xsi:type="string">catalogProductSimple::default</data> <constraint name="Magento\Sales\Test\Constraint\AssertProductInItemsOrderedGrid" /> </variation> - <variation name="MoveRecentlyComparedProductsOnOrderPageTestVariation2"> - <data name="tag" xsi:type="string">to_maintain:yes</data> - <data name="products/0" xsi:type="string">configurableProduct::configurable_with_qty_1</data> - <data name="products/1" xsi:type="string">configurableProduct::configurable_with_qty_1</data> - <constraint name="Magento\Sales\Test\Constraint\AssertProductInItemsOrderedGrid" /> - </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml index f42c97e1a6614a927da685f9cd5e1f8c84ff0c32..df10cccbd82136f027f4ee6b236cafe272cdbdc8 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml @@ -11,6 +11,11 @@ <argument name="severity" xsi:type="string">S0</argument> </arguments> </type> + <type name="Magento\Sales\Test\Constraint\AssertInvoiceStatusInOrdersGrid"> + <arguments> + <argument name="severity" xsi:type="string">S1</argument> + </arguments> + </type> <type name="Magento\Sales\Test\Constraint\AssertOrderStatusDuplicateStatus"> <arguments> <argument name="severity" xsi:type="string">S0</argument> diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertCityBasedShippingRateChanged.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertCityBasedShippingRateChanged.php new file mode 100644 index 0000000000000000000000000000000000000000..a10b47a2f9950f311d4c8ebcbdd3babb46faf6a8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertCityBasedShippingRateChanged.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Shipping\Test\Constraint; + +use Magento\Checkout\Test\Page\CheckoutOnepage; +use Magento\Mtf\Constraint\AbstractConstraint; + +/** + * Check that Shipping rate changes due to City change. + */ +class AssertCityBasedShippingRateChanged extends AbstractConstraint +{ + /** + * Assert that Shipping rate changed on City change. + * + * @param CheckoutOnepage $checkoutOnepage + * @param array $shippingMethod + * @param bool $isShippingAvailable + * @return void + */ + public function processAssert(CheckoutOnepage $checkoutOnepage, $shippingMethod, $isShippingAvailable) + { + if ($isShippingAvailable) { + \PHPUnit_Framework_Assert::assertTrue( + $checkoutOnepage->getShippingMethodBlock()->isLoaderAppeared(), + 'Shipping rate has not been changed.' + ); + } + $shippingAvaialability = $isShippingAvailable ? 'avaiable' : 'unavailable'; + \PHPUnit_Framework_Assert::assertEquals( + $isShippingAvailable, + $checkoutOnepage->getShippingMethodBlock()->isShippingMethodAvaiable($shippingMethod), + "Shipping rates for {$shippingMethod['shipping_service']} should be $shippingAvaialability." + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Shipping rate has been changed."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/CityBasedShippingRateTest.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/CityBasedShippingRateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..294cf129c607308425fc6e9a3574b047d8b2ff18 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/CityBasedShippingRateTest.php @@ -0,0 +1,44 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Shipping\Test\TestCase; + +use Magento\Mtf\TestCase\Scenario; + +/** + * Preconditions: + * 1. Configure shipping method. + * 2. Create products. + * 3. Create and setup customer. + * + * Steps: + * 1. Go to Frontend. + * 2. Add products to the cart. + * 3. Click the 'Proceed to Checkout' button. + * 4. Fill shipping information. + * 5. Perform assertions. + * + * @group Shipping + * @ZephyrId MAGETWO-56124 + */ +class CityBasedShippingRateTest extends Scenario +{ + /* tags */ + const MVP = 'yes'; + const TEST_TYPE = '3rd_party_test'; + const SEVERITY = 'S1'; + /* end tags */ + + /** + * Runs City Based Shipping Rate test. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/TestStep/FillShippingAddressesStep.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestStep/FillShippingAddressesStep.php new file mode 100644 index 0000000000000000000000000000000000000000..8a0f5ea7e269d71234e3cdacbc8c570c6bb040ed --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestStep/FillShippingAddressesStep.php @@ -0,0 +1,98 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Shipping\Test\TestStep; + +use Magento\Mtf\Fixture\FixtureFactory; +use Magento\Mtf\TestStep\TestStepInterface; +use Magento\Customer\Test\Fixture\Address; +use Magento\Checkout\Test\Page\CheckoutOnepage; +use Magento\Shipping\Test\Constraint\AssertCityBasedShippingRateChanged; + +/** + * Fill shipping addresses and assert rates relouding. + */ +class FillShippingAddressesStep implements TestStepInterface +{ + /** + * Onepage checkout page. + * + * @var CheckoutOnepage + */ + private $checkoutOnepage; + + /** + * Address fixture. + * + * @var Address[] + */ + private $shippingAddresses; + + /** + * Assert City based Shipping rate. + * + * @var array + */ + private $assertRate; + + /** + * @var array + */ + private $isShippingAvailable; + + /** + * Shipping method. + * + * @var array + */ + private $shippingMethod; + + /** + * @param CheckoutOnepage $checkoutOnepage + * @param FixtureFactory $fixtureFactory + * @param AssertCityBasedShippingRateChanged $assertRate + * @param array $shippingMethod + * @param array $shippingAddresses + * @param array $clearShippingAddress + * @param array $isShippingAvailable + */ + public function __construct( + CheckoutOnepage $checkoutOnepage, + FixtureFactory $fixtureFactory, + AssertCityBasedShippingRateChanged $assertRate, + array $shippingMethod, + array $shippingAddresses, + array $clearShippingAddress, + array $isShippingAvailable + ) { + $this->checkoutOnepage = $checkoutOnepage; + $this->assertRate = $assertRate; + + foreach ($shippingAddresses as $address) { + $data = array_merge($clearShippingAddress, $address); + $this->shippingAddresses[] = $fixtureFactory->createByCode('address', ['data' => $data]); + } + $this->isShippingAvailable = $isShippingAvailable; + $this->shippingMethod = $shippingMethod; + } + + /** + * Fill shipping address and assert if the shipping rates is reloaded. + * + * @return void + */ + public function run() + { + foreach ($this->shippingAddresses as $key => $shippingAddress) { + $this->checkoutOnepage->getShippingBlock()->fill($shippingAddress); + $this->assertRate->processAssert( + $this->checkoutOnepage, + $this->shippingMethod, + $this->isShippingAvailable[$key] + ); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..d0d24b810fb44bd0caa7dec1e6b302006904b102 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/di.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\Shipping\Test\Constraint\AssertCityBasedShippingRateChanged"> + <arguments> + <argument name="severity" xsi:type="string">S1</argument> + </arguments> + </type> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/testcase.xml new file mode 100644 index 0000000000000000000000000000000000000000..b1fabed80066b6933f58f89e69aa59ea20042d65 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/testcase.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/TestCase/etc/testcase.xsd"> + <scenario name="CityBasedShippingRateTest" firstStep="setupConfiguration"> + <step name="setupConfiguration" module="Magento_Config" next="createProducts" /> + <step name="createProducts" module="Magento_Catalog" next="addProductsToTheCart" /> + <step name="addProductsToTheCart" module="Magento_Checkout" next="proceedToCheckout" /> + <step name="proceedToCheckout" module="Magento_Checkout" next="createCustomer" /> + <step name="createCustomer" module="Magento_Customer" next="selectCheckoutMethod" /> + <step name="selectCheckoutMethod" module="Magento_Checkout" next="fillShippingAddresses" /> + <step name="fillShippingAddresses" module="Magento_Shipping" /> + </scenario> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/CheckSaveCreditCardOptionStep.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/CheckSaveCreditCardOptionStep.php index b0f33872103f27ffe00e2b1323574fa0fdc6b88a..eee0f1be86ef79198a7864df8be90e8a225ea840 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/CheckSaveCreditCardOptionStep.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/CheckSaveCreditCardOptionStep.php @@ -36,28 +36,28 @@ class CheckSaveCreditCardOptionStep implements TestStepInterface private $payment; /** - * If vault is enabled for payment method. + * If 'Save for later use' checkbox is present in credit card form. * * @var null|bool */ - private $isVaultEnabled; + private $isVaultPresent; /** * @param CheckoutOnepage $checkoutOnepage * @param AssertSaveCreditCardOptionNotPresent $assertSaveCreditCardOptionNotPresent * @param array $payment - * @param null|bool $isVaultEnabled + * @param null|bool $isVaultPresent */ public function __construct( CheckoutOnepage $checkoutOnepage, AssertSaveCreditCardOptionNotPresent $assertSaveCreditCardOptionNotPresent, array $payment, - $isVaultEnabled = null + $isVaultPresent = null ) { $this->checkoutOnepage = $checkoutOnepage; $this->assertSaveCreditCardOptionNotPresent = $assertSaveCreditCardOptionNotPresent; $this->payment = $payment; - $this->isVaultEnabled = $isVaultEnabled; + $this->isVaultPresent = $isVaultPresent; } /** @@ -67,7 +67,7 @@ class CheckSaveCreditCardOptionStep implements TestStepInterface */ public function run() { - if ($this->isVaultEnabled === false) { + if ($this->isVaultPresent === false) { $this->assertSaveCreditCardOptionNotPresent->processAssert( $this->checkoutOnepage, $this->payment['method'] diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Vault/Test/etc/testcase.xml index 6289a8392ee7544777959e8afffe9fd999388713..ee55d7ef5ba905973cbbfb38effab1ccc7f750e0 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/etc/testcase.xml @@ -56,7 +56,8 @@ <step name="selectCheckoutMethod" module="Magento_Checkout" next="fillShippingAddress" /> <step name="fillShippingAddress" module="Magento_Checkout" next="fillShippingMethod" /> <step name="fillShippingMethod" module="Magento_Checkout" next="selectPaymentMethod" /> - <step name="selectPaymentMethod" module="Magento_Checkout" next="fillBillingInformation" /> + <step name="selectPaymentMethod" module="Magento_Checkout" next="checkSaveCreditCardOption" /> + <step name="checkSaveCreditCardOption" module="Magento_Vault" next="fillBillingInformation" /> <step name="fillBillingInformation" module="Magento_Checkout" next="placeOrder" /> <step name="placeOrder" module="Magento_Checkout" next="openOrder" /> <step name="openOrder" module="Magento_Sales" next="reorder" /> diff --git a/dev/tests/integration/testsuite/Magento/Authorizenet/Model/Directpost/RequestTest.php b/dev/tests/integration/testsuite/Magento/Authorizenet/Model/Directpost/RequestTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ab35c27985da8f13fb2fd4362c719fe0d3267315 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Authorizenet/Model/Directpost/RequestTest.php @@ -0,0 +1,102 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Authorizenet\Model\Directpost; + +use Magento\Authorizenet\Model\Directpost; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\App\ObjectManager; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +/** + * Class contains tests for Authorize.net Direct Post request handler + */ +class RequestTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var Order + */ + private $order; + + /** + * @var Request + */ + private $request; + + /** + * @var ObjectManager + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + + $this->order = $this->getOrder(); + $this->request = $this->objectManager->get(Request::class); + } + + /** + * @covers \Magento\Authorizenet\Model\Directpost\Request::setDataFromOrder + * @magentoDataFixture Magento/Authorizenet/_files/order.php + */ + public function testSetDataFromOrder() + { + $customerEmail = 'john.doe@example.com'; + $merchantEmail = 'merchant@example.com'; + + /** @var Directpost|MockObject $payment */ + $payment = $this->getMockBuilder(Directpost::class) + ->disableOriginalConstructor() + ->setMethods(['getConfigData']) + ->getMock(); + + $payment->expects(static::exactly(2)) + ->method('getConfigData') + ->willReturnMap([ + ['email_customer', null, $customerEmail], + ['merchant_email', null, $merchantEmail] + ]); + + $result = $this->request->setDataFromOrder($this->order, $payment); + + static::assertEquals('US', $result->getXCountry()); + static::assertEquals('UK', $result->getXShipToCountry()); + static::assertEquals($customerEmail, $result->getXEmailCustomer()); + static::assertEquals($merchantEmail, $result->getXMerchantEmail()); + } + + /** + * Get stored order + * @return Order + */ + private function getOrder() + { + /** @var FilterBuilder $filterBuilder */ + $filterBuilder = $this->objectManager->get(FilterBuilder::class); + $filters = [ + $filterBuilder->setField(OrderInterface::INCREMENT_ID) + ->setValue('100000002') + ->create() + ]; + + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilters($filters) + ->create(); + + $orderRepository = $this->objectManager->get(OrderRepositoryInterface::class); + $orders = $orderRepository->getList($searchCriteria) + ->getItems(); + + /** @var OrderInterface $order */ + return array_pop($orders); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php b/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c20db43c127b4a9c058cb206cde14822f9aafd84 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php @@ -0,0 +1,129 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Authorizenet\Model; + +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\HTTP\ZendClient; +use Magento\Framework\HTTP\ZendClientFactory; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order\Payment; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit_Framework_MockObject_MockObject as MockObject; +use Zend_Http_Response; + +/** + * Class contains tests for Direct Post integration + */ +class DirectpostTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var ZendClientFactory|MockObject + */ + private $httpClientFactory; + + /** + * @var Directpost + */ + private $directPost; + + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + + $this->httpClientFactory = $this->getMockBuilder(ZendClientFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->directPost = $this->objectManager->create(Directpost::class, [ + 'httpClientFactory' => $this->httpClientFactory + ]); + } + + /** + * @covers \Magento\Authorizenet\Model\Directpost::capture + * @magentoDataFixture Magento/Authorizenet/_files/order.php + */ + public function testCapture() + { + $amount = 120.15; + /** @var Payment $payment */ + $payment = $this->getPayment(); + $transactionId = '106235225'; + + /** @var ZendClient|MockObject $httpClient */ + $httpClient = $this->getMockBuilder(ZendClient::class) + ->disableOriginalConstructor() + ->setMethods(['setUri', 'setConfig', 'setParameterPost', 'setMethod', 'request']) + ->getMock(); + + $this->httpClientFactory->expects(static::once()) + ->method('create') + ->willReturn($httpClient); + + $response = $this->getMockBuilder(Zend_Http_Response::class) + ->disableOriginalConstructor() + ->setMethods(['getBody']) + ->getMock(); + $response->expects(static::once()) + ->method('getBody') + ->willReturn( + "1(~)1(~)1(~)This transaction has been approved.(~)AWZFTG(~)P(~){$transactionId}(~)100000002(~) + (~)120.15(~)CC(~)prior_auth_capture(~)(~)Anthony(~)Nealy(~)(~)Pearl St(~)Los Angeles(~)California + (~)10020(~)US(~)22-333-44(~)(~)customer@example.com(~)John(~)Doe(~) + (~)Bourne St(~)London(~)(~)DW23W(~)UK(~)0.00(~)(~){$amount}(~)(~) + (~)74B5D54ADFE98093A0FF6446(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)XXXX1111(~)Visa(~)(~)(~)(~)(~) + (~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)" + ); + + $httpClient->expects(static::once()) + ->method('request') + ->willReturn($response); + + $this->directPost->capture($payment, $amount); + + static::assertEquals($transactionId, $payment->getTransactionId()); + static::assertFalse($payment->getIsTransactionClosed()); + static::assertEquals('US', $payment->getOrder()->getBillingAddress()->getCountryId()); + static::assertEquals('UK', $payment->getOrder()->getShippingAddress()->getCountryId()); + } + + /** + * Get order payment + * @return Payment + */ + private function getPayment() + { + /** @var FilterBuilder $filterBuilder */ + $filterBuilder = $this->objectManager->get(FilterBuilder::class); + $filters = [ + $filterBuilder->setField(OrderInterface::INCREMENT_ID) + ->setValue('100000002') + ->create() + ]; + + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilters($filters) + ->create(); + + $orderRepository = $this->objectManager->get(OrderRepositoryInterface::class); + $orders = $orderRepository->getList($searchCriteria) + ->getItems(); + + /** @var OrderInterface $order */ + $order = array_pop($orders); + return $order->getPayment(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Authorizenet/_files/order.php b/dev/tests/integration/testsuite/Magento/Authorizenet/_files/order.php new file mode 100644 index 0000000000000000000000000000000000000000..564ab84a8f8527c61bf8e79f7a57ad53b971089f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Authorizenet/_files/order.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Address; +use Magento\Sales\Model\Order\Payment; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +$amount = 120.15; + +/** @var Payment $payment */ +$payment = $objectManager->get(Payment::class); +$payment + ->setMethod('authorizenet_directpost') + ->setAnetTransType('AUTH_ONLY') + ->setBaseAmountAuthorized($amount) + ->setPoNumber('10101200'); + +/** @var Address\ $billingAddress */ +$billingAddress = $objectManager->create(Address::class, [ + 'data' => [ + 'firstname' => 'John', + 'lastname' => 'Doe', + 'email' => 'customer@example.com', + 'street' => 'Pearl St', + 'city' => 'Los Angeles', + 'region' => 'CA', + 'postcode' => '10020', + 'country_id' => 'US', + 'telephone' => '22-333-44', + 'address_type' => 'billing' + ] +]); + +$shippingAddress = $objectManager->create(Address::class, [ + 'data' => [ + 'firstname' => 'John', + 'lastname' => 'Doe', + 'email' => 'customer@example.com', + 'street' => 'Bourne St', + 'city' => 'London', + 'postcode' => 'DW23W', + 'country_id' => 'UK', + 'telephone' => '22-333-44', + 'address_type' => 'billing' + ] +]); + +/** @var Order $order */ +$order = $objectManager->create(Order::class); +$order->setIncrementId('100000002') + ->setQuoteId(2) + ->setIncrementId('100000002') + ->setBaseGrandTotal($amount) + ->setBaseCurrencyCode('USD') + ->setBaseTaxAmount($amount) + ->setBaseShippingAmount($amount) + ->setCustomerEmail('customer@example.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setPayment($payment); + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +$orderRepository->save($order); diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/Column/Renderer/TextTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/Column/Renderer/TextTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9d2875716156e83b48502be84a4ef1a86ef46772 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/Column/Renderer/TextTest.php @@ -0,0 +1,142 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Backend\Block\Widget\Grid\Column\Renderer; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\ObjectManager; +use Magento\Backend\Block\Widget\Grid\Column; +use Magento\Framework\DataObject; +use Magento\Framework\Phrase; +use Magento\Framework\Phrase\RendererInterface; + +class TextTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var RendererInterface + */ + private $origRenderer; + + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->origRenderer = Phrase::getRenderer(); + /** @var RendererInterface|PHPUnit_Framework_MockObject_MockObject $rendererMock */ + $rendererMock = $this->getMock(RendererInterface::class); + $rendererMock->expects($this->any()) + ->method('render') + ->willReturnCallback( + function ($input) { + return end($input) . ' translated'; + } + ); + Phrase::setRenderer($rendererMock); + } + + protected function tearDown() + { + Phrase::setRenderer($this->origRenderer); + } + + /** + * @param array $columnData + * @param array $rowData + * @param string $expected + * @dataProvider renderDataProvider + */ + public function testRender($columnData, $rowData, $expected) + { + /** @var Text $renderer */ + $renderer = $this->objectManager->create(Text::class); + /** @var Column $column */ + $column = $this->objectManager->create( + Column::class, + [ + 'data' => $columnData + ] + ); + /** @var DataObject $row */ + $row = $this->objectManager->create( + DataObject::class, + [ + 'data' => $rowData + ] + ); + $this->assertEquals( + $expected, + $renderer->setColumn($column)->render($row) + ); + } + + /** + * @return array + */ + public function renderDataProvider() + { + return [ + [ + [ + 'index' => 'title', + 'translate' => true + ], + [ + 'title' => 'String' + ], + 'String translated' + ], + [ + [ + 'index' => 'title' + ], + [ + 'title' => 'Doesn\'t need to be translated' + ], + 'Doesn't need to be translated' + ], + [ + [ + 'format' => '#$subscriber_id $customer_name ($subscriber_email)' + ], + [ + 'subscriber_id' => '10', + 'customer_name' => 'John Doe', + 'subscriber_email' => 'john@doe.com' + ], + '#10 John Doe (john@doe.com)' + ], + [ + [ + 'format' => '$customer_name, email: $subscriber_email', + 'translate' => true + ], + [ + 'customer_name' => 'John Doe', + 'subscriber_email' => 'john@doe.com' + ], + 'John Doe, email: john@doe.com translated' + ], + [ + [ + 'format' => 'String', + 'translate' => true + ], + [], + 'String translated' + ], + [ + [ + 'format' => 'Doesn\'t need to be translated' + ], + [], + 'Doesn't need to be translated' + ] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ProcessorTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ProcessorTest.php index 9c9e564939070e99b097477a221f445811a25ef1..ae954fdc7cfbb7bdc7c66dfb4ab9a25e977e8fae 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ProcessorTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ProcessorTest.php @@ -146,15 +146,15 @@ class ProcessorTest extends \PHPUnit_Framework_TestCase ); $product->setData(['image' => 'test1', 'small_image' => 'test2', 'thumbnail' => 'test3']); - $this->assertNotEmpty($product->getData('image')); + $this->assertNotEquals('no_selection', $product->getData('image')); $this->_model->clearMediaAttribute($product, 'image'); - $this->assertNull($product->getData('image')); + $this->assertEquals('no_selection', $product->getData('image')); - $this->assertNotEmpty($product->getData('small_image')); - $this->assertNotEmpty($product->getData('thumbnail')); + $this->assertNotEquals('no_selection', $product->getData('small_image')); + $this->assertNotEquals('no_selection', $product->getData('thumbnail')); $this->_model->clearMediaAttribute($product, ['small_image', 'thumbnail']); - $this->assertNull($product->getData('small_image')); - $this->assertNull($product->getData('thumbnail')); + $this->assertEquals('no_selection', $product->getData('small_image')); + $this->assertEquals('no_selection', $product->getData('thumbnail')); } public function testSetMediaAttribute() diff --git a/dev/tests/integration/testsuite/Magento/Directory/Model/ObserverTest.php b/dev/tests/integration/testsuite/Magento/Directory/Model/ObserverTest.php index 389fd4b253eb7c8e8a89237f1b7a20be9aa777fe..95fd6110bb432e72daa2af66d7b65f7abbdb3d0f 100644 --- a/dev/tests/integration/testsuite/Magento/Directory/Model/ObserverTest.php +++ b/dev/tests/integration/testsuite/Magento/Directory/Model/ObserverTest.php @@ -62,12 +62,12 @@ class ObserverTest extends \PHPUnit_Framework_TestCase { //skipping test if service is unavailable $url = str_replace('{{CURRENCY_FROM}}', 'USD', - \Magento\Directory\Model\Currency\Import\Webservicex::CURRENCY_CONVERTER_URL + \Magento\Directory\Model\Currency\Import\Webservicex::CURRENCY_CONVERTER_URL ); $url = str_replace('{{CURRENCY_TO}}', 'GBP', $url); try { file_get_contents($url); - } catch (\PHPUnit_Framework_Error_Warning $e) { + } catch (\PHPUnit_Framework_Exception $e) { $this->markTestSkipped('http://www.webservicex.net is unavailable '); } diff --git a/dev/tests/static/framework/Magento/Sniffs/Translation/ConstantUsageSniff.php b/dev/tests/static/framework/Magento/Sniffs/Translation/ConstantUsageSniff.php index 260f731aecf1ce30d60cbd5dee1c2fb0f20074d2..4f9082aa4eb2124072b3c9fe39ddd50a901b7bd1 100644 --- a/dev/tests/static/framework/Magento/Sniffs/Translation/ConstantUsageSniff.php +++ b/dev/tests/static/framework/Magento/Sniffs/Translation/ConstantUsageSniff.php @@ -5,12 +5,10 @@ */ namespace Magento\Sniffs\Translation; -use PHP_CodeSniffer_File; - /** * Make sure that constants are not used as the first argument of translation function. */ -class ConstantUsageSniff extends \Generic_Sniffs_Files_LineLengthSniff +class ConstantUsageSniff implements \PHP_CodeSniffer_Sniff { /** * Having previous line content allows to process multi-line declaration. @@ -20,24 +18,73 @@ class ConstantUsageSniff extends \Generic_Sniffs_Files_LineLengthSniff protected $previousLineContent = ''; /** - * {@inheritdoc} + * {@inheritDoc} + */ + public function register() + { + return [T_OPEN_TAG]; + + } + + /** + * Copied from \Generic_Sniffs_Files_LineLengthSniff, minor changes made + * + * {@inheritDoc} */ - protected function checkLineLength(\PHP_CodeSniffer_File $phpcsFile, $stackPtr, $lineContent) + public function process(\PHP_CodeSniffer_File $phpcsFile, $stackPtr) { - $previousLineRegexp = '~__\($|Phrase\($~'; - $currentLineRegexp = '~__\(.+\)|Phrase\(.+\)~'; + $tokens = $phpcsFile->getTokens(); + + // Make sure this is the first open tag + $previousOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); + if ($previousOpenTag !== false) { + return; + } + + $tokenCount = 0; + $currentLineContent = ''; + $currentLine = 1; + + for (; $tokenCount < $phpcsFile->numTokens; $tokenCount++) { + if ($tokens[$tokenCount]['line'] === $currentLine) { + $currentLineContent .= $tokens[$tokenCount]['content']; + } else { + $this->checkIfFirstArgumentConstant($phpcsFile, ($tokenCount - 1), $currentLineContent); + $currentLineContent = $tokens[$tokenCount]['content']; + $currentLine++; + } + } + + $this->checkIfFirstArgumentConstant($phpcsFile, ($tokenCount - 1), $currentLineContent); + } + + /** + * Checks if first argument of \Magento\Framework\Phrase or translation function is a constant + * + * @param \PHP_CodeSniffer_File $phpcsFile + * @param int $stackPtr + * @param string $lineContent + * @return void + */ + private function checkIfFirstArgumentConstant( + \PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $lineContent + ) { + $previousLineRegexp = '/(__|Phrase)\($/im'; + $currentLineRegexp = '/(__|Phrase)\(.+\)/'; $currentLineMatch = preg_match($currentLineRegexp, $lineContent) !== 0; $previousLineMatch = preg_match($previousLineRegexp, $this->previousLineContent) !== 0; $this->previousLineContent = $lineContent; $error = 'Constants are not allowed as the first argument of translation function, use string literal instead'; - $constantRegexp = '[^\'"]+::[A-Z_0-9]+.*'; + $constantRegexp = '[^\$\'"]+::[A-Z_0-9]+.*'; if ($currentLineMatch) { - $variableRegexp = "~__\({$constantRegexp}\)|Phrase\({$constantRegexp}\)~"; + $variableRegexp = "/(__|Phrase)\({$constantRegexp}\)/"; if (preg_match($variableRegexp, $lineContent) !== 0) { $phpcsFile->addError($error, $stackPtr, 'VariableTranslation'); } } else if ($previousLineMatch) { - $variableRegexp = "~^\s+{$constantRegexp}~"; + $variableRegexp = "/^{$constantRegexp}/"; if (preg_match($variableRegexp, $lineContent) !== 0) { $phpcsFile->addError($error, $stackPtr, 'VariableTranslation'); } diff --git a/dev/tests/static/framework/Magento/TestFramework/Utility/ChangedFiles.php b/dev/tests/static/framework/Magento/TestFramework/Utility/ChangedFiles.php index d71c03eb0f85d01634f6f3a28c185c37e84bc1b2..571b663067151db4eb05d1484f38e1e10cd9527e 100644 --- a/dev/tests/static/framework/Magento/TestFramework/Utility/ChangedFiles.php +++ b/dev/tests/static/framework/Magento/TestFramework/Utility/ChangedFiles.php @@ -3,10 +3,10 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\TestFramework\Utility; use Magento\Framework\App\Utility\Files; +use Magento\TestFramework\Utility\File\RegexIteratorFactory; /** * A helper to gather various changed files @@ -23,7 +23,7 @@ class ChangedFiles */ public static function getPhpFiles($changedFilesList) { - $fileHelper = \Magento\Framework\App\Utility\Files::init(); + $fileUtilities = new File(Files::init(), new RegexIteratorFactory()); if (isset($_ENV['INCREMENTAL_BUILD'])) { $phpFiles = []; foreach (glob($changedFilesList) as $listFile) { @@ -36,27 +36,11 @@ class ChangedFiles } ); if (!empty($phpFiles)) { - $phpFiles = \Magento\Framework\App\Utility\Files::composeDataSets($phpFiles); - $phpFiles = array_intersect_key($phpFiles, $fileHelper->getPhpFiles( - Files::INCLUDE_APP_CODE - | Files::INCLUDE_PUB_CODE - | Files::INCLUDE_LIBS - | Files::INCLUDE_TEMPLATES - | Files::INCLUDE_TESTS - | Files::AS_DATA_SET - | Files::INCLUDE_NON_CLASSES - )); + $phpFiles = Files::composeDataSets($phpFiles); + $phpFiles = array_intersect_key($phpFiles, $fileUtilities->getPhpFiles()); } } else { - $phpFiles = $fileHelper->getPhpFiles( - Files::INCLUDE_APP_CODE - | Files::INCLUDE_PUB_CODE - | Files::INCLUDE_LIBS - | Files::INCLUDE_TEMPLATES - | Files::INCLUDE_TESTS - | Files::AS_DATA_SET - | Files::INCLUDE_NON_CLASSES - ); + $phpFiles = $fileUtilities->getPhpFiles(); } return $phpFiles; diff --git a/dev/tests/static/framework/Magento/TestFramework/Utility/File.php b/dev/tests/static/framework/Magento/TestFramework/Utility/File.php new file mode 100644 index 0000000000000000000000000000000000000000..7a8e02e5143a0808867a4b9c1d1d01b2da7b34f9 --- /dev/null +++ b/dev/tests/static/framework/Magento/TestFramework/Utility/File.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestFramework\Utility; + +use Magento\Framework\App\Utility\Files; +use Magento\TestFramework\Utility\File\RegexIteratorFactory; + +/** + * Get list of PHP files including files in setup application + */ +class File +{ + /** + * @var RegexIteratorFactory + */ + private $regexIteratorFactory; + + /** + * @var Files + */ + private $fileUtilities; + + /** + * Constructor + * + * @param Files $fileUtilities + * @param RegexIteratorFactory $regexIteratorFactory + */ + public function __construct( + Files $fileUtilities, + RegexIteratorFactory $regexIteratorFactory + ) { + $this->fileUtilities = $fileUtilities; + $this->regexIteratorFactory = $regexIteratorFactory; + } + + /** + * Get list of PHP files + * + * @return array + * @throws \Exception + */ + public function getPhpFiles() + { + $files = array_merge( + $this->fileUtilities->getPhpFiles( + Files::INCLUDE_APP_CODE + | Files::INCLUDE_PUB_CODE + | Files::INCLUDE_LIBS + | Files::INCLUDE_TEMPLATES + | Files::INCLUDE_TESTS + | Files::INCLUDE_NON_CLASSES + ), + $this->getSetupPhpFiles() + ); + return Files::composeDataSets($files); + } + + /** + * Get list of PHP files in setup application + * + * @param int $flags + * @return array + */ + private function getSetupPhpFiles() + { + $files = []; + $regexIterator = $this->regexIteratorFactory->create( + BP . '/setup', + '/.*php^/' + ); + foreach ($regexIterator as $file) { + $files = array_merge($files, [$file]); + } + return $files; + } +} diff --git a/dev/tests/static/framework/Magento/TestFramework/Utility/File/RegexIteratorFactory.php b/dev/tests/static/framework/Magento/TestFramework/Utility/File/RegexIteratorFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..d2e5768414f06f13138ba83ebcf34ce7535783e6 --- /dev/null +++ b/dev/tests/static/framework/Magento/TestFramework/Utility/File/RegexIteratorFactory.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestFramework\Utility\File; + +/** + * Factory for \RegexIterator + */ +class RegexIteratorFactory +{ + /** + * Create instance of \RegexIterator + * + * @param string $directoryPath + * @param string $regexp + * @return \RegexIterator + */ + public function create($directoryPath, $regexp) + { + $directory = new \RecursiveDirectoryIterator($directoryPath); + $recursiveIterator = new \RecursiveIteratorIterator($directory); + return new \RegexIterator($recursiveIterator, $regexp, \RegexIterator::GET_MATCH); + } +} diff --git a/dev/tests/static/framework/Magento/TestFramework/Utility/FunctionDetector.php b/dev/tests/static/framework/Magento/TestFramework/Utility/FunctionDetector.php new file mode 100644 index 0000000000000000000000000000000000000000..17310404e372097169f7cc36dcd8bb125349565d --- /dev/null +++ b/dev/tests/static/framework/Magento/TestFramework/Utility/FunctionDetector.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestFramework\Utility; + +/** + * Check if one or more functions are used in the file + */ +class FunctionDetector +{ + /** + * Detect functions in given file + * + * return result in this format: + * [ + * line_number => [ + * function_name_1, + * function_name_2, + * function_name_3, + * ], + * line_number => [ + * function_name_1, + * function_name_2, + * function_name_3, + * ], + * ] + * + * @param string $filePath + * @param string[] $functions + * @return array + */ + public function detect($filePath, $functions) + { + $result = []; + $regexp = $this->composeRegexp($functions); + if ($regexp) { + $file = file($filePath); + array_unshift($file, ''); + $lines = preg_grep( + $regexp, + $file + ); + foreach ($lines as $lineNumber => $line) { + if (preg_match_all($regexp, $line, $matches)) { + $result[$lineNumber] = $matches[1]; + } + } + } + return $result; + } + + /** + * Compose regular expression + * + * @param array $functions + * @return string + */ + private function composeRegexp(array $functions) + { + if (empty($functions)) { + return ''; + } + return '/(?<!function |->|::)\b(' . join('|', $functions) . ')\s*\(/i'; + } +} diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/ConstantUsageSniffTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/ConstantUsageSniffTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a64d47054ede9bc1f695514aa8f3ef95fc1e8eeb --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/ConstantUsageSniffTest.php @@ -0,0 +1,96 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Sniffs\Translation; + +class ConstantUsageSniffTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHP_CodeSniffer_File|\PHPUnit_Framework_MockObject_MockObject + */ + private $fileMock; + + /** + * @var ConstantUsageSniff + */ + private $constantUsageSniff; + + protected function setUp() + { + $this->fileMock = $this->getMock(\PHP_CodeSniffer_File::class, [], [], '', false); + $this->constantUsageSniff = new ConstantUsageSniff(); + } + + /** + * @param string $file + * @param int $numIncorrectUsages + * @dataProvider processDataProvider + */ + public function testProcessIncorrectArguments($file, $numIncorrectUsages) + { + $stackPtr = 10; + $fileContent = file_get_contents(__DIR__ . '/_files/' . $file); + $tokens = $this->tokenizeString($fileContent); + $this->fileMock->expects($this->once()) + ->method('findPrevious') + ->with( + T_OPEN_TAG, + $stackPtr - 1 + ) + ->willReturn(false); + $this->fileMock->expects($this->once()) + ->method('getTokens') + ->willReturn($tokens); + $this->fileMock->numTokens = count($tokens); + $this->fileMock->expects($this->exactly($numIncorrectUsages)) + ->method('addError') + ->with( + 'Constants are not allowed as the first argument of translation function, use string literal instead', + $this->anything(), + 'VariableTranslation' + ); + $this->constantUsageSniff->process($this->fileMock, $stackPtr); + } + + /** + * Get tokens for a string + * + * @param string $fileContent + * @return array + */ + private function tokenizeString($fileContent) + { + $lineNumber = 1; + $tokens = token_get_all($fileContent); + $snifferTokens = []; + for ($i = 0; $i < count($tokens); $i++) { + $content = is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i]; + $snifferTokens[$i]['line'] = $lineNumber; + $snifferTokens[$i]['content'] = $content; + $trimmedContent = trim($content, ' '); + if ($trimmedContent == PHP_EOL || $trimmedContent == PHP_EOL . PHP_EOL) { + $lineNumber++; + } + } + return $snifferTokens; + } + + /** + * @return array + */ + public function processDataProvider() + { + return [ + [ + 'incorrect_arguments.txt', + 9 + ], + [ + 'correct_arguments.txt', + 0 + ] + ]; + } +} diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/_files/correct_arguments.txt b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/_files/correct_arguments.txt new file mode 100644 index 0000000000000000000000000000000000000000..536029811fd87972da11ca531cd6787fa59921a4 --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/_files/correct_arguments.txt @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +__($variable) + +__($variable[Class::CONSTANT]) + +__($variable[\Namespace\Class::CONSTANT]) + +__($variable['value']) + +__( + $variable +) + +Phrase($variable) + +Phrase($variable[Class::CONSTANT]) + +Phrase($variable[\Namespace\Class::CONSTANT]) + +\Magento\Framework\Phrase($variable['value']) + +\Magento\Framework\Phrase( + $variable[Class::CONSTANT] +) diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/_files/incorrect_arguments.txt b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/_files/incorrect_arguments.txt new file mode 100644 index 0000000000000000000000000000000000000000..6112ce567ce14cc200e4bb648e828fc51d0dbc77 --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/_files/incorrect_arguments.txt @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +__(Class::CONSTANT) + +__(self::CONSTANT) + +__(\Namespace\Class::CONSTANT) + +__( + Class::CONSTANT +) + +Phrase(Class::CONSTANT) + +Phrase(self::CONSTANT) + +Phrase(\Namespace\Class::CONSTANT) + +\Magento\Framework\Phrase(Class::CONSTANT) + +\Magento\Framework\Phrase( + Class::CONSTANT +) diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/FileTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/FileTest.php new file mode 100644 index 0000000000000000000000000000000000000000..be8b246a9330495fd5b859a4feb2552772492e21 --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/FileTest.php @@ -0,0 +1,83 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestFramework\Utility; + +use Magento\Framework\App\Utility\Files; +use Magento\TestFramework\Utility\File\RegexIteratorFactory; +use Magento\TestFramework\Utility\File; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +class FileTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var Files|PHPUnit_Framework_MockObject_MockObject + */ + private $fileUtilitiesMock; + + /** + * @var RegexIteratorFactory|PHPUnit_Framework_MockObject_MockObject + */ + private $regexIteratorFactoryMock; + + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var File + */ + private $file; + + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->fileUtilitiesMock = $this->getMock(Files::class, [], [], '', false); + $this->regexIteratorFactoryMock = $this->getMock(RegexIteratorFactory::class, [], [], '', false); + $this->file = $this->objectManager->getObject( + File::class, + [ + 'fileUtilities' => $this->fileUtilitiesMock, + 'regexIteratorFactory' => $this->regexIteratorFactoryMock + ] + ); + } + + public function testGetPhpFiles() + { + $appFiles = [ + 'file1', + 'file2' + ]; + $setupFiles = [ + 'file3' + ]; + $expected = [ + 'file1' => ['file1'], + 'file2' => ['file2'], + 'file3' => ['file3'] + ]; + $iteratorMock = $this->getMock(\IteratorAggregate::class, [], [], '', false); + $iteratorMock->expects($this->any()) + ->method('getIterator') + ->willReturn(new \ArrayIterator($setupFiles)); + $this->regexIteratorFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($iteratorMock); + $this->fileUtilitiesMock->expects($this->once()) + ->method('getPhpFiles') + ->with( + Files::INCLUDE_APP_CODE + | Files::INCLUDE_PUB_CODE + | Files::INCLUDE_LIBS + | Files::INCLUDE_TEMPLATES + | Files::INCLUDE_TESTS + | Files::INCLUDE_NON_CLASSES + ) + ->willReturn($appFiles); + $this->assertEquals($expected, $this->file->getPhpFiles()); + } +} diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/FunctionDetectorTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/FunctionDetectorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a356aaa3cc83b48e4bf310b31d2556ec4c63bc12 --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/FunctionDetectorTest.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestFramework\Utility; + +class FunctionDetectorTest extends \PHPUnit_Framework_TestCase +{ + public function testDetectFunctions() + { + $fixturePath = __DIR__ . '/_files/test.txt'; + $expectedResults = [ + 1 => ['strtoupper', 'strtolower'], + 3 => ['foo'], + 4 => ['foo'], + ]; + $functionDetector = new FunctionDetector(); + $lines = $functionDetector->detect($fixturePath, ['foo', 'strtoupper', 'test', 'strtolower']); + $this->assertEquals($expectedResults, $lines); + } +} diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/test.txt b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/test.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2feb8284b2373bc94f9c16f7b5383fbc60f711a --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/test.txt @@ -0,0 +1,9 @@ +strtoupper(strtolower($foo . $bar)) +function foo($merchantMd5, $merchantApiLogin) +$this->generateHash(foo($bar), $foo) +foo( + 'bar' +) +Foo::bar($foo, $this->getData('bar')) +$this->foo('bar') +Foo::foo() diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ApiAnnotationTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ApiAnnotationTest.php deleted file mode 100644 index a1e7c25e3d6008cff744a090c0c01a810efad8a4..0000000000000000000000000000000000000000 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ApiAnnotationTest.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/** - * Scan source code for unmarked API interfaces - * - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Test\Integrity; - -use Magento\Framework\App\Utility\Files; -use Magento\Framework\Component\ComponentRegistrar; - -class ApiAnnotationTest extends \PHPUnit_Framework_TestCase -{ - /** - * API annotation pattern - */ - private $apiAnnotation = '~/\*{2}(.*@api.*)\*/\s+(?=interface)~s'; - - public function testApiAnnotations() - { - $modulePaths = array_map(function ($path) { - return $path . DIRECTORY_SEPARATOR . 'Api'; - }, (new ComponentRegistrar())->getPaths(ComponentRegistrar::MODULE)); - - foreach (Files::init()->getFiles($modulePaths, '*.php', true) as $file) { - $fileContent = file_get_contents($file); - if (!preg_match($this->apiAnnotation, $fileContent)) { - $result[] = $file; - } - } - if (!empty($result)) { - $this->fail(sprintf( - 'Found %s file(s) without @api annotations under Api namespace: %s', - count($result), - PHP_EOL . implode(PHP_EOL, $result) - )); - } - } -} diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/RestrictedCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/RestrictedCodeTest.php index 0c4c6eba49efa33c997b2dc62c70bd49434540e8..68c2d166448ab6fb4c39354b92ddb9f803d500f1 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/RestrictedCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/RestrictedCodeTest.php @@ -3,14 +3,13 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ - -/** - * Tests to find usage of restricted code - */ namespace Magento\Test\Legacy; use Magento\Framework\Component\ComponentRegistrar; +/** + * Tests to find usage of restricted code + */ class RestrictedCodeTest extends \PHPUnit_Framework_TestCase { /**@#+ @@ -18,17 +17,29 @@ class RestrictedCodeTest extends \PHPUnit_Framework_TestCase * * @var array */ - protected static $_classes = []; + private static $_classes = []; /**#@-*/ /** * List of fixtures that contain restricted classes and should not be tested + * * @var array */ - protected static $_fixtureFiles = []; + private static $_fixtureFiles = []; + + /** + * @var ComponentRegistrar + */ + private $componentRegistrar; + + protected function setUp() + { + $this->componentRegistrar = new ComponentRegistrar(); + } /** * Read fixtures into memory as arrays + * * @return void */ public static function setUpBeforeClass() @@ -69,6 +80,7 @@ class RestrictedCodeTest extends \PHPUnit_Framework_TestCase /** * Test that restricted entities are not used in PHP files + * * @return void */ public function testPhpFiles() @@ -97,15 +109,13 @@ class RestrictedCodeTest extends \PHPUnit_Framework_TestCase protected function _testRestrictedClasses($file) { $content = file_get_contents($file); - $componentRegistrar = new ComponentRegistrar(); foreach (self::$_classes as $restrictedClass => $classRules) { foreach ($classRules['exclude'] as $skippedPathInfo) { - $skippedPath = $componentRegistrar->getPath($skippedPathInfo['type'], $skippedPathInfo['name']) - . '/' . $skippedPathInfo['path']; - if (strpos($file, $skippedPath) === 0) { + if (strpos($file, $this->getExcludedFilePath($skippedPathInfo)) === 0) { continue 2; } } + $this->assertFalse( \Magento\TestFramework\Utility\CodeCheck::isClassUsed($restrictedClass, $content), sprintf( @@ -117,4 +127,18 @@ class RestrictedCodeTest extends \PHPUnit_Framework_TestCase ); } } + + /** + * Get full path for excluded file + * + * @param array $pathInfo + * @return string + */ + private function getExcludedFilePath($pathInfo) + { + if ($pathInfo['type'] != 'setup') { + return $this->componentRegistrar->getPath($pathInfo['type'], $pathInfo['name']) . '/' . $pathInfo['path']; + } + return BP . '/setup/' . $pathInfo['path']; + } } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/UnsecureFunctionsUsageTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/UnsecureFunctionsUsageTest.php index e5263713d71d7af374ea1f32c2d765d3639e56ce..44eb7fa78d8ac7099bfbfb6c14eae050c5e578e1 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/UnsecureFunctionsUsageTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/UnsecureFunctionsUsageTest.php @@ -6,12 +6,28 @@ namespace Magento\Test\Legacy; use Magento\Framework\App\Utility\Files; +use Magento\Framework\Component\ComponentRegistrar; +use Magento\TestFramework\Utility\FunctionDetector; /** * Tests to detect unsecure functions usage */ class UnsecureFunctionsUsageTest extends \PHPUnit_Framework_TestCase { + /** + * Php unsecure functions + * + * @var array + */ + private static $phpUnsecureFunctions = []; + + /** + * JS unsecure functions + * + * @var array + */ + private static $jsUnsecureFunctions = []; + /** * File extensions pattern to search for * @@ -20,25 +36,54 @@ class UnsecureFunctionsUsageTest extends \PHPUnit_Framework_TestCase private $fileExtensions = '/\.(php|phtml|js)$/'; /** - * Php unsecure functions to detect + * Read fixtures into memory as arrays * - * @var array + * @return void */ - private $phpUnsecureFunctions = [ - 'unserialize', - 'serialize', - 'eval', - 'md5', - 'srand', - 'mt_srand' - ]; + public static function setUpBeforeClass() + { + self::loadData(self::$phpUnsecureFunctions, 'unsecure_php_functions*.php'); + self::loadData(self::$jsUnsecureFunctions, 'unsecure_js_functions*.php'); + } /** - * JS unsecure functions to detect + * Loads and merges data from fixtures * - * @var array + * @param array $data + * @param string $filePattern + * @return void */ - private $jsUnsecureFunctions = []; + private static function loadData(array &$data, $filePattern) + { + foreach (glob(__DIR__ . '/_files/security/' . $filePattern) as $file) { + $data = array_merge_recursive($data, self::readList($file)); + } + $componentRegistrar = new ComponentRegistrar(); + foreach ($data as $key => $value) { + $excludes = $value['exclude']; + $excludePaths = []; + foreach ($excludes as $exclude) { + if ('setup' == $exclude['type']) { + $excludePaths[] = BP . '/setup/' . $exclude['path']; + } else { + $excludePaths[] = $componentRegistrar->getPath($exclude['type'], $exclude['name']) + . '/' . $exclude['path']; + } + } + $data[$key]['exclude'] = $excludePaths; + } + } + + /** + * Isolate including a file into a method to reduce scope + * + * @param string $file + * @return array + */ + private static function readList($file) + { + return include $file; + } /** * Detect unsecure functions usage for changed files in whitelist with the exception of blacklist @@ -48,46 +93,69 @@ class UnsecureFunctionsUsageTest extends \PHPUnit_Framework_TestCase public function testUnsecureFunctionsUsage() { $invoker = new \Magento\Framework\App\Utility\AggregateInvoker($this); + $functionDetector = new FunctionDetector(); $invoker( - function ($fileName) { - $result = ''; - $errorMessage = 'The following functions are non secure and should be avoided: ' - . implode(', ', $this->phpUnsecureFunctions) - . ' for PHP'; - if (!empty($this->jsUnsecureFunctions)) { - $errorMessage .= ', and ' - . implode(', ', $this->jsUnsecureFunctions) - . ' for JavaScript'; - } - $errorMessage .= ".\n"; - $regexp = $this->getRegexpByFileExtension(pathinfo($fileName, PATHINFO_EXTENSION)); - if ($regexp) { - $matches = preg_grep( - $regexp, - file($fileName) - ); - if (!empty($matches)) { - foreach (array_keys($matches) as $line) { - $result .= $fileName . ':' . ($line + 1) . "\n"; - } - } - $this->assertEmpty($result, $errorMessage . $result); + function ($fileFullPath) use ($functionDetector) { + $functions = $this->getFunctions($fileFullPath); + $lines = $functionDetector->detect($fileFullPath, array_keys($functions)); + + $message = ''; + if (!empty($lines)) { + $message = $this->composeMessage($fileFullPath, $lines, $functions); } + $this->assertEmpty( + $lines, + $message + ); }, - $this->unsecureFunctionsUsageDataProvider() + $this->getFilesToVerify() ); } /** - * Data provider for test + * Compose message + * + * @param string $fileFullPath + * @param array $lines + * @param array $functionRules + * @return string + */ + private function composeMessage($fileFullPath, $lines, $functionRules) + { + $result = ''; + foreach ($lines as $lineNumber => $detectedFunctions) { + $detectedFunctionRules = array_intersect_key($functionRules, array_flip($detectedFunctions)); + $replacementString = ''; + foreach ($detectedFunctionRules as $function => $functionRule) { + $replacement = $functionRule['replacement']; + if (is_array($replacement)) { + $replacement = array_unique($replacement); + $replacement = count($replacement) > 1 ? + "[\n\t\t\t" . implode("\n\t\t\t", $replacement) . "\n\t\t]" : + $replacement[0]; + } + $replacement = empty($replacement) ? 'No suggested replacement at this time' : $replacement; + $replacementString .= "\t\t'$function' => '$replacement'\n"; + } + $result .= sprintf( + "Functions '%s' are not secure in %s. \n\tSuggested replacement:\n%s", + implode(', ', $detectedFunctions), + $fileFullPath . ':' . $lineNumber, + $replacementString + ); + } + return $result; + } + + /** + * Get files to be verified * * @return array */ - public function unsecureFunctionsUsageDataProvider() + private function getFilesToVerify() { $fileExtensions = $this->fileExtensions; $directoriesToScan = Files::init()->readLists(__DIR__ . '/_files/security/whitelist.txt'); - $blackListFiles = include __DIR__ . '/_files/security/blacklist.php'; $filesToVerify = []; foreach (glob(__DIR__ . '/../_files/changed_files*') as $listFile) { @@ -104,7 +172,7 @@ class UnsecureFunctionsUsageTest extends \PHPUnit_Framework_TestCase ); $filesToVerify = array_filter( $filesToVerify, - function ($path) use ($directoriesToScan, $fileExtensions, $blackListFiles) { + function ($path) use ($directoriesToScan, $fileExtensions) { if (!file_exists($path[0])) { return false; } @@ -113,11 +181,9 @@ class UnsecureFunctionsUsageTest extends \PHPUnit_Framework_TestCase $directory = realpath($directory); if (strpos($path, $directory) === 0) { if (preg_match($fileExtensions, $path)) { - foreach ($blackListFiles as $blackListFile) { - $blackListFile = preg_quote($blackListFile, '#'); - if (preg_match('#' . $blackListFile . '#', $path)) { - return false; - } + // skip unit tests + if (preg_match('#' . preg_quote('Test/Unit', '#') . '#', $path)) { + return false; } return true; } @@ -130,35 +196,27 @@ class UnsecureFunctionsUsageTest extends \PHPUnit_Framework_TestCase } /** - * Get regular expression by file extension + * Get functions for the given file * - * @param string $fileExtension - * @return string|bool + * @param string $fileFullPath + * @return array */ - private function getRegexpByFileExtension($fileExtension) + private function getFunctions($fileFullPath) { - $regexp = false; + $fileExtension = pathinfo($fileFullPath, PATHINFO_EXTENSION); + $functions = []; if ($fileExtension == 'php') { - $regexp = $this->prepareRegexp($this->phpUnsecureFunctions); + $functions = self::$phpUnsecureFunctions; } elseif ($fileExtension == 'js') { - $regexp = $this->prepareRegexp($this->jsUnsecureFunctions); + $functions = self::$jsUnsecureFunctions; } elseif ($fileExtension == 'phtml') { - $regexp = $this->prepareRegexp($this->phpUnsecureFunctions + $this->jsUnsecureFunctions); + $functions = array_merge_recursive(self::$phpUnsecureFunctions, self::$jsUnsecureFunctions); } - return $regexp; - } - - /** - * Prepare regular expression for unsecure function names - * - * @param array $functions - * @return string - */ - private function prepareRegexp(array $functions) - { - if (empty($functions)) { - return ''; + foreach ($functions as $function => $functionRules) { + if (in_array($fileFullPath, $functionRules['exclude'])) { + unset($functions[$function]); + } } - return '/(?<!function |[^\s])\b(' . join('|', $functions) . ')\s*\(/i'; + return $functions; } } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/restricted_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/restricted_classes.php index a950b2d7e9ed243356da176f8eef1095ef4fb210..683449d4e5e34b919ef476d93c26fe01d122b0a8 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/restricted_classes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/restricted_classes.php @@ -1,27 +1,103 @@ <?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + /** * Classes that are restricted to use directly. * A <replacement> will be suggested to be used instead. * Use <whitelist> to specify files and directories that are allowed to use restricted classes. * * Format: array(<class_name>, <replacement>[, array(<whitelist>)]]) - * - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. */ return [ 'Zend_Db_Select' => [ 'replacement' => '\Magento\Framework\DB\Select', 'exclude' => [ - ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Select.php'], - ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Adapter/Pdo/Mysql.php'], - ['type' => 'library', 'name' => 'magento/framework', 'path' => 'Model/ResourceModel/Iterator.php'], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/Select.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/Adapter/Pdo/Mysql.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Model/ResourceModel/Iterator.php' + ], ] ], 'Zend_Db_Adapter_Pdo_Mysql' => [ 'replacement' => '\Magento\Framework\DB\Adapter\Pdo\Mysql', 'exclude' => [ - ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Adapter/Pdo/Mysql.php'], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/Adapter/Pdo/Mysql.php' + ], ] ], + 'Magento\Framework\Serialize\Serializer\Serialize' => [ + 'replacement' => 'Magento\Framework\Serialize\SerializerInterface', + 'exclude' => [ + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/Adapter/Pdo/Mysql.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/ObjectManager/ConfigLoader/Compiled.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/Config/ScopePool.php'], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/ObjectManager/ConfigCache.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/ObjectManager/ConfigLoader.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'ObjectManager/Config/Compiled.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Interception/Config/Config.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Interception/PluginList/PluginList.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/Router/ActionList.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Serialize/Test/Unit/Serializer/SerializeTest.php' + ], + [ + 'type' => 'setup', + 'path' => 'src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php' + ], + ] + ] ]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/blacklist.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/blacklist.php deleted file mode 100644 index 42b8e68e784111b96d43049ae27dc5ebc963ad40..0000000000000000000000000000000000000000 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/blacklist.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -return [ - 'Test/Unit', - 'lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php', - 'lib/internal/Magento/Framework/Serialize/Serializer/Serialize.php', -]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php new file mode 100644 index 0000000000000000000000000000000000000000..eb51d1bbba3bd98ec7ef2d5fd26754aea8fc221a --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * Functions that are not secure to use. + * A <replacement> will be suggested to be used instead. + * Use <exclude> to specify files and directories that are allowed to use function. + * + * Format: [ + * <class_name> => [ + * 'replacement' => <replacement>, + * 'exclude' => [ + * <exclude>, + * <exclude>, + * ] + * ] + */ +return [ + 'unserialize' => [ + 'replacement' => '\Magento\Framework\Serialize\SerializerInterface::unserialize', + 'exclude' => [ + ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Adapter/Pdo/Mysql.php'], + ['type' => 'library', 'name' => 'magento/framework', 'path' => 'Serialize/Serializer/Serialize.php'], + ] + ], + 'serialize' => [ + 'replacement' => '\Magento\Framework\Serialize\SerializerInterface::serialize', + 'exclude' => [ + ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Adapter/Pdo/Mysql.php'], + ['type' => 'library', 'name' => 'magento/framework', 'path' => 'Serialize/Serializer/Serialize.php'], + ] + ], + 'eval' => [ + 'replacement' => '', + 'exclude' => [] + ], + 'md5' => [ + 'replacement' => '', + 'exclude' => [] + ], + 'srand' => [ + 'replacement' => '', + 'exclude' => [] + ], + 'mt_srand' => [ + 'replacement' => '', + 'exclude' => [] + ], +]; diff --git a/lib/internal/Magento/Framework/Api/Search/SearchResult.php b/lib/internal/Magento/Framework/Api/Search/SearchResult.php index f637ef27d7b2cb4889e509aac154997ff1454aa9..f4ece5c84dde049468b76b357ecb09e2e86c2230 100644 --- a/lib/internal/Magento/Framework/Api/Search/SearchResult.php +++ b/lib/internal/Magento/Framework/Api/Search/SearchResult.php @@ -85,4 +85,18 @@ class SearchResult extends AbstractSimpleObject implements SearchResultInterface { return $this->setData(self::TOTAL_COUNT, $totalCount); } + + /** + * Retrieve ids of all items + * + * @return array + */ + public function getAllIds() + { + $ids = []; + foreach ($this->getItems() as $item) { + $ids[] = $item->getId(); + } + return $ids; + } } diff --git a/lib/internal/Magento/Framework/Api/Search/SearchResultInterface.php b/lib/internal/Magento/Framework/Api/Search/SearchResultInterface.php index ffa4c0fe43cf2422efbefc5a2c1605ec78281711..d44a8be3fb0ecff9a5031d07d66a50785c31c9d0 100644 --- a/lib/internal/Magento/Framework/Api/Search/SearchResultInterface.php +++ b/lib/internal/Magento/Framework/Api/Search/SearchResultInterface.php @@ -7,6 +7,11 @@ namespace Magento\Framework\Api\Search; use Magento\Framework\Api\SearchResultsInterface; +/** + * Interface SearchResultInterface + * + * @api + */ interface SearchResultInterface extends SearchResultsInterface { /**#@+ @@ -48,4 +53,11 @@ interface SearchResultInterface extends SearchResultsInterface * @return \Magento\Framework\Api\Search\SearchCriteriaInterface */ public function getSearchCriteria(); + + /** + * Retrieve all ids from list + * + * @return int[] + */ + public function getAllIds(); } diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Search/SearchResultTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Search/SearchResultTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5d289291996906e4b60b0940da8fafd893a720fc --- /dev/null +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Search/SearchResultTest.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Api\Test\Unit\Search; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Api\Search\SearchResult; +use Magento\Framework\Api\Search\DocumentInterface; + +class SearchResultTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var SearchResult + */ + private $search; + + /** + * @var DocumentInterface[] + */ + private $items; + + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * Set up + */ + protected function setUp() + { + $document1 = $this->getMock(DocumentInterface::class); + $document2 = $this->getMock(DocumentInterface::class); + + $this->items = [ $document1, $document2]; + $document1->expects($this->any()) + ->method('getId') + ->willReturn(1); + $document2->expects($this->any()) + ->method('getId') + ->willReturn(2); + + $data = [ + 'items' => $this->items + ]; + $this->objectManager = new ObjectManager($this); + $this->search = $this->objectManager->getObject( + SearchResult::class, + [ + 'data' => $data + ] + ); + } + + /** + * Test getAllIds + */ + public function testGetAllIds() + { + $this->assertEquals([1, 2], $this->search->getAllIds()); + } + + /** + * Test getItems + */ + public function testGetItems() + { + $this->assertEquals($this->items, $this->search->getItems()); + } +} diff --git a/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php b/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php index 181783c7b2115d8a216c681077e116e98344d15c..35d7b3ac5ee20ae669ccc66775498b3c0d9348b4 100644 --- a/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php +++ b/lib/internal/Magento/Framework/HTTP/Adapter/Curl.php @@ -28,6 +28,7 @@ class Curl implements \Zend_Http_Client_Adapter_Interface ), 'verifypeer' => true, 'verifyhost' => 2, + 'sslversion' => 6 ]; /** @@ -53,6 +54,7 @@ class Curl implements \Zend_Http_Client_Adapter_Interface 'protocols' => CURLOPT_PROTOCOLS, 'verifypeer' => CURLOPT_SSL_VERIFYPEER, 'verifyhost' => CURLOPT_SSL_VERIFYHOST, + 'sslversion' => CURLOPT_SSLVERSION, ]; /** diff --git a/lib/internal/Magento/Framework/HTTP/Client/Curl.php b/lib/internal/Magento/Framework/HTTP/Client/Curl.php index 67525f62f6336cf7de844e866a153be223dc0b5c..5ebc92abf70d9063af63683f5f530dd01470865a 100644 --- a/lib/internal/Magento/Framework/HTTP/Client/Curl.php +++ b/lib/internal/Magento/Framework/HTTP/Client/Curl.php @@ -9,14 +9,17 @@ namespace Magento\Framework\HTTP\Client; * Class to work with HTTP protocol using curl library * * @author Magento Core Team <core@magentocommerce.com> + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ class Curl implements \Magento\Framework\HTTP\ClientInterface { + const SSL_VERSION = 6; + /** * Max supported protocol by curl CURL_SSLVERSION_TLSv1_2 * @var int */ - private static $sslVersion = 6; + private $sslVersion; /** * Hostname @@ -86,7 +89,7 @@ class Curl implements \Magento\Framework\HTTP\ClientInterface /** * Curl - * @var object + * @var resource */ protected $_ch; @@ -117,10 +120,11 @@ class Curl implements \Magento\Framework\HTTP\ClientInterface } /** - * Constructor + * @param int|null $sslVersion */ - public function __construct() + public function __construct($sslVersion = self::SSL_VERSION) { + $this->sslVersion = $sslVersion; } /** @@ -377,10 +381,9 @@ class Curl implements \Magento\Framework\HTTP\ClientInterface $this->curlOption(CURLOPT_PORT, $this->_port); } - //$this->curlOption(CURLOPT_HEADER, 1); $this->curlOption(CURLOPT_RETURNTRANSFER, 1); $this->curlOption(CURLOPT_HEADERFUNCTION, [$this, 'parseHeaders']); - $this->curlOption(CURLOPT_SSLVERSION, self::$sslVersion); + $this->curlOption(CURLOPT_SSLVERSION, $this->sslVersion); if (count($this->_curlUserOptions)) { foreach ($this->_curlUserOptions as $k => $v) { @@ -415,6 +418,7 @@ class Curl implements \Magento\Framework\HTTP\ClientInterface * @param resource $ch curl handle, not needed * @param string $data * @return int + * @throws \Exception * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ protected function parseHeaders($ch, $data) @@ -422,11 +426,10 @@ class Curl implements \Magento\Framework\HTTP\ClientInterface if ($this->_headerCount == 0) { $line = explode(" ", trim($data), 3); if (count($line) != 3) { - return $this->doError("Invalid response line returned from server: " . $data); + $this->doError("Invalid response line returned from server: " . $data); } $this->_responseStatus = intval($line[1]); } else { - //var_dump($data); $name = $value = ''; $out = explode(": ", trim($data), 2); if (count($out) == 2) { diff --git a/lib/internal/Magento/Framework/Indexer/Config/Converter.php b/lib/internal/Magento/Framework/Indexer/Config/Converter.php index b8b17b185a1f2630842d6fe6e01b6a9de2a52107..0112b4d9a4de301a312e3e66bd146d8f477cd349 100644 --- a/lib/internal/Magento/Framework/Indexer/Config/Converter.php +++ b/lib/internal/Magento/Framework/Indexer/Config/Converter.php @@ -72,10 +72,10 @@ class Converter implements ConverterInterface $data['fieldsets'] = isset($data['fieldsets']) ? $data['fieldsets'] : []; switch ($childNode->nodeName) { case 'title': - $data['title'] = $this->getTranslatedNodeValue($childNode); + $data['title'] = $childNode->nodeValue; break; case 'description': - $data['description'] = $this->getTranslatedNodeValue($childNode); + $data['description'] = $childNode->nodeValue; break; case 'saveHandler': $data['saveHandler'] = $this->getAttributeValue($childNode, 'class'); @@ -207,6 +207,7 @@ class Converter implements ConverterInterface * * @param \DOMNode $node * @return string + * @deprecated */ protected function getTranslatedNodeValue(\DOMNode $node) {