diff --git a/app/code/Magento/Authorizenet/composer.json b/app/code/Magento/Authorizenet/composer.json index b93cb6688f56d..f4acc4504604d 100644 --- a/app/code/Magento/Authorizenet/composer.json +++ b/app/code/Magento/Authorizenet/composer.json @@ -12,6 +12,9 @@ "magento/module-catalog": "101.1.*", "magento/framework": "100.2.*" }, + "suggest": { + "magento/module-config": "100.2.*" + }, "type": "magento2-module", "version": "100.2.0-dev", "license": [ diff --git a/app/code/Magento/Authorizenet/etc/di.xml b/app/code/Magento/Authorizenet/etc/di.xml index f5e595fb450e8..287cdec6fa0f7 100644 --- a/app/code/Magento/Authorizenet/etc/di.xml +++ b/app/code/Magento/Authorizenet/etc/di.xml @@ -16,4 +16,14 @@ Magento\Authorizenet\Model\Directpost\Session\Storage + + + + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Backend/Block/Cache/Grid/Massaction/ProductionModeVisibilityChecker.php b/app/code/Magento/Backend/Block/Cache/Grid/Massaction/ProductionModeVisibilityChecker.php new file mode 100644 index 0000000000000..70a125e399ab3 --- /dev/null +++ b/app/code/Magento/Backend/Block/Cache/Grid/Massaction/ProductionModeVisibilityChecker.php @@ -0,0 +1,36 @@ +state = $state; + } + + /** + * {@inheritdoc} + */ + public function isVisible() + { + return $this->state->getMode() !== State::MODE_PRODUCTION; + } +} diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction.php index ffe12c6cff46e..c86907cc98042 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Massaction.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction.php @@ -3,14 +3,11 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ +namespace Magento\Backend\Block\Widget\Grid; /** * Grid widget massaction default block - * - * @author Magento Core Team */ -namespace Magento\Backend\Block\Widget\Grid; - class Massaction extends \Magento\Backend\Block\Widget\Grid\Massaction\AbstractMassaction { } diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php index 2f3df1377b395..7f697599c7003 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php @@ -5,14 +5,14 @@ */ namespace Magento\Backend\Block\Widget\Grid\Massaction; -use Magento\Framework\View\Element\Template; +use Magento\Backend\Block\Widget\Grid\Massaction\VisibilityCheckerInterface as VisibilityChecker; +use Magento\Framework\DataObject; /** * Grid widget massaction block * * @method \Magento\Quote\Model\Quote setHideFormElement(boolean $value) Hide Form element to prevent IE errors * @method boolean getHideFormElement() - * @author Magento Core Team */ abstract class AbstractMassaction extends \Magento\Backend\Block\Widget { @@ -73,20 +73,21 @@ protected function _construct() * 'complete' => string, // Only for ajax enabled grid (optional) * 'url' => string, * 'confirm' => string, // text of confirmation of this action (optional) - * 'additional' => string // (optional) + * 'additional' => string, // (optional) + * 'visible' => object // instance of VisibilityCheckerInterface (optional) * ); * * @param string $itemId - * @param array|\Magento\Framework\DataObject $item + * @param array|DataObject $item * @return $this */ public function addItem($itemId, $item) { if (is_array($item)) { - $item = new \Magento\Framework\DataObject($item); + $item = new DataObject($item); } - if ($item instanceof \Magento\Framework\DataObject) { + if ($item instanceof DataObject && $this->isVisible($item)) { $item->setId($itemId); $item->setUrl($this->getUrl($item->getUrl())); $this->_items[$itemId] = $item; @@ -95,6 +96,19 @@ public function addItem($itemId, $item) return $this; } + /** + * Check that item can be added to list + * + * @param DataObject $item + * @return bool + */ + private function isVisible(DataObject $item) + { + /** @var VisibilityChecker $checker */ + $checker = $item->getData('visible'); + return (!$checker instanceof VisibilityChecker) || $checker->isVisible(); + } + /** * Retrieve massaction item with id $itemId * diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/VisibilityCheckerInterface.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/VisibilityCheckerInterface.php new file mode 100644 index 0000000000000..934c4a84d145f --- /dev/null +++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/VisibilityCheckerInterface.php @@ -0,0 +1,18 @@ +getState()->getMode() === State::MODE_PRODUCTION) { + $this->messageManager->addErrorMessage(__('You can\'t change status of cache type(s) in production mode')); + } else { + $this->disableCache(); + } + + return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('adminhtml/*'); + } + + /** + * Disable cache + * + * @return void + */ + private function disableCache() { try { $types = $this->getRequest()->getParam('types'); @@ -41,9 +67,20 @@ public function execute() } catch (\Exception $e) { $this->messageManager->addException($e, __('An error occurred while disabling cache.')); } + } + + /** + * Get State Instance + * + * @return State + * @deprecated + */ + private function getState() + { + if ($this->state === null) { + $this->state = ObjectManager::getInstance()->get(State::class); + } - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); - return $resultRedirect->setPath('adminhtml/*'); + return $this->state; } } diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php index 6c8bccfee166a..8c4117831e8c8 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php @@ -8,15 +8,41 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\App\State; +use Magento\Framework\App\ObjectManager; +/** + * Controller enables some types of cache + */ class MassEnable extends \Magento\Backend\Controller\Adminhtml\Cache { + /** + * @var State + */ + private $state; + /** * Mass action for cache enabling * * @return \Magento\Backend\Model\View\Result\Redirect */ public function execute() + { + if ($this->getState()->getMode() === State::MODE_PRODUCTION) { + $this->messageManager->addErrorMessage(__('You can\'t change status of cache type(s) in production mode')); + } else { + $this->enableCache(); + } + + return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('adminhtml/*'); + } + + /** + * Enable cache + * + * @return void + */ + private function enableCache() { try { $types = $this->getRequest()->getParam('types'); @@ -40,9 +66,20 @@ public function execute() } catch (\Exception $e) { $this->messageManager->addException($e, __('An error occurred while enabling cache.')); } + } + + /** + * Get State Instance + * + * @return State + * @deprecated + */ + private function getState() + { + if ($this->state === null) { + $this->state = ObjectManager::getInstance()->get(State::class); + } - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); - return $resultRedirect->setPath('adminhtml/*'); + return $this->state; } } diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/MassactionTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/MassactionTest.php index 234e9d857549e..79ecb388873eb 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/MassactionTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/MassactionTest.php @@ -9,6 +9,8 @@ */ namespace Magento\Backend\Test\Unit\Block\Widget\Grid; +use Magento\Backend\Block\Widget\Grid\Massaction\VisibilityCheckerInterface as VisibilityChecker; + class MassactionTest extends \PHPUnit_Framework_TestCase { /** @@ -17,12 +19,12 @@ class MassactionTest extends \PHPUnit_Framework_TestCase protected $_block; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\View\Layout|\PHPUnit_Framework_MockObject_MockObject */ protected $_layoutMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Backend\Block\Widget\Grid|\PHPUnit_Framework_MockObject_MockObject */ protected $_gridMock; @@ -32,63 +34,63 @@ class MassactionTest extends \PHPUnit_Framework_TestCase protected $_eventManagerMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Backend\Model\Url|\PHPUnit_Framework_MockObject_MockObject */ protected $_urlModelMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject */ protected $_requestMock; + /** + * @var VisibilityChecker|\PHPUnit_Framework_MockObject_MockObject + */ + private $visibilityCheckerMock; + protected function setUp() { - $this->_gridMock = $this->getMock( - \Magento\Backend\Block\Widget\Grid::class, - ['getId', 'getCollection'], - [], - '', - false - ); - $this->_gridMock->expects($this->any())->method('getId')->will($this->returnValue('test_grid')); - - $this->_layoutMock = $this->getMock( - \Magento\Framework\View\Layout::class, - ['getParentName', 'getBlock', 'helper'], - [], - '', - false, - false - ); + $this->_gridMock = $this->getMockBuilder(\Magento\Backend\Block\Widget\Grid::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->setMethods(['getId', 'getCollection']) + ->getMock(); + $this->_gridMock->expects($this->any()) + ->method('getId') + ->willReturn('test_grid'); - $this->_layoutMock->expects( - $this->any() - )->method( - 'getParentName' - )->with( - 'test_grid_massaction' - )->will( - $this->returnValue('test_grid') - ); - $this->_layoutMock->expects( - $this->any() - )->method( - 'getBlock' - )->with( - 'test_grid' - )->will( - $this->returnValue($this->_gridMock) - ); + $this->_layoutMock = $this->getMockBuilder(\Magento\Framework\View\Layout::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->setMethods(['getParentName', 'getBlock', 'helper']) + ->getMock(); + $this->_layoutMock->expects($this->any()) + ->method('getParentName') + ->with('test_grid_massaction') + ->willReturn('test_grid'); + $this->_layoutMock->expects($this->any()) + ->method('getBlock') + ->with('test_grid') + ->willReturn($this->_gridMock); + + $this->_requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); - $this->_requestMock = $this->getMock(\Magento\Framework\App\Request\Http::class, [], [], '', false); + $this->_urlModelMock = $this->getMockBuilder(\Magento\Backend\Model\Url::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); - $this->_urlModelMock = $this->getMock(\Magento\Backend\Model\Url::class, [], [], '', false); + $this->visibilityCheckerMock = $this->getMockBuilder(VisibilityChecker::class) + ->getMockForAbstractClass(); $arguments = [ 'layout' => $this->_layoutMock, 'request' => $this->_requestMock, 'urlBuilder' => $this->_urlModelMock, - 'data' => ['massaction_id_field' => 'test_id', 'massaction_id_filter' => 'test_id'], + 'data' => ['massaction_id_field' => 'test_id', 'massaction_id_filter' => 'test_id'] ]; $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -124,26 +126,24 @@ public function testMassactionDefaultValues() } /** - * @param $itemId - * @param $item + * @param string $itemId + * @param \Magento\Framework\DataObject $item * @param $expectedItem \Magento\Framework\DataObject - * @dataProvider itemsDataProvider + * @dataProvider itemsProcessingDataProvider */ public function testItemsProcessing($itemId, $item, $expectedItem) { - $this->_urlModelMock->expects( - $this->any() - )->method( - 'getBaseUrl' - )->will( - $this->returnValue('http://localhost/index.php') - ); + $this->_urlModelMock->expects($this->any()) + ->method('getBaseUrl') + ->willReturn('http://localhost/index.php'); $urlReturnValueMap = [ ['*/*/test1', [], 'http://localhost/index.php/backend/admin/test/test1'], ['*/*/test2', [], 'http://localhost/index.php/backend/admin/test/test2'], ]; - $this->_urlModelMock->expects($this->any())->method('getUrl')->will($this->returnValueMap($urlReturnValueMap)); + $this->_urlModelMock->expects($this->any()) + ->method('getUrl') + ->willReturnMap($urlReturnValueMap); $this->_block->addItem($itemId, $item); $this->assertEquals(1, $this->_block->getCount()); @@ -157,7 +157,10 @@ public function testItemsProcessing($itemId, $item, $expectedItem) $this->assertNull($this->_block->getItem($itemId)); } - public function itemsDataProvider() + /** + * @return array + */ + public function itemsProcessingDataProvider() { return [ [ @@ -186,22 +189,17 @@ public function itemsDataProvider() } /** - * @param $param - * @param $expectedJson - * @param $expected + * @param string $param + * @param string $expectedJson + * @param array $expected * @dataProvider selectedDataProvider */ public function testSelected($param, $expectedJson, $expected) { - $this->_requestMock->expects( - $this->any() - )->method( - 'getParam' - )->with( - $this->_block->getFormFieldNameInternal() - )->will( - $this->returnValue($param) - ); + $this->_requestMock->expects($this->any()) + ->method('getParam') + ->with($this->_block->getFormFieldNameInternal()) + ->willReturn($param); $this->assertEquals($expectedJson, $this->_block->getSelectedJson()); $this->assertEquals($expected, $this->_block->getSelected()); @@ -262,6 +260,9 @@ public function testGetGridIdsJsonWithUseSelectAll(array $items, $result) $this->assertEquals($result, $this->_block->getGridIdsJson()); } + /** + * @return array + */ public function dataProviderGetGridIdsJsonWithUseSelectAll() { return [ @@ -279,4 +280,71 @@ public function dataProviderGetGridIdsJsonWithUseSelectAll() ], ]; } + + /** + * @param string $itemId + * @param array|\Magento\Framework\DataObject $item + * @param int $count + * @param bool $withVisibilityChecker + * @param bool $isVisible + * @dataProvider addItemDataProvider + */ + public function testAddItem($itemId, $item, $count, $withVisibilityChecker, $isVisible) + { + $this->visibilityCheckerMock->expects($this->any()) + ->method('isVisible') + ->willReturn($isVisible); + + if ($withVisibilityChecker) { + $item['visible'] = $this->visibilityCheckerMock; + } + + $urlReturnValueMap = [ + ['*/*/test1', [], 'http://localhost/index.php/backend/admin/test/test1'], + ['*/*/test2', [], 'http://localhost/index.php/backend/admin/test/test2'], + ]; + $this->_urlModelMock->expects($this->any()) + ->method('getUrl') + ->willReturnMap($urlReturnValueMap); + + $this->_block->addItem($itemId, $item); + $this->assertEquals($count, $this->_block->getCount()); + } + + /** + * @return array + */ + public function addItemDataProvider() + { + return [ + [ + 'itemId' => 'test1', + 'item' => ['label' => 'Test 1', 'url' => '*/*/test1'], + 'count' => 1, + 'withVisibilityChecker' => false, + '$isVisible' => false, + ], + [ + 'itemId' => 'test2', + 'item' => ['label' => 'Test 2', 'url' => '*/*/test2'], + 'count' => 1, + 'withVisibilityChecker' => false, + 'isVisible' => true, + ], + [ + 'itemId' => 'test1', + 'item' => ['label' => 'Test 1. Hide', 'url' => '*/*/test1'], + 'count' => 0, + 'withVisibilityChecker' => true, + 'isVisible' => false, + ], + [ + 'itemId' => 'test2', + 'item' => ['label' => 'Test 2. Does not hide', 'url' => '*/*/test2'], + 'count' => 1, + 'withVisibilityChecker' => true, + 'isVisible' => true, + ] + ]; + } } diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php new file mode 100644 index 0000000000000..b2fc808b0e237 --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php @@ -0,0 +1,224 @@ +stateMock = $this->getMockBuilder(State::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + + $this->messageManagerMock = $this->getMockBuilder(MessageManager::class) + ->getMockForAbstractClass(); + + $this->requestMock = $this->getMockBuilder(Request::class) + ->getMockForAbstractClass(); + + $this->cacheTypeListMock = $this->getMockBuilder(CacheTypeList::class) + ->getMockForAbstractClass(); + + $this->cacheStateMock = $this->getMockBuilder(CacheState::class) + ->getMockForAbstractClass(); + + $this->redirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $this->redirectMock->expects($this->once()) + ->method('setPath') + ->with('adminhtml/*') + ->willReturnSelf(); + $resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->redirectMock); + + $contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $contextMock->expects($this->once()) + ->method('getMessageManager') + ->willReturn($this->messageManagerMock); + $contextMock->expects($this->once()) + ->method('getResultFactory') + ->willReturn($resultFactoryMock); + $contextMock->expects($this->once()) + ->method('getRequest') + ->willReturn($this->requestMock); + + $this->controller = $objectManagerHelper->getObject( + MassDisable::class, + [ + 'context' => $contextMock, + 'cacheTypeList' => $this->cacheTypeListMock, + 'cacheState' => $this->cacheStateMock + ] + ); + $objectManagerHelper->setBackwardCompatibleProperty($this->controller, 'state', $this->stateMock); + } + + public function testExecuteInProductionMode() + { + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_PRODUCTION); + + $this->messageManagerMock->expects($this->once()) + ->method('addErrorMessage') + ->with('You can\'t change status of cache type(s) in production mode', null) + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteInvalidTypeCache() + { + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->cacheTypeListMock->expects($this->once()) + ->method('getTypes') + ->willReturn([ + 'pageCache' => [ + 'id' => 'pageCache', + 'label' => 'Cache of Page' + ] + ]); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('types') + ->willReturn(['someCache']); + + $this->messageManagerMock->expects($this->once()) + ->method('addError') + ->with('Specified cache type(s) don\'t exist: someCache') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteWithException() + { + $exception = new \Exception(); + + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->willThrowException($exception); + + $this->messageManagerMock->expects($this->once()) + ->method('addException') + ->with($exception, 'An error occurred while disabling cache.') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteSuccess() + { + $cacheType = 'pageCache'; + + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->cacheTypeListMock->expects($this->once()) + ->method('getTypes') + ->willReturn([ + 'pageCache' => [ + 'id' => 'pageCache', + 'label' => 'Cache of Page' + ] + ]); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('types') + ->willReturn([$cacheType]); + + $this->cacheStateMock->expects($this->once()) + ->method('isEnabled') + ->with($cacheType) + ->willReturn(true); + $this->cacheStateMock->expects($this->once()) + ->method('setEnabled') + ->with($cacheType, false); + $this->cacheStateMock->expects($this->once()) + ->method('persist'); + + $this->messageManagerMock->expects($this->once()) + ->method('addSuccess') + ->with('1 cache type(s) disabled.') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php new file mode 100644 index 0000000000000..8c1b9f1718ab9 --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php @@ -0,0 +1,224 @@ +stateMock = $this->getMockBuilder(State::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + + $this->messageManagerMock = $this->getMockBuilder(MessageManager::class) + ->getMockForAbstractClass(); + + $this->requestMock = $this->getMockBuilder(Request::class) + ->getMockForAbstractClass(); + + $this->cacheTypeListMock = $this->getMockBuilder(CacheTypeList::class) + ->getMockForAbstractClass(); + + $this->cacheStateMock = $this->getMockBuilder(CacheState::class) + ->getMockForAbstractClass(); + + $this->redirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $this->redirectMock->expects($this->once()) + ->method('setPath') + ->with('adminhtml/*') + ->willReturnSelf(); + $resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->redirectMock); + + $contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $contextMock->expects($this->once()) + ->method('getMessageManager') + ->willReturn($this->messageManagerMock); + $contextMock->expects($this->once()) + ->method('getResultFactory') + ->willReturn($resultFactoryMock); + $contextMock->expects($this->once()) + ->method('getRequest') + ->willReturn($this->requestMock); + + $this->controller = $objectManagerHelper->getObject( + MassEnable::class, + [ + 'context' => $contextMock, + 'cacheTypeList' => $this->cacheTypeListMock, + 'cacheState' => $this->cacheStateMock + ] + ); + $objectManagerHelper->setBackwardCompatibleProperty($this->controller, 'state', $this->stateMock); + } + + public function testExecuteInProductionMode() + { + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_PRODUCTION); + + $this->messageManagerMock->expects($this->once()) + ->method('addErrorMessage') + ->with('You can\'t change status of cache type(s) in production mode', null) + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteInvalidTypeCache() + { + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->cacheTypeListMock->expects($this->once()) + ->method('getTypes') + ->willReturn([ + 'pageCache' => [ + 'id' => 'pageCache', + 'label' => 'Cache of Page' + ] + ]); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('types') + ->willReturn(['someCache']); + + $this->messageManagerMock->expects($this->once()) + ->method('addError') + ->with('Specified cache type(s) don\'t exist: someCache') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteWithException() + { + $exception = new \Exception(); + + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->willThrowException($exception); + + $this->messageManagerMock->expects($this->once()) + ->method('addException') + ->with($exception, 'An error occurred while enabling cache.') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteSuccess() + { + $cacheType = 'pageCache'; + + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->cacheTypeListMock->expects($this->once()) + ->method('getTypes') + ->willReturn([ + 'pageCache' => [ + 'id' => 'pageCache', + 'label' => 'Cache of Page' + ] + ]); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('types') + ->willReturn([$cacheType]); + + $this->cacheStateMock->expects($this->once()) + ->method('isEnabled') + ->with($cacheType) + ->willReturn(false); + $this->cacheStateMock->expects($this->once()) + ->method('setEnabled') + ->with($cacheType, true); + $this->cacheStateMock->expects($this->once()) + ->method('persist'); + + $this->messageManagerMock->expects($this->once()) + ->method('addSuccess') + ->with('1 cache type(s) enabled.') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } +} diff --git a/app/code/Magento/Backend/etc/di.xml b/app/code/Magento/Backend/etc/di.xml index 8b52d08da48fb..c0c5a0ec5b8a7 100644 --- a/app/code/Magento/Backend/etc/di.xml +++ b/app/code/Magento/Backend/etc/di.xml @@ -213,4 +213,22 @@ + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 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 decc26f331c82..98f9ca89ba18a 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 @@ -23,10 +23,12 @@ Enable adminhtml/*/massEnable + Magento\Backend\Block\Cache\Grid\Massaction\ProductionModeVisibilityChecker Disable adminhtml/*/massDisable + Magento\Backend\Block\Cache\Grid\Massaction\ProductionModeVisibilityChecker Refresh diff --git a/app/code/Magento/Braintree/etc/di.xml b/app/code/Magento/Braintree/etc/di.xml index d051ef78cfcd2..5417c96ba6772 100644 --- a/app/code/Magento/Braintree/etc/di.xml +++ b/app/code/Magento/Braintree/etc/di.xml @@ -365,7 +365,7 @@ - + @@ -452,7 +452,7 @@ - + @@ -544,4 +544,16 @@ + + + + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Checkout/etc/di.xml b/app/code/Magento/Checkout/etc/di.xml index a2243b33a04ed..81a430d52c499 100644 --- a/app/code/Magento/Checkout/etc/di.xml +++ b/app/code/Magento/Checkout/etc/di.xml @@ -42,4 +42,11 @@ + + + + 1 + + + diff --git a/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php new file mode 100644 index 0000000000000..80567d0504ee9 --- /dev/null +++ b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php @@ -0,0 +1,152 @@ +excludeList = $excludeList; + $this->sources = $sources; + } + + /** + * Retrieve aggregated configuration from all available sources. + * + * @param string $path + * @return array + */ + public function get($path = '') + { + $path = (string)$path; + $data = []; + + if (isset($this->data[$path])) { + return $this->data[$path]; + } + + $this->sortSources(); + + foreach ($this->sources as $sourceConfig) { + /** @var ConfigSourceInterface $source */ + $source = $sourceConfig['source']; + $data = array_replace_recursive($data, $source->get($path)); + } + + $this->excludedFields = []; + $this->filterChain($path, $data); + + return $this->data[$path] = $data; + } + + /** + * Recursive filtering of sensitive data + * + * @param string $path + * @param array $data + * @return void + */ + private function filterChain($path, &$data) + { + foreach ($data as $subKey => &$subData) { + $newPath = $path ? $path . '/' . $subKey : $subKey; + $filteredPath = $this->filterPath($newPath); + + if ( + $filteredPath + && !is_array($data[$subKey]) + && $this->excludeList->isPresent($filteredPath) + ) { + $this->excludedFields[$newPath] = $filteredPath; + + unset($data[$subKey]); + } elseif (is_array($subData)) { + $this->filterChain($newPath, $subData); + } + } + } + + /** + * Eliminating scope info from path + * + * @param string $path + * @return null|string + */ + private function filterPath($path) + { + $parts = explode('/', $path); + + // Check if there are enough parts to recognize scope + if (count($parts) < 3) { + return null; + } + + if ($parts[0] === ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { + unset($parts[0]); + } else { + unset($parts[0], $parts[1]); + } + + return implode('/', $parts); + } + + /** + * Sort sources ASC from higher priority to lower + * + * @return void + */ + private function sortSources() + { + uasort($this->sources, function ($firstItem, $secondItem) { + return $firstItem['sortOrder'] > $secondItem['sortOrder']; + }); + } + + /** + * Retrieves list of field paths were excluded from config dump + * @return array + */ + public function getExcludedFields() + { + $this->get(); + + $fields = array_values($this->excludedFields); + $fields = array_unique($fields); + + return $fields; + } +} diff --git a/app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php new file mode 100644 index 0000000000000..cf0ce492b7d52 --- /dev/null +++ b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php @@ -0,0 +1,21 @@ +source = $source; $this->postProcessor = $postProcessor; + $this->preProcessor = $preProcessor; $this->cache = $cache; $this->cachingNestedLevel = $cachingNestedLevel; $this->fallback = $fallback; @@ -96,7 +95,9 @@ public function get($path = '') if (!$this->data) { $data = $this->cache->load(self::CONFIG_TYPE); if (!$data) { - $data = $this->fallback->process($this->source->get()); + $data = $this->preProcessor->process($this->source->get()); + $this->data = new DataObject($data); + $data = $this->fallback->process($data); $this->data = new DataObject($data); //Placeholder processing need system config - so we need to save intermediate result $data = $this->postProcessor->process($data); diff --git a/app/code/Magento/Config/Block/System/Config/Form.php b/app/code/Magento/Config/Block/System/Config/Form.php index d1a0da2a700a3..f0ad7e4a28b1a 100644 --- a/app/code/Magento/Config/Block/System/Config/Form.php +++ b/app/code/Magento/Config/Block/System/Config/Form.php @@ -7,8 +7,10 @@ use Magento\Config\App\Config\Type\System; use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\ObjectManager; +use Magento\Framework\DataObject; /** * System config form block @@ -331,29 +333,9 @@ protected function _initElement( $fieldPrefix = '', $labelPrefix = '' ) { - $inherit = true; - $data = $this->getAppConfigDataValue($path); - if ($data === null) { - if (array_key_exists($path, $this->_configData)) { - $data = $this->_configData[$path]; - $inherit = false; + $inherit = !array_key_exists($path, $this->_configData); + $data = $this->getFieldData($field, $path); - if ($field->hasBackendModel()) { - $backendModel = $field->getBackendModel(); - $backendModel->setPath($path) - ->setValue($data) - ->setWebsite($this->getWebsiteCode()) - ->setStore($this->getStoreCode()) - ->afterLoad(); - $data = $backendModel->getValue(); - } - - } elseif ($field->getConfigPath() !== null) { - $data = $this->getConfigValue($field->getConfigPath()); - } else { - $data = $this->getConfigValue($path); - } - } $fieldRendererClass = $field->getFrontendModel(); if ($fieldRendererClass) { $fieldRenderer = $this->_layout->getBlockSingleton($fieldRendererClass); @@ -373,9 +355,7 @@ protected function _initElement( $sharedClass = $this->_getSharedCssClass($field); $requiresClass = $this->_getRequiresCssClass($field, $fieldPrefix); - $isReadOnly = $this->getSettingChecker()->isReadOnly($path, $this->getScope(), $this->getScopeCode()); - $canUseDefault = $this->canUseDefaultValue($field->showInDefault()); - $canUseWebsite = $this->canUseWebsiteValue($field->showInWebsite()); + $isReadOnly = $this->getSettingChecker()->isReadOnly($path, $this->getScope(), $this->getStringScopeCode()); $formField = $fieldset->addField( $elementId, $field->getType(), @@ -392,8 +372,8 @@ protected function _initElement( 'scope' => $this->getScope(), 'scope_id' => $this->getScopeId(), 'scope_label' => $this->getScopeLabel($field), - 'can_use_default_value' => $canUseDefault, - 'can_use_website_value' => $canUseWebsite, + 'can_use_default_value' => $this->canUseDefaultValue($field->showInDefault()), + 'can_use_website_value' => $this->canUseWebsiteValue($field->showInWebsite()), 'can_restore_to_default' => $this->isCanRestoreToDefault($field->canRestore()), 'disabled' => $isReadOnly, 'is_disable_inheritance' => $isReadOnly @@ -413,6 +393,74 @@ protected function _initElement( $formField->setRenderer($fieldRenderer); } + /** + * Get data of field by path + * + * @param \Magento\Config\Model\Config\Structure\Element\Field $field + * @param string $path + * @return mixed|null|string + */ + private function getFieldData(\Magento\Config\Model\Config\Structure\Element\Field $field, $path) + { + $data = $this->getAppConfigDataValue($path); + + $placeholderValue = $this->getSettingChecker()->getPlaceholderValue( + $path, + $this->getScope(), + $this->getStringScopeCode() + ); + + if ($placeholderValue) { + $data = $placeholderValue; + } + if ($data === null) { + if (array_key_exists($path, $this->_configData)) { + $data = $this->_configData[$path]; + + if ($field->hasBackendModel()) { + $backendModel = $field->getBackendModel(); + $backendModel->setPath($path) + ->setValue($data) + ->setWebsite($this->getWebsiteCode()) + ->setStore($this->getStoreCode()) + ->afterLoad(); + $data = $backendModel->getValue(); + } + + } elseif ($field->getConfigPath() !== null) { + $data = $this->getConfigValue($field->getConfigPath()); + } else { + $data = $this->getConfigValue($path); + } + } + + return $data; + } + + /** + * Retrieve Scope string code + * + * @return string + */ + private function getStringScopeCode() + { + $scopeCode = $this->getData('scope_string_code'); + + if (null === $scopeCode) { + if ($this->getStoreCode()) { + $scopeCode = $this->_storeManager->getStore($this->getStoreCode())->getCode(); + } elseif ($this->getWebsiteCode()) { + $scopeCode = $this->_storeManager->getWebsite($this->getWebsiteCode())->getCode(); + } else { + $scopeCode = ''; + } + + $this->setData('scope_string_code', $scopeCode); + } + + return $scopeCode; + } + /** * Populate dependencies block * @@ -748,14 +796,13 @@ private function getAppConfigDataValue($path) { $appConfig = $this->getAppConfig()->get(System::CONFIG_TYPE); $scope = $this->getScope(); - $scopeId = $this->getScopeId(); - if ($scope === 'default') { - $data = isset($appConfig[$scope][$path]) ? $appConfig[$scope][$path] : null; + $scopeCode = $this->getStringScopeCode(); + + if ($scope === ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { + $data = new DataObject(isset($appConfig[$scope]) ? $appConfig[$scope] : []); } else { - $data = isset($appConfig[$scope][$scopeId][$path]) - ? $appConfig[$scope][$scopeId][$path] - : null; + $data = new DataObject(isset($appConfig[$scope][$scopeCode]) ? $appConfig[$scope][$scopeCode] : []); } - return $data; + return $data->getData($path); } } diff --git a/app/code/Magento/Config/Model/Config/Export/Comment.php b/app/code/Magento/Config/Model/Config/Export/Comment.php new file mode 100644 index 0000000000000..ae0431c82daa0 --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Export/Comment.php @@ -0,0 +1,59 @@ +placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT); + $this->source = $source; + } + + /** + * Retrieves comments for config export file. + * + * @return string + */ + public function get() + { + $comment = ''; + $fields = $this->source->getExcludedFields(); + foreach ($fields as $path) { + $comment .= "\n" . $this->placeholder->generate($path) . ' for ' . $path ; + } + if ($comment) { + $comment = 'The configuration file doesn\'t contain sensitive data for security reasons. ' + . 'Sensitive data can be stored in the following environment variables:' + . $comment; + } + return $comment; + } +} diff --git a/app/code/Magento/Config/Model/Config/Export/ExcludeList.php b/app/code/Magento/Config/Model/Config/Export/ExcludeList.php new file mode 100644 index 0000000000000..f3c10b4100ed3 --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Export/ExcludeList.php @@ -0,0 +1,55 @@ +configs = $configs; + } + + /** + * Check whether config item is excluded from export + * + * @param string $path + * @return bool + */ + public function isPresent($path) + { + return !empty($this->configs[$path]) ; + } + + /** + * Retrieves all excluded field paths for export + * + * @return array + */ + public function get() + { + return array_keys( + array_filter( + $this->configs, + function ($value) { + return filter_var($value, FILTER_VALIDATE_BOOLEAN); + } + ) + ); + } +} diff --git a/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php new file mode 100644 index 0000000000000..efbe888f2ebd6 --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php @@ -0,0 +1,70 @@ +placeholderFactory = $placeholderFactory; + $this->arrayManager = $arrayManager; + $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT); + } + + /** + * Method extracts environment variables. + * If environment variable is matching the desired rule - it's being used as value. + * + * {@inheritdoc} + */ + public function process(array $config) + { + $environmentVariables = $_ENV; + + foreach ($environmentVariables as $template => $value) { + if (!$this->placeholder->isApplicable($template)) { + continue; + } + + $config = $this->arrayManager->set( + $this->placeholder->restore($template), + $config, + $value + ); + } + + return $config; + } +} diff --git a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php index 48b82086ad8b1..7e673401c7348 100644 --- a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php +++ b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php @@ -6,10 +6,11 @@ namespace Magento\Config\Model\Config\Reader\Source\Deployed; use Magento\Config\Model\Config\Reader; -use Magento\Framework\App\Config\ScopeCodeResolver; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\DeploymentConfig; -use Magento\Framework\App\ObjectManager; +use Magento\Config\Model\Placeholder\PlaceholderInterface; +use Magento\Config\Model\Placeholder\PlaceholderFactory; +use Magento\Framework\App\Config\ScopeCodeResolver; /** * Class for checking settings that defined in config file @@ -21,6 +22,11 @@ class SettingChecker */ private $config; + /** + * @var PlaceholderInterface + */ + private $placeholder; + /** * @var ScopeCodeResolver */ @@ -28,45 +34,86 @@ class SettingChecker /** * @param DeploymentConfig $config + * @param PlaceholderFactory $placeholderFactory * @param ScopeCodeResolver $scopeCodeResolver */ public function __construct( DeploymentConfig $config, + PlaceholderFactory $placeholderFactory, ScopeCodeResolver $scopeCodeResolver ) { $this->config = $config; $this->scopeCodeResolver = $scopeCodeResolver; + $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT); } /** - * Resolve path by scope and scope code + * Check that setting defined in deployed configuration * + * @param string $path * @param string $scope - * @param string $scopeCode - * @return string + * @param string|null $scopeCode + * @return boolean */ - private function resolvePath($scope, $scopeCode) + public function isReadOnly($path, $scope, $scopeCode = null) { - $scopePath = 'system/' . $scope; + $config = $this->getEnvValue( + $this->placeholder->generate($path, $scope, $scopeCode) + ); - if ($scope != ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { - $scopePath .= '/' . $this->scopeCodeResolver->resolve($scope, $scopeCode); + if (null === $config) { + $config = $this->config->get($this->resolvePath($scope, $scopeCode) . "/" . $path); } - return $scopePath; + return $config !== null; } /** - * Check that setting defined in deployed configuration + * Check that there is value for generated placeholder + * + * Placeholder is generated from values of $path, $scope and $scopeCode * * @param string $path * @param string $scope * @param string $scopeCode - * @return boolean + * @param string|null $scopeCode + * @return string|null */ - public function isReadOnly($path, $scope, $scopeCode) + public function getPlaceholderValue($path, $scope, $scopeCode = null) { - $config = $this->config->get($this->resolvePath($scope, $scopeCode) . "/" . $path); - return $config !== null; + return $this->getEnvValue($this->placeholder->generate($path, $scope, $scopeCode)); + } + + /** + * Retrieve value of environment variable by placeholder + * + * @param string $placeholder + * @return string|null + */ + public function getEnvValue($placeholder) + { + if ($this->placeholder->isApplicable($placeholder) && isset($_ENV[$placeholder])) { + return $_ENV[$placeholder]; + } + + return null; + } + + /** + * Resolve path by scope and scope code + * + * @param string $scope + * @param string $scopeCode + * @return string + */ + private function resolvePath($scope, $scopeCode) + { + $scopePath = 'system/' . $scope; + + if ($scope != ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { + $scopePath .= '/' . $this->scopeCodeResolver->resolve($scope, $scopeCode); + } + + return $scopePath; } } diff --git a/app/code/Magento/Config/Model/Placeholder/Environment.php b/app/code/Magento/Config/Model/Placeholder/Environment.php new file mode 100644 index 0000000000000..96ffadc96c6f9 --- /dev/null +++ b/app/code/Magento/Config/Model/Placeholder/Environment.php @@ -0,0 +1,76 @@ +deploymentConfig = $deploymentConfig; + } + + /** + * Generates placeholder like CONFIG__DEFAULT__TEST__TEST_VALUE + * + * @inheritdoc + */ + public function generate($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) + { + $parts = $scopeType ? [$scopeType] : []; + + if ($scopeType !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT && $scopeCode) { + $parts[] = $scopeCode; + } + + $parts[] = $path; + + $template = implode('__', $parts); + $template = str_replace('/', '__', $template); + $template = static::PREFIX . $template; + $template = strtoupper($template); + + return $template; + } + + /** + * @inheritdoc + */ + public function restore($template) + { + $template = preg_replace('/^' . static::PREFIX . '/', '', $template); + $template = str_replace('__', '/', $template); + $template = strtolower($template); + + return $template; + } + + /** + * @inheritdoc + */ + public function isApplicable($placeholder) + { + return 1 === preg_match('/^' . static::PREFIX . '([a-zA-Z]+)([a-zA-Z0-9_])*$/', $placeholder); + } +} diff --git a/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php new file mode 100644 index 0000000000000..3f88bc2a289c4 --- /dev/null +++ b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php @@ -0,0 +1,59 @@ +objectManager = $objectManager; + $this->types = $types; + } + + /** + * Create placeholder + * + * @param string $type + * @return PlaceholderInterface + * @throws LocalizedException + */ + public function create($type) + { + if (!isset($this->types[$type])) { + throw new LocalizedException(__('There is no defined type ' . $type)); + } + + $object = $this->objectManager->create($this->types[$type]); + + if (!$object instanceof PlaceholderInterface) { + throw new LocalizedException(__('Object is not instance of ' . PlaceholderInterface::class)); + } + + return $object; + } +} diff --git a/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php b/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php new file mode 100644 index 0000000000000..286eb0034a550 --- /dev/null +++ b/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php @@ -0,0 +1,40 @@ +sourceMock = $this->getMockBuilder(ConfigSourceInterface::class) + ->getMockForAbstractClass(); + $this->sourceMockTwo = $this->getMockBuilder(ConfigSourceInterface::class) + ->getMockForAbstractClass(); + $this->excludeListMock = $this->getMockBuilder(ExcludeList::class) + ->disableOriginalConstructor() + ->getMock(); + + $sources = [ + [ + 'source' => $this->sourceMockTwo, + 'sortOrder' => 100 + ], + [ + 'source' => $this->sourceMock, + 'sortOrder' => 10 + ], + + ]; + + $this->model = new DumpConfigSourceAggregated($this->excludeListMock, $sources); + } + + public function testGet() + { + $path = ''; + $data = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://test.local', + ], + 'secure' => [ + 'base_url' => 'https://test.local', + ] + ] + ], + 'test' => [ + 'test' => [ + 'test1' => [ + 'test2' => [ + 'test3' => 5, + ] + ] + ] + ] + ]; + + $this->sourceMock->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn($data); + $this->sourceMockTwo->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn(['key' => 'value2']); + $this->excludeListMock->expects($this->any()) + ->method('isPresent') + ->willReturnMap([ + ['web/unsecure/base_url', false], + ['web/secure/base_url', true], + ['test1/test2/test/3', false] + ]); + + $this->assertEquals( + [ + 'test' => [ + 'test' => [ + 'test1' => [ + 'test2' => [ + 'test3' => 5, + ] + ] + ], + ], + 'key' => 'value2', + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://test.local', + ], + 'secure' => [] + ] + ], + ], + $this->model->get($path) + ); + } + + public function testGetExcludedFields() + { + $path = ''; + $data = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://test.local', + ], + 'secure' => [ + 'base_url' => 'https://test.local', + ] + ] + ], + 'test' => [ + 'test' => [ + 'test1' => [ + 'test2' => [ + 'test3' => 5, + ] + ] + ] + ] + ]; + + $this->sourceMock->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn($data); + $this->sourceMockTwo->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn(['key' => 'value2']); + $this->excludeListMock->expects($this->any()) + ->method('isPresent') + ->willReturnMap([ + ['web/unsecure/base_url', false], + ['web/secure/base_url', true], + ['test1/test2/test/3', false] + ]); + + $this->assertEquals( + ['web/secure/base_url'], + $this->model->getExcludedFields() + ); + } +} diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php index be541228bf6d8..8409e96db552e 100644 --- a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php +++ b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php @@ -8,9 +8,9 @@ use Magento\Config\App\Config\Type\System; use Magento\Framework\App\Config\ConfigSourceInterface; use Magento\Framework\App\Config\Spi\PostProcessorInterface; -use Magento\Framework\App\ObjectManager; +use Magento\Framework\App\Config\Spi\PreProcessorInterface; use Magento\Framework\Cache\FrontendInterface; -use Magento\Framework\Serialize\Serializer\Serialize; +use Magento\Framework\Serialize\SerializerInterface; use Magento\Store\Model\Config\Processor\Fallback; /** @@ -29,6 +29,11 @@ class SystemTest extends \PHPUnit_Framework_TestCase */ private $postProcessor; + /** + * @var PreProcessorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $preProcessor; + /** * @var Fallback|\PHPUnit_Framework_MockObject_MockObject */ @@ -45,7 +50,7 @@ class SystemTest extends \PHPUnit_Framework_TestCase private $configType; /** - * @var Serialize|\PHPUnit_Framework_MockObject_MockObject + * @var SerializerInterface|\PHPUnit_Framework_MockObject_MockObject */ private $serializer; @@ -60,7 +65,9 @@ public function setUp() ->getMock(); $this->cache = $this->getMockBuilder(FrontendInterface::class) ->getMockForAbstractClass(); - $this->serializer = $this->getMockBuilder(Serialize::class) + $this->preProcessor = $this->getMockBuilder(PreProcessorInterface::class) + ->getMockForAbstractClass(); + $this->serializer = $this->getMockBuilder(SerializerInterface::class) ->disableOriginalConstructor() ->getMock(); $this->configType = new System( @@ -68,7 +75,8 @@ public function setUp() $this->postProcessor, $this->fallback, $this->cache, - $this->serializer + $this->serializer, + $this->preProcessor ); } @@ -112,6 +120,10 @@ public function testGet($isCached) ->method('process') ->with($data) ->willReturnArgument(0); + $this->preProcessor->expects($this->once()) + ->method('process') + ->with($data) + ->willReturnArgument(0); $this->postProcessor->expects($this->once()) ->method('process') ->with($data) diff --git a/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php b/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php index 2c671914f264b..5c7bf92f95428 100644 --- a/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php +++ b/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php @@ -10,6 +10,7 @@ use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; use Magento\Framework\App\DeploymentConfig; +use Magento\Store\Model\StoreManagerInterface; /** * Test System config form block @@ -72,6 +73,11 @@ class FormTest extends \PHPUnit_Framework_TestCase */ protected $_fieldsetFactoryMock; + /** + * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $storeManagerMock; + /** * @return void * @SuppressWarnings(PHPMD.ExcessiveMethodLength) @@ -161,6 +167,9 @@ protected function setUp() false ); + $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) + ->getMockForAbstractClass(); + $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $context = $helper->getObject( @@ -168,7 +177,8 @@ protected function setUp() [ 'scopeConfig' => $this->_coreConfigMock, 'request' => $requestMock, - 'urlBuilder' => $this->_urlModelMock + 'urlBuilder' => $this->_urlModelMock, + 'storeManager' => $this->storeManagerMock ] ); @@ -423,6 +433,7 @@ public function initGroupDataProvider() * @param string|null $configPath * @param bool $inherit * @param string $expectedValue + * @param string|null $placeholderValue * @param int $hasBackendModel * * @dataProvider initFieldsDataProvider @@ -434,6 +445,7 @@ public function testInitFields( $configPath, $inherit, $expectedValue, + $placeholderValue, $hasBackendModel ) { // Parameters initialization @@ -503,6 +515,18 @@ public function testInitFields( $this->returnValue($configValue) ); + /** @var \Magento\Store\Api\Data\StoreInterface|\PHPUnit_Framework_MockObject_MockObject $storeMock */ + $storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) + ->getMockForAbstractClass(); + $storeMock->expects($this->once()) + ->method('getCode') + ->willReturn('store_code'); + + $this->storeManagerMock->expects($this->atLeastOnce()) + ->method('getStore') + ->with('store_code') + ->willReturn($storeMock); + // Field mock configuration $fieldMock = $this->getMock( \Magento\Config\Model\Config\Structure\Element\Field::class, @@ -596,17 +620,20 @@ public function testInitFields( $fieldMock->expects($this->once())->method('populateInput'); - - $settingChecker = $this->getMockBuilder(SettingChecker::class) + $settingCheckerMock = $this->getMockBuilder(SettingChecker::class) ->disableOriginalConstructor() ->getMock(); - $settingChecker->expects($this->once()) + $settingCheckerMock->expects($this->once()) ->method('isReadOnly') ->willReturn(false); - $reflection = new \ReflectionClass(get_class($this->object)); - $reflectionProperty = $reflection->getProperty('settingChecker'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->object, $settingChecker); + + $settingCheckerMock->expects($this->once()) + ->method('getPlaceholderValue') + ->willReturn($placeholderValue); + + $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $helper->setBackwardCompatibleProperty($this->object, 'settingChecker', $settingCheckerMock); $this->object->initFields($fieldsetMock, $groupMock, $sectionMock, $fieldPrefix, $labelPrefix); } @@ -617,8 +644,9 @@ public function testInitFields( public function initFieldsDataProvider() { return [ - [['section1/group1/field1' => 'some_value'], false, null, false, 'some_value', 1], - [[], 'Config Value', 'some/config/path', true, 'Config Value', 0] + [['section1/group1/field1' => 'some_value'], false, null, false, 'some_value', null, 1], + [[], 'Config Value', 'some/config/path', true, 'Config Value', null, 0], + [[], 'Config Value', 'some/config/path', true, 'Placeholder Value', 'Placeholder Value', 0] ]; } } diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php new file mode 100644 index 0000000000000..c8b10bcf4ddcd --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php @@ -0,0 +1,88 @@ +placeholderMock = $this->getMockBuilder(PlaceholderInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $placeholderFactoryMock->expects($this->once()) + ->method('create') + ->with(PlaceholderFactory::TYPE_ENVIRONMENT) + ->willReturn($this->placeholderMock); + + $this->configSourceMock = $this->getMockBuilder(DumpConfigSourceInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->model = $objectManager->getObject( + Comment::class, + [ + 'placeholderFactory' => $placeholderFactoryMock, + 'source' => $this->configSourceMock + ] + ); + } + + public function testGetEmpty() + { + $this->configSourceMock->expects($this->once()) + ->method('getExcludedFields') + ->willReturn([]); + $this->assertEmpty($this->model->get()); + } + + public function testGet() + { + $path = 'one/two'; + $placeholder = 'one__two'; + $expectedResult = 'The configuration file doesn\'t contain sensitive data for security reasons. ' + . 'Sensitive data can be stored in the following environment variables:' + . "\n$placeholder for $path"; + + $this->configSourceMock->expects($this->once()) + ->method('getExcludedFields') + ->willReturn([$path]); + + $this->placeholderMock->expects($this->once()) + ->method('generate') + ->with($path) + ->willReturn($placeholder); + + $this->assertEquals($expectedResult, $this->model->get()); + } +} diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php new file mode 100644 index 0000000000000..3156ad1ec5493 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php @@ -0,0 +1,40 @@ +model = new ExcludeList( + [ + 'web/unsecure/base_url' => '', + 'web/test/test_value' => '0', + 'web/test/test_sensitive' => '1', + ] + ); + } + + public function testGet() + { + $this->assertEquals(['web/test/test_sensitive'], $this->model->get()); + } + + public function testIsPresent() + { + $this->assertFalse($this->model->isPresent('some/new/path')); + $this->assertFalse($this->model->isPresent('web/unsecure/base_url')); + $this->assertFalse($this->model->isPresent('web/test/test_value')); + $this->assertTrue($this->model->isPresent('web/test/test_sensitive')); + } +} diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php new file mode 100644 index 0000000000000..25f9f6b3cb832 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php @@ -0,0 +1,131 @@ +placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->placeholderMock = $this->getMockBuilder(PlaceholderInterface::class) + ->getMockForAbstractClass(); + $this->env = $_ENV; + + $this->placeholderFactoryMock->expects($this->any()) + ->method('create') + ->with(PlaceholderFactory::TYPE_ENVIRONMENT) + ->willReturn($this->placeholderMock); + + $this->model = new EnvironmentPlaceholder( + $this->placeholderFactoryMock, + $this->arrayManagerMock + ); + } + + public function testProcess() + { + $_ENV = array_merge( + $this->env, + [ + 'CONFIG_DEFAULT_TEST' => 1, + 'CONFIG_DEFAULT_TEST2' => 2, + 'BAD_CONFIG' => 3, + ] + ); + + $this->placeholderMock->expects($this->any()) + ->method('isApplicable') + ->willReturnMap( + [ + ['CONFIG_DEFAULT_TEST', true], + ['CONFIG_DEFAULT_TEST2', true], + ['BAD_CONFIG', false], + ] + ); + $this->placeholderMock->expects($this->any()) + ->method('restore') + ->willReturnMap( + [ + ['CONFIG_DEFAULT_TEST', 'default/test'], + ['CONFIG_DEFAULT_TEST2', 'default/test2'], + ] + ); + $this->arrayManagerMock->expects($this->any()) + ->method('set') + ->willReturnMap( + [ + ['default/test', [], 1, '/', ['default' => ['test' => 1]]], + [ + 'default/test2', + [ + 'default' => [ + 'test' => 1 + ] + ], + 2, + '/', + [ + 'default' => [ + 'test' => 1, + 'test2' => 2 + ] + ], + ] + ] + ); + + $this->assertSame( + [ + 'default' => [ + 'test' => 1, + 'test2' => 2 + ] + ], + $this->model->process([]) + ); + } + + protected function tearDown() + { + $_ENV = $this->env; + } +} diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php index 2e746eae410f4..75bfab85616b5 100644 --- a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php @@ -7,21 +7,30 @@ use Magento\Config\Model\Config\Reader; use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; -use Magento\Framework\App\Config\ScopeCodeResolver; use Magento\Framework\App\Config; use Magento\Framework\App\DeploymentConfig; +use Magento\Config\Model\Placeholder\PlaceholderInterface; +use Magento\Config\Model\Placeholder\PlaceholderFactory; /** * Test class for checking settings that defined in config file - * - * @package Magento\Config\Test\Unit\Model\Config\Reader\Source\Deployed */ class SettingCheckerTest extends \PHPUnit_Framework_TestCase { /** * @var Config|\PHPUnit_Framework_MockObject_MockObject */ - private $config; + private $configMock; + + /** + * @var PlaceholderInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $placeholderMock; + + /** + * @var Config\ScopeCodeResolver|\PHPUnit_Framework_MockObject_MockObject + */ + private $scopeCodeResolverMock; /** * @var SettingChecker @@ -29,43 +38,109 @@ class SettingCheckerTest extends \PHPUnit_Framework_TestCase private $checker; /** - * @var ScopeCodeResolver | \PHPUnit_Framework_MockObject_MockObject + * @var array */ - private $scopeCodeResolver; + private $env; public function setUp() { - $this->config = $this->getMockBuilder(DeploymentConfig::class) + $this->configMock = $this->getMockBuilder(DeploymentConfig::class) ->disableOriginalConstructor() ->getMock(); - $this->scopeCodeResolver = $this->getMockBuilder(ScopeCodeResolver::class) + $this->placeholderMock = $this->getMockBuilder(PlaceholderInterface::class) + ->getMockForAbstractClass(); + $this->scopeCodeResolverMock = $this->getMockBuilder(Config\ScopeCodeResolver::class) ->disableOriginalConstructor() ->getMock(); - $this->checker = new SettingChecker($this->config, $this->scopeCodeResolver); + $placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->env = $_ENV; + + $placeholderFactoryMock->expects($this->once()) + ->method('create') + ->with(PlaceholderFactory::TYPE_ENVIRONMENT) + ->willReturn($this->placeholderMock); + + $this->checker = new SettingChecker($this->configMock, $placeholderFactoryMock, $this->scopeCodeResolverMock); } - public function testIsDefined() + /** + * @param string $path + * @param string $scope + * @param string $scopeCode + * @param string|null $confValue + * @param array $variables + * @param bool $expectedResult + * @dataProvider isReadonlyDataProvider + */ + public function testIsReadonly($path, $scope, $scopeCode, $confValue, array $variables, $expectedResult) { - $path = 'general/web/locale'; - $scope = 'website'; - $scopeCode = 'myWebsite'; - $scopeCodeId = '4'; + $this->placeholderMock->expects($this->once()) + ->method('isApplicable') + ->willReturn(true); + $this->placeholderMock->expects($this->once()) + ->method('generate') + ->with($path, $scope, $scopeCode) + ->willReturn('SOME_PLACEHOLDER'); + $this->scopeCodeResolverMock->expects($this->any()) + ->method('resolve') + ->willReturnMap( + [ + ['website', 'myWebsite', ($scopeCode ? $scopeCode : '')] + ] + ); + + $_ENV = array_merge($this->env, $variables); - $this->config->expects($this->once()) + $this->configMock->expects($this->any()) ->method('get') - ->willReturn([ - $scope => [ - $scopeCode => [ - $path => 'value' - ], + ->willReturnMap([ + [ + 'system/' . $scope . "/" . ($scopeCode ? $scopeCode . '/' : '') . $path, + null, + $confValue ], ]); - $this->scopeCodeResolver->expects($this->once()) - ->method('resolve') - ->with($scope, $scopeCodeId) - ->willReturn($scopeCode); + $this->assertSame($expectedResult, $this->checker->isReadOnly($path, $scope, $scopeCode)); + } - $this->assertTrue($this->checker->isReadOnly($path, $scope, $scopeCodeId)); + /** + * @return array + */ + public function isReadonlyDataProvider() + { + return [ + [ + 'path' => 'general/web/locale', + 'scope' => 'website', + 'scopeCode' => 'myWebsite', + 'confValue' => 'value', + 'variables' => [], + 'expectedResult' => true, + ], + [ + 'path' => 'general/web/locale', + 'scope' => 'website', + 'scopeCode' => 'myWebsite', + 'confValue' => null, + 'variables' => ['SOME_PLACEHOLDER' => 'value'], + 'expectedResult' => true, + ], + [ + 'path' => 'general/web/locale', + 'scope' => 'website', + 'scopeCode' => 'myWebsite', + 'confValue' => null, + 'variables' => [], + 'expectedResult' => false, + ] + ]; + } + + protected function tearDown() + { + $_ENV = $this->env; } } diff --git a/app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php b/app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php new file mode 100644 index 0000000000000..64b4e6e37fb94 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php @@ -0,0 +1,131 @@ +deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new Environment( + $this->deploymentConfigMock + ); + } + + /** + * @param string $path + * @param string $scope + * @param string $scopeId + * @param string $expected + * @dataProvider getGenerateDataProvider + */ + public function testGenerate($path, $scope, $scopeId, $expected) + { + $this->assertSame( + $expected, + $this->model->generate($path, $scope, $scopeId) + ); + } + + public function getGenerateDataProvider() + { + return [ + [ + 'web/unsecure/base_url', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + Environment::PREFIX . 'DEFAULT__WEB__UNSECURE__BASE_URL' + ], + [ + 'web/unsecure/base_url', + 'web', + 'test', + Environment::PREFIX . 'WEB__TEST__WEB__UNSECURE__BASE_URL' + ], + [ + 'web/unsecure/base_url', + 'web', + null, + Environment::PREFIX . 'WEB__WEB__UNSECURE__BASE_URL' + ], + ]; + } + + /** + * @param string $placeholder + * @param bool $expected + * @dataProvider getIsPlaceholderDataProvider + */ + public function testIsApplicable($placeholder, $expected) + { + $this->assertSame( + $expected, + $this->model->isApplicable($placeholder) + ); + } + + /** + * @return array + */ + public function getIsPlaceholderDataProvider() + { + return [ + [Environment::PREFIX . 'TEST', true], + ['TEST', false], + [Environment::PREFIX . 'TEST_test', true], + [Environment::PREFIX . '-:A', false], + [Environment::PREFIX . '_A', false], + [Environment::PREFIX . 'A@#$', false] + ]; + } + + /** + * @param string $template + * @param string $expected + * @dataProvider restoreDataProvider + */ + public function testRestore($template, $expected) + { + $this->assertSame( + $expected, + $this->model->restore($template) + ); + } + + /** + * @return array + */ + public function restoreDataProvider() + { + return [ + [Environment::PREFIX . 'TEST__CONFIG', 'test/config'], + [Environment::PREFIX . 'TEST__CONFIG__VALUE', 'test/config/value'], + [Environment::PREFIX . 'TEST__CONFIG_VALUE', 'test/config_value'], + ]; + } +} diff --git a/app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php b/app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php new file mode 100644 index 0000000000000..e8f646e984187 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php @@ -0,0 +1,76 @@ +objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->getMockForAbstractClass(); + $this->environmentMock = $this->getMockBuilder(Environment::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new PlaceholderFactory( + $this->objectManagerMock, + [ + PlaceholderFactory::TYPE_ENVIRONMENT => Environment::class, + 'wrongClass' => \stdClass::class, + ] + ); + } + + public function testCreate() + { + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with(Environment::class) + ->willReturn($this->environmentMock); + + $this->assertInstanceOf( + Environment::class, + $this->model->create(PlaceholderFactory::TYPE_ENVIRONMENT) + ); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage There is no defined type dummyClass + */ + public function testCreateNonExisted() + { + $this->model->create('dummyClass'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Object is not instance of Magento\Config\Model\Placeholder\PlaceholderInterface + */ + public function testCreateWrongImplementation() + { + $this->model->create('wrongClass'); + } +} diff --git a/app/code/Magento/Config/etc/di.xml b/app/code/Magento/Config/etc/di.xml index 4f9eae24b55f6..3e2fa4fbecf6d 100644 --- a/app/code/Magento/Config/etc/di.xml +++ b/app/code/Magento/Config/etc/di.xml @@ -81,6 +81,8 @@ systemConfigSourceAggregatedProxy systemConfigPostProcessorCompositeProxy Magento\Framework\App\Cache\Type\Config + systemConfigPreProcessorComposite + Magento\Framework\Serialize\Serializer\Serialize @@ -113,6 +115,13 @@ + + + + Magento\Config\Model\Config\Processor\EnvironmentPlaceholder + + + @@ -138,15 +147,15 @@ Magento\Framework\Config\File\ConfigFilePool::APP_CONFIG - + - - systemConfigInitialDataProvider - 10 - Magento\Config\App\Config\Source\RuntimeConfigSource + 100 + + + systemConfigInitialDataProvider 1000 @@ -158,8 +167,21 @@ appDumpSystemSource Magento\Config\App\Config\Type\System::CONFIG_TYPE + Magento\Config\Model\Config\Export\Comment + + + appDumpSystemSource + + + + + + Magento\Config\Model\Placeholder\Environment + + + diff --git a/app/code/Magento/Contact/etc/di.xml b/app/code/Magento/Contact/etc/di.xml new file mode 100644 index 0000000000000..95cd40cb55e31 --- /dev/null +++ b/app/code/Magento/Contact/etc/di.xml @@ -0,0 +1,16 @@ + + + + + + + 1 + + + + diff --git a/app/code/Magento/Cron/Console/Command/CronInstallCommand.php b/app/code/Magento/Cron/Console/Command/CronInstallCommand.php new file mode 100644 index 0000000000000..2835244599d38 --- /dev/null +++ b/app/code/Magento/Cron/Console/Command/CronInstallCommand.php @@ -0,0 +1,79 @@ +crontabManager = $crontabManager; + $this->tasksProvider = $tasksProvider; + + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName('cron:install') + ->setDescription('Generates and installs crontab for current user') + ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force install tasks'); + + parent::configure(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if ($this->crontabManager->getTasks() && !$input->getOption('force')) { + $output->writeln('Crontab has already been generated and saved'); + return Cli::RETURN_FAILURE; + } + + try { + $this->crontabManager->saveTasks($this->tasksProvider->getTasks()); + } catch (LocalizedException $e) { + $output->writeln('' . $e->getMessage() . ''); + return Cli::RETURN_FAILURE; + } + + $output->writeln('Crontab has been generated and saved'); + + return Cli::RETURN_SUCCESS; + } +} diff --git a/app/code/Magento/Cron/Console/Command/CronRemoveCommand.php b/app/code/Magento/Cron/Console/Command/CronRemoveCommand.php new file mode 100644 index 0000000000000..11c666a556f89 --- /dev/null +++ b/app/code/Magento/Cron/Console/Command/CronRemoveCommand.php @@ -0,0 +1,62 @@ +crontabManager = $crontabManager; + + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName('cron:remove') + ->setDescription('Removes tasks from crontab'); + + parent::configure(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + try { + $this->crontabManager->removeTasks(); + } catch (LocalizedException $e) { + $output->writeln('' . $e->getMessage() . ''); + return Cli::RETURN_FAILURE; + } + + $output->writeln('Magento cron tasks have been removed'); + + return Cli::RETURN_SUCCESS; + } +} diff --git a/app/code/Magento/Cron/Test/Unit/Console/Command/CronInstallCommandTest.php b/app/code/Magento/Cron/Test/Unit/Console/Command/CronInstallCommandTest.php new file mode 100644 index 0000000000000..09949cf78dc8f --- /dev/null +++ b/app/code/Magento/Cron/Test/Unit/Console/Command/CronInstallCommandTest.php @@ -0,0 +1,126 @@ +crontabManagerMock = $this->getMockBuilder(CrontabManagerInterface::class) + ->getMockForAbstractClass(); + $this->tasksProviderMock = $this->getMockBuilder(TasksProviderInterface::class) + ->getMockForAbstractClass(); + + $this->commandTester = new CommandTester( + new CronInstallCommand($this->crontabManagerMock, $this->tasksProviderMock) + ); + } + + /** + * @return void + */ + public function testExecuteAlreadyInstalled() + { + $this->crontabManagerMock->expects($this->once()) + ->method('getTasks') + ->willReturn([['* * * * * /bin/php /var/run.php']]); + $this->tasksProviderMock->expects($this->never()) + ->method('getTasks'); + + $this->commandTester->execute([]); + $this->assertEquals( + 'Crontab has already been generated and saved' . PHP_EOL, + $this->commandTester->getDisplay() + ); + $this->assertEquals(Cli::RETURN_FAILURE, $this->commandTester->getStatusCode()); + } + + /** + * @return void + */ + public function testExecuteWithException() + { + $this->crontabManagerMock->expects($this->once()) + ->method('getTasks') + ->willReturn([]); + $this->tasksProviderMock->expects($this->once()) + ->method('getTasks') + ->willReturn([]); + $this->crontabManagerMock->expects($this->once()) + ->method('saveTasks') + ->willThrowException(new LocalizedException(new Phrase('Some error'))); + + $this->commandTester->execute([]); + $this->assertEquals( + 'Some error' . PHP_EOL, + $this->commandTester->getDisplay() + ); + $this->assertEquals(Cli::RETURN_FAILURE, $this->commandTester->getStatusCode()); + } + + /** + * @param array $existingTasks + * @param array $options + * @return void + * @dataProvider executeDataProvider + */ + public function testExecute($existingTasks, $options) + { + $this->crontabManagerMock->expects($this->once()) + ->method('getTasks') + ->willReturn($existingTasks); + $this->tasksProviderMock->expects($this->once()) + ->method('getTasks') + ->willReturn([]); + $this->crontabManagerMock->expects($this->once()) + ->method('saveTasks') + ->with([]); + + $this->commandTester->execute($options); + $this->assertEquals( + 'Crontab has been generated and saved' . PHP_EOL, + $this->commandTester->getDisplay() + ); + $this->assertEquals(Cli::RETURN_SUCCESS, $this->commandTester->getStatusCode()); + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + ['existingTasks' => [], 'options' => []], + ['existingTasks' => ['* * * * * /bin/php /var/www/run.php'], 'options' => ['-f'=> true]] + ]; + } +} diff --git a/app/code/Magento/Cron/Test/Unit/Console/Command/CronRemoveCommandTest.php b/app/code/Magento/Cron/Test/Unit/Console/Command/CronRemoveCommandTest.php new file mode 100644 index 0000000000000..cd017b26d7585 --- /dev/null +++ b/app/code/Magento/Cron/Test/Unit/Console/Command/CronRemoveCommandTest.php @@ -0,0 +1,72 @@ +crontabManagerMock = $this->getMockBuilder(CrontabManagerInterface::class) + ->getMockForAbstractClass(); + + $this->commandTester = new CommandTester( + new CronRemoveCommand($this->crontabManagerMock) + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->crontabManagerMock->expects($this->once()) + ->method('RemoveTasks'); + + $this->commandTester->execute([]); + $this->assertEquals( + 'Magento cron tasks have been removed' . PHP_EOL, + $this->commandTester->getDisplay() + ); + $this->assertEquals(Cli::RETURN_SUCCESS, $this->commandTester->getStatusCode()); + } + + /** + * @return void + */ + public function testExecuteFailed() + { + $this->crontabManagerMock->expects($this->once()) + ->method('RemoveTasks') + ->willThrowException(new LocalizedException(new Phrase('Some error'))); + + $this->commandTester->execute([]); + $this->assertEquals( + 'Some error' . PHP_EOL, + $this->commandTester->getDisplay() + ); + $this->assertEquals(Cli::RETURN_FAILURE, $this->commandTester->getStatusCode()); + } +} diff --git a/app/code/Magento/Cron/etc/di.xml b/app/code/Magento/Cron/etc/di.xml index d5624e96765c5..6abc9096f2401 100644 --- a/app/code/Magento/Cron/etc/di.xml +++ b/app/code/Magento/Cron/etc/di.xml @@ -8,6 +8,8 @@ + + @@ -28,6 +30,8 @@ Magento\Cron\Console\Command\CronCommand + Magento\Cron\Console\Command\CronInstallCommand + Magento\Cron\Console\Command\CronRemoveCommand @@ -38,4 +42,24 @@ + + + Magento\Framework\App\Shell + + + + + + + {magentoRoot}bin/magento cron:run | grep -v "Ran jobs by schedule" >> {magentoLog}magento.cron.log + + + {magentoRoot}update/cron.php >> {magentoLog}update.cron.log + + + {magentoRoot}bin/magento setup:cron:run >> {magentoLog}setup.cron.log + + + + diff --git a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php index b4e4fef8fb2f9..40b262e3e4f51 100644 --- a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php +++ b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php @@ -5,7 +5,7 @@ */ namespace Magento\Deploy\Console\Command\App; -use Magento\Framework\App\Config\Reader\Source\SourceInterface; +use Magento\Framework\App\Config\ConfigSourceInterface; use Magento\Framework\App\DeploymentConfig\Writer; use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Console\Cli; @@ -24,7 +24,7 @@ class ApplicationDumpCommand extends Command private $writer; /** - * @var SourceInterface[] + * @var ConfigSourceInterface[] */ private $sources; @@ -64,20 +64,29 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { $dump = []; + $comments = []; foreach ($this->sources as $sourceData) { - /** @var SourceInterface $source */ + /** @var ConfigSourceInterface $source */ $source = $sourceData['source']; $namespace = $sourceData['namespace']; $dump[$namespace] = $source->get(); + if (!empty($sourceData['comment'])) { + $comments[$namespace] = is_string($sourceData['comment']) + ? $sourceData['comment'] + : $sourceData['comment']->get(); + } } - $this->writer ->saveConfig( [ConfigFilePool::APP_CONFIG => $dump], true, - ConfigFilePool::LOCAL + ConfigFilePool::LOCAL, + $comments ); + if (!empty($comments)) { + $output->writeln($comments); + } $output->writeln('Done.'); - return Cli::RETURN_SUCCESS; + return Cli::RETURN_SUCCESS; } } diff --git a/app/code/Magento/Developer/etc/di.xml b/app/code/Magento/Developer/etc/di.xml index 80433242853b8..2362aaa0780de 100644 --- a/app/code/Magento/Developer/etc/di.xml +++ b/app/code/Magento/Developer/etc/di.xml @@ -252,4 +252,11 @@ + + + + 1 + + + diff --git a/app/code/Magento/Dhl/etc/di.xml b/app/code/Magento/Dhl/etc/di.xml index a215c2e821825..cbe795791147c 100644 --- a/app/code/Magento/Dhl/etc/di.xml +++ b/app/code/Magento/Dhl/etc/di.xml @@ -9,4 +9,13 @@ + + + + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Directory/etc/di.xml b/app/code/Magento/Directory/etc/di.xml index f868197e60593..b4da40d119fe3 100644 --- a/app/code/Magento/Directory/etc/di.xml +++ b/app/code/Magento/Directory/etc/di.xml @@ -47,4 +47,12 @@ + + + + + 1 + + + diff --git a/app/code/Magento/NewRelicReporting/etc/di.xml b/app/code/Magento/NewRelicReporting/etc/di.xml index caabf89be1871..6e3a24be91982 100644 --- a/app/code/Magento/NewRelicReporting/etc/di.xml +++ b/app/code/Magento/NewRelicReporting/etc/di.xml @@ -12,4 +12,14 @@ Magento\Framework\Module\FullModuleList + + + + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Paypal/etc/di.xml b/app/code/Magento/Paypal/etc/di.xml index c5cbdbdc51331..940876451fd59 100644 --- a/app/code/Magento/Paypal/etc/di.xml +++ b/app/code/Magento/Paypal/etc/di.xml @@ -182,4 +182,32 @@ Magento\Vault\Model\CreditCardTokenFactory + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/ProductAlert/composer.json b/app/code/Magento/ProductAlert/composer.json index 9c63c6958a465..4ed6a998b084e 100644 --- a/app/code/Magento/ProductAlert/composer.json +++ b/app/code/Magento/ProductAlert/composer.json @@ -9,6 +9,9 @@ "magento/module-customer": "100.2.*", "magento/framework": "100.2.*" }, + "suggest": { + "magento/module-config": "100.2.*" + }, "type": "magento2-module", "version": "100.2.0-dev", "license": [ diff --git a/app/code/Magento/ProductAlert/etc/di.xml b/app/code/Magento/ProductAlert/etc/di.xml index 734b0f6695778..d5c81adce46f0 100644 --- a/app/code/Magento/ProductAlert/etc/di.xml +++ b/app/code/Magento/ProductAlert/etc/di.xml @@ -13,4 +13,12 @@ + + + + + 1 + + + diff --git a/app/code/Magento/ProductVideo/composer.json b/app/code/Magento/ProductVideo/composer.json index 08d21e4c2abbf..726104c084677 100644 --- a/app/code/Magento/ProductVideo/composer.json +++ b/app/code/Magento/ProductVideo/composer.json @@ -12,7 +12,8 @@ "magento/magento-composer-installer": "*" }, "suggest": { - "magento/module-customer": "100.2.*" + "magento/module-customer": "100.2.*", + "magento/module-config": "100.2.*" }, "type": "magento2-module", "version": "100.2.0-dev", diff --git a/app/code/Magento/ProductVideo/etc/di.xml b/app/code/Magento/ProductVideo/etc/di.xml index 7242a9d48ce1e..9aad01caaf72b 100644 --- a/app/code/Magento/ProductVideo/etc/di.xml +++ b/app/code/Magento/ProductVideo/etc/di.xml @@ -46,4 +46,11 @@ + + + + 1 + + + diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml index 4e2487d9dcada..eb392fc83d858 100644 --- a/app/code/Magento/Sales/etc/di.xml +++ b/app/code/Magento/Sales/etc/di.xml @@ -956,4 +956,18 @@ + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Shipping/composer.json b/app/code/Magento/Shipping/composer.json index 03f51bbd95e0f..6f3f5c3925fa5 100644 --- a/app/code/Magento/Shipping/composer.json +++ b/app/code/Magento/Shipping/composer.json @@ -21,7 +21,8 @@ }, "suggest": { "magento/module-fedex": "100.2.*", - "magento/module-ups": "100.2.*" + "magento/module-ups": "100.2.*", + "magento/module-config": "100.2.*" }, "type": "magento2-module", "version": "100.2.0-dev", diff --git a/app/code/Magento/Shipping/etc/di.xml b/app/code/Magento/Shipping/etc/di.xml index 1fe0657bf1337..44e138d6c9ac6 100644 --- a/app/code/Magento/Shipping/etc/di.xml +++ b/app/code/Magento/Shipping/etc/di.xml @@ -9,4 +9,16 @@ + + + + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Sitemap/composer.json b/app/code/Magento/Sitemap/composer.json index 9f556178fc2cc..307691a67d2e2 100644 --- a/app/code/Magento/Sitemap/composer.json +++ b/app/code/Magento/Sitemap/composer.json @@ -12,6 +12,9 @@ "magento/module-media-storage": "100.2.*", "magento/framework": "100.2.*" }, + "suggest": { + "magento/module-config": "100.2.*" + }, "type": "magento2-module", "version": "100.2.0-dev", "license": [ diff --git a/app/code/Magento/Sitemap/etc/di.xml b/app/code/Magento/Sitemap/etc/di.xml index 7ce1fdee7b5b6..dfe34a25fb7ba 100644 --- a/app/code/Magento/Sitemap/etc/di.xml +++ b/app/code/Magento/Sitemap/etc/di.xml @@ -11,4 +11,11 @@ Magento\Sitemap\Model\ResourceModel\Sitemap + + + + 1 + + + diff --git a/app/code/Magento/Theme/Model/Design/Config/DataProvider.php b/app/code/Magento/Theme/Model/Design/Config/DataProvider.php index c433b02fab240..977295c1f80c4 100644 --- a/app/code/Magento/Theme/Model/Design/Config/DataProvider.php +++ b/app/code/Magento/Theme/Model/Design/Config/DataProvider.php @@ -5,9 +5,13 @@ */ namespace Magento\Theme\Model\Design\Config; +use Magento\Framework\App\Config\ScopeCodeResolver; +use Magento\Framework\App\ObjectManager; use Magento\Theme\Model\ResourceModel\Design\Config\Collection; use Magento\Theme\Model\ResourceModel\Design\Config\CollectionFactory; use Magento\Ui\DataProvider\AbstractDataProvider; +use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; +use Magento\Framework\App\RequestInterface; class DataProvider extends AbstractDataProvider { @@ -31,6 +35,21 @@ class DataProvider extends AbstractDataProvider */ private $metadataLoader; + /** + * @var SettingChecker + */ + private $settingChecker; + + /** + * @var RequestInterface + */ + private $request; + + /** + * @var ScopeCodeResolver + */ + private $scopeCodeResolver; + /** * @param string $name * @param string $primaryFieldName @@ -78,4 +97,84 @@ public function getData() $this->loadedData = $this->dataLoader->getData(); return $this->loadedData; } + + /** + * {@inheritdoc} + */ + public function getMeta() + { + $meta = parent::getMeta(); + if (!isset($meta['other_settings']['children'])) { + return $meta; + } + + $request = $this->getRequest()->getParams(); + if (!isset($request['scope'])) { + return $meta; + } + + $scope = $request['scope']; + $scopeCode = $this->getScopeCodeResolver()->resolve( + $scope, + isset($request['scope_id']) ? $request['scope_id'] : null + ); + + foreach ($meta['other_settings']['children'] as $settingGroupName => &$settingGroup) { + foreach ($settingGroup['children'] as $fieldName => &$field) { + $path = sprintf( + 'design/%s/%s', + $settingGroupName, + preg_replace('/^' . $settingGroupName . '_/', '', $fieldName) + ); + $isReadOnly = $this->getSettingChecker()->isReadOnly( + $path, + $scope, + $scopeCode + ); + + if ($isReadOnly) { + $field['arguments']['data']['config']['disabled'] = true; + $field['arguments']['data']['config']['is_disable_inheritance'] = true; + } + } + } + + return $meta; + } + + /** + * @deprecated + * @return ScopeCodeResolver + */ + private function getScopeCodeResolver() + { + if ($this->scopeCodeResolver === null) { + $this->scopeCodeResolver = ObjectManager::getInstance()->get(ScopeCodeResolver::class); + } + return $this->scopeCodeResolver; + } + + /** + * @deprecated + * @return SettingChecker + */ + private function getSettingChecker() + { + if ($this->settingChecker === null) { + $this->settingChecker = ObjectManager::getInstance()->get(SettingChecker::class); + } + return $this->settingChecker; + } + + /** + * @deprecated + * @return RequestInterface + */ + private function getRequest() + { + if ($this->request === null) { + $this->request = ObjectManager::getInstance()->get(RequestInterface::class); + } + return $this->request; + } } diff --git a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php index 3ba61da79b5ca..a5db6156efea3 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php @@ -5,11 +5,18 @@ */ namespace Magento\Theme\Test\Unit\Model\Design\Config; +use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; +use Magento\Framework\App\Config\ScopeCodeResolver; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Theme\Model\Design\Config\DataLoader; use Magento\Theme\Model\Design\Config\DataProvider; use Magento\Theme\Model\Design\Config\MetadataLoader; use Magento\Theme\Model\ResourceModel\Design\Config\Collection; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class DataProviderTest extends \PHPUnit_Framework_TestCase { /** @@ -32,8 +39,29 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase */ protected $collection; + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $requestMock; + + /** + * @var ScopeCodeResolver|\PHPUnit_Framework_MockObject_MockObject + */ + private $scopeCodeResolverMock; + + /** + * @var SettingChecker|\PHPUnit_Framework_MockObject_MockObject + */ + private $settingCheckerMock; + protected function setUp() { + $this->objectManager = new ObjectManager($this); $this->dataLoader = $this->getMockBuilder(\Magento\Theme\Model\Design\Config\DataProvider\DataLoader::class) ->disableOriginalConstructor() ->getMock(); @@ -56,6 +84,16 @@ protected function setUp() ->method('create') ->willReturn($this->collection); + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->scopeCodeResolverMock = $this->getMockBuilder(ScopeCodeResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->settingCheckerMock = $this->getMockBuilder(SettingChecker::class) + ->disableOriginalConstructor() + ->getMock(); + $this->model = new DataProvider( 'scope', 'scope', @@ -64,6 +102,21 @@ protected function setUp() $this->metadataLoader, $collectionFactory ); + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'request', + $this->requestMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'scopeCodeResolver', + $this->scopeCodeResolverMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'settingChecker', + $this->settingCheckerMock + ); } public function testGetData() @@ -78,4 +131,119 @@ public function testGetData() $this->assertEquals($data, $this->model->getData()); } + + /** + * @param array $inputMeta + * @param array $expectedMeta + * @param array $request + * @dataProvider getMetaDataProvider + */ + public function testGetMeta(array $inputMeta, array $expectedMeta, array $request) + { + $this->requestMock->expects($this->any()) + ->method('getParams') + ->willReturn($request); + $this->scopeCodeResolverMock->expects($this->any()) + ->method('resolve') + ->with('stores', 1) + ->willReturn('default'); + $this->settingCheckerMock->expects($this->any()) + ->method('isReadOnly') + ->withConsecutive( + ['design/head/welcome', 'stores', 'default'], + ['design/head/logo', 'stores', 'default'], + ['design/head/head', 'stores', 'default'] + ) + ->willReturnOnConsecutiveCalls( + true, + false, + true + ); + + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'meta', + $inputMeta + ); + + $this->assertSame($expectedMeta, $this->model->getMeta()); + } + + /** + * @return array + */ + public function getMetaDataProvider() + { + return [ + [ + [ + 'option1' + ], + [ + 'option1' + ], + [ + 'scope' => 'default' + ] + ], + [ + [ + 'other_settings' => [ + 'children' => [ + 'head' => [ + 'children' => [ + 'head_welcome' => [ + + ], + 'head_logo' => [ + + ], + 'head_head' => [ + + ] + ] + ] + ] + ] + ], + [ + 'other_settings' => [ + 'children' => [ + 'head' => [ + 'children' => [ + 'head_welcome' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'disabled' => true, + 'is_disable_inheritance' => true, + ] + ] + ] + ], + 'head_logo' => [ + + ], + 'head_head' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'disabled' => true, + 'is_disable_inheritance' => true, + ] + ] + ] + ] + ] + ] + ] + ] + ], + [ + 'scope' => 'stores', + 'scope_id' => 1 + ] + ] + ]; + } } diff --git a/app/code/Magento/Ups/composer.json b/app/code/Magento/Ups/composer.json index c20dd28ba8887..e3cf2bce1813a 100644 --- a/app/code/Magento/Ups/composer.json +++ b/app/code/Magento/Ups/composer.json @@ -12,6 +12,9 @@ "magento/module-quote": "100.2.*", "magento/framework": "100.2.*" }, + "suggest": { + "magento/module-config": "100.2.*" + }, "type": "magento2-module", "version": "100.2.0-dev", "license": [ diff --git a/app/code/Magento/Ups/etc/di.xml b/app/code/Magento/Ups/etc/di.xml new file mode 100644 index 0000000000000..324349a82994f --- /dev/null +++ b/app/code/Magento/Ups/etc/di.xml @@ -0,0 +1,21 @@ + + + + + + + 1 + 1 + 1 + 1 + 1 + 1 + + + + diff --git a/app/code/Magento/Usps/etc/di.xml b/app/code/Magento/Usps/etc/di.xml new file mode 100644 index 0000000000000..450a24ad8b9f7 --- /dev/null +++ b/app/code/Magento/Usps/etc/di.xml @@ -0,0 +1,19 @@ + + + + + + + 1 + 1 + 1 + 1 + + + + diff --git a/app/etc/di.xml b/app/etc/di.xml index e9767eccb2811..1b347574f4b2a 100755 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -433,7 +433,7 @@ - Magento\Framework\Data\CollectionDataSourceInterface + Magento\Framework\View\Element\Block\ArgumentInterface diff --git a/dev/tests/functional/composer.json b/dev/tests/functional/composer.json index e4a9bd10fa658..f170114a4ea83 100644 --- a/dev/tests/functional/composer.json +++ b/dev/tests/functional/composer.json @@ -1,6 +1,6 @@ { "require": { - "magento/mtf": "1.0.0-rc49", + "magento/mtf": "1.0.0-rc50", "php": "~5.6.5|7.0.2|~7.0.6", "phpunit/phpunit": "~4.8.0|~5.5.0", "phpunit/phpunit-selenium": ">=1.2" diff --git a/dev/tests/functional/credentials.xml.dist b/dev/tests/functional/credentials.xml.dist index 78186091a568d..1061ca183f7f9 100644 --- a/dev/tests/functional/credentials.xml.dist +++ b/dev/tests/functional/credentials.xml.dist @@ -48,20 +48,32 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - diff --git a/dev/tests/functional/lib/Magento/Mtf/Client/Element/DatepickerElement.php b/dev/tests/functional/lib/Magento/Mtf/Client/Element/DatepickerElement.php index e09ca5647cf59..07ac393631190 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Client/Element/DatepickerElement.php +++ b/dev/tests/functional/lib/Magento/Mtf/Client/Element/DatepickerElement.php @@ -67,8 +67,8 @@ public function setValue($value) $date[1] = ltrim($date[1], '0'); $this->find($this->datePickerButton, Locator::SELECTOR_XPATH)->click(); $datapicker = $this->find($this->datePickerBlock, Locator::SELECTOR_XPATH); - $datapicker->find($this->datePickerMonth, Locator::SELECTOR_XPATH, 'select')->setValue($date[0]); $datapicker->find($this->datePickerYear, Locator::SELECTOR_XPATH, 'select')->setValue($date[2]); + $datapicker->find($this->datePickerMonth, Locator::SELECTOR_XPATH, 'select')->setValue($date[0]); $datapicker->find(sprintf($this->datePickerCalendar, $date[1]), Locator::SELECTOR_XPATH)->click(); if ($datapicker->isVisible()) { $datapicker->find($this->datePickerButtonClose, Locator::SELECTOR_XPATH)->click(); diff --git a/dev/tests/functional/lib/Magento/Mtf/Constraint/AbstractAssertForm.php b/dev/tests/functional/lib/Magento/Mtf/Constraint/AbstractAssertForm.php index ba1eca68a2436..7114ec405ea28 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Constraint/AbstractAssertForm.php +++ b/dev/tests/functional/lib/Magento/Mtf/Constraint/AbstractAssertForm.php @@ -118,8 +118,8 @@ protected function sortData(array $data) /** * Sort multidimensional array by paths. - * Pattern path: key/subKey::sorkKey. - * Exapmle: + * Pattern path: key/subKey::sortKey. + * Example: * $data = [ * 'custom_options' => [ * 'options' => [ diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Block/Form/Cc.php b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Block/Form/Cc.php deleted file mode 100644 index 7918859e53715..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Block/Form/Cc.php +++ /dev/null @@ -1,18 +0,0 @@ - - - - payment - - - - select - - - select - - - - diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Fixture/CreditCardAuthorizenet.xml b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Fixture/CreditCardAuthorizenet.xml deleted file mode 100644 index 2777d09b4f163..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Fixture/CreditCardAuthorizenet.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml index d629bcba9e174..d25149f645f05 100644 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml @@ -17,9 +17,8 @@ 15.00 - credit_card_authorizenet authorizenet_directpost - visa_authorizenet + visa_default authorizenet Processing test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/BraintreeCc.php similarity index 65% rename from dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.php rename to dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/BraintreeCc.php index 2179efc0d5bf1..60354b0f9ca28 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/BraintreeCc.php @@ -9,26 +9,33 @@ use Magento\Mtf\Client\Locator; use Magento\Mtf\Client\Element\SimpleElement; use Magento\Mtf\Fixture\FixtureInterface; -use Magento\Payment\Test\Block\Form\Cc as CreditCard; +use Magento\Mtf\ObjectManager; +use Magento\Payment\Test\Block\Form\PaymentCc; /** - * Class Cc - * Form for filling credit card data for Braintree payment method + * Form for filling credit card data for Braintree payment method. */ -class Cc extends CreditCard +class BraintreeCc extends PaymentCc { /** - * Braintree iFrame locator + * Braintree iFrame locator. * * @var array */ protected $braintreeForm = [ - "credit_card_number" => "#braintree-hosted-field-number", - "credit_card_exp_month" => "#braintree-hosted-field-expirationMonth", - "credit_card_exp_year" => "#braintree-hosted-field-expirationYear", - "cvv" => "#braintree-hosted-field-cvv", + "cc_number" => "#braintree-hosted-field-number", + "cc_exp_month" => "#braintree-hosted-field-expirationMonth", + "cc_exp_year" => "#braintree-hosted-field-expirationYear", + "cc_cid" => "#braintree-hosted-field-cvv", ]; + /** + * Fill Braintree credit card form. + * + * @param FixtureInterface $fixture + * @param SimpleElement|null $element + * @return void + */ public function fill(FixtureInterface $fixture, SimpleElement $element = null) { $mapping = $this->dataMapping($fixture->getData()); @@ -40,7 +47,8 @@ function () use ($element, $iframe) { return $fieldElement->isVisible() ? true : null; } ); - $this->browser->switchToFrame(new Locator($iframe)); + $iframeLocator = ObjectManager::getInstance()->create(Locator::class, ['value' => $iframe]); + $this->browser->switchToFrame($iframeLocator); $element = $this->browser->find('body'); $this->browser->waitUntil( function () use ($element) { diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/BraintreeCc.xml similarity index 63% rename from dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.xml rename to dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/BraintreeCc.xml index 6ea1ba9ee6e15..d1d09ec7b1dd7 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/BraintreeCc.xml @@ -7,17 +7,17 @@ --> - + #credit-card-number - - + + #expiration-month - - + + #expiration-year - - + + #cvv - + \ No newline at end of file diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Info.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Info.php deleted file mode 100644 index 32dfb8f40fe87..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Info.php +++ /dev/null @@ -1,38 +0,0 @@ -_rootElement->getElements($this->info, Locator::SELECTOR_XPATH); - foreach ($elements as $row) { - $key = rtrim($row->find('./th', Locator::SELECTOR_XPATH)->getText(), ':'); - $value = $row->find('./td', Locator::SELECTOR_XPATH)->getText(); - $result[$key] = $value; - } - return $result; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php index bb1e067023157..29af7632f7fd7 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php @@ -6,13 +6,16 @@ namespace Magento\Braintree\Test\Constraint; -use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; +/** + * Assert that 3D Secure information is present on order page in Admin. + */ class Assert3dSecureInfoIsPresent extends AbstractConstraint { /** - * Assert that 3D Secure information is present on order page in Admin. + * Assert that 3D Secure information is present on order page in Admin. * * @param SalesOrderView $salesOrderView * @param array $paymentInformation @@ -20,7 +23,9 @@ class Assert3dSecureInfoIsPresent extends AbstractConstraint */ public function processAssert(SalesOrderView $salesOrderView, array $paymentInformation) { - $actualPaymentInformation = $salesOrderView->getBraintreeInfoBlock()->getPaymentInfo(); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $actualPaymentInformation = $infoTab->getPaymentInfoBlock()->getData(); foreach ($paymentInformation as $key => $value) { \PHPUnit_Framework_Assert::assertArrayHasKey( $key, diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/CreditCardBraintree.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/CreditCardBraintree.xml deleted file mode 100644 index e9baa301509ce..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/CreditCardBraintree.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SalesOrderView.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SalesOrderView.xml deleted file mode 100644 index be96e88c35f81..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SalesOrderView.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - 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 6aa9383ff2bd1..e780ece1ab971 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 @@ -6,33 +6,29 @@ */ --> - - - 4111111111111111 - 01 - 2020 - 123 - - + - 4000000000000002 - 01 - 20 - 123 + braintree + 4000000000000002 + 01 + 20 + 123 - 4000000000000028 - 01 - 2020 - 123 + braintree + 4000000000000028 + 01 + 2020 + 123 - 4000111111111511 - 01 - 2020 - 123 + braintree + 4000111111111511 + 01 + 2020 + 123 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/BraintreeSettlementReportTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/BraintreeSettlementReportTest.xml index e80f6071ae5d1..dba818e57659d 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/BraintreeSettlementReportTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/BraintreeSettlementReportTest.xml @@ -18,8 +18,8 @@ 15.00 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree Processing test_type:extended_acceptance_test, test_type:3rd_party_test, severity:S1 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreePaypalTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreePaypalTest.xml index 53847e55fd9f9..2f14871eda96e 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreePaypalTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreePaypalTest.xml @@ -14,7 +14,7 @@ login us_ca_ny_rule - 139.9 + 139.90 US_address_1_without_email Flat Rate @@ -34,7 +34,7 @@ login us_ca_ny_rule - 621.2 + 621.20 US_address_1_without_email Flat Rate diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineInvoiceEntityTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineInvoiceEntityTest.xml index d9f382e4b650e..da73da001338a 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineInvoiceEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineInvoiceEntityTest.xml @@ -18,11 +18,11 @@ Flat Rate Fixed - 139.9 + 139.90 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree Processing Back, Send Email, Credit Memo, Hold, Ship, Reorder @@ -50,8 +50,8 @@ 118.25 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree Processing Back, Send Email, Credit Memo, Hold, Ship, Reorder 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 083bd33feca7b..7e010fc4d1f0d 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 @@ -22,8 +22,8 @@ 145.98 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree Processing Back, Cancel, Send Email, Hold, Invoice, Ship, Reorder, Edit @@ -52,8 +52,8 @@ 145.98 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree, braintree_sale Processing Back, Send Email, Hold, Ship, Reorder @@ -79,7 +79,6 @@ 145.98 braintree - credit_card_braintree visa_braintree_fraud_rejected braintree Processing diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml index c9b26df050cfc..123a453a921d6 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml @@ -20,8 +20,8 @@ braintree braintree_cc_vault - credit_card_braintree - visa_braintree + visa_default + braintree Yes braintree, braintree_use_vault Processing diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/InvoicePaypalBraintreeTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/InvoicePaypalBraintreeTest.xml index 352e0ed684919..23985d208e5a6 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/InvoicePaypalBraintreeTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/InvoicePaypalBraintreeTest.xml @@ -15,10 +15,10 @@ Flat Rate Fixed - 139.9 + 139.90 - 139.9 + 139.90 braintree_paypal braintree, braintree_paypal, braintree_paypal_skip_order_review diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.xml index 841145d7a5fdf..1b9540c443650 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.xml @@ -17,8 +17,8 @@ Flat Rate Fixed braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree,braintree_fraudprotection Processing test_type:3rd_party_test, severity:S2 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 index 4a2aa551a1817..510d27d324f92 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDeclinedTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDeclinedTest.xml @@ -15,7 +15,6 @@ Flat Rate Fixed braintree - credit_card_braintree visa_braintree_fraud_rejected Transaction has been declined. Please try again later. braintree_fraud_tool_enabled_account, braintree_fraudprotection @@ -31,8 +30,8 @@ Flat Rate Fixed braintree - credit_card_braintree - visa_braintree + visa_default + braintree Sorry, but something went wrong braintree, braintree_incorrect_merchant_account_id Processing diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.xml index 95d07079ef36c..8d16fcc3fcae1 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.xml @@ -17,8 +17,8 @@ Flat Rate Fixed braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree,braintree_fraudprotection Canceled test_type:3rd_party_test, severity:S2 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 54fdfc96dc947..c99a855b236a5 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 @@ -21,7 +21,6 @@ 145.98 braintree - credit_card_braintree visa_braintree_3dsecure false braintree, braintree_3d_secure_not_triggered_due_threshold @@ -45,7 +44,6 @@ 145.98 braintree - credit_card_braintree visa_braintree_3dsecure false braintree, braintree_3d_secure_uk @@ -69,8 +67,8 @@ 145.98 braintree - credit_card_braintree - visa_braintree + visa_default + braintree false braintree Processing @@ -97,8 +95,8 @@ 145.98 braintree - credit_card_braintree - visa_braintree + visa_default + braintree false braintree, braintree_sale Processing 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 index 2a17d1496a72d..12cde9b6233a9 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.xml @@ -15,7 +15,6 @@ Flat Rate Fixed braintree - credit_card_braintree visa_braintree_3dsecure_failed secure3d_braintree braintree, braintree_3d_secure diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureTest.xml index 295a9dcd5c533..051700480fcb3 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureTest.xml @@ -22,7 +22,6 @@ 145.98 braintree - credit_card_braintree visa_braintree_3dsecure 1 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml index f8ffa51982f1f..06299e2e5a10c 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml @@ -17,8 +17,8 @@ Flat Rate Fixed braintree - credit_card_braintree - visa_braintree + visa_default + braintree 10.00 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 5f5e2f50594bf..1b7d248d537dc 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 @@ -21,8 +21,8 @@ braintree braintree_cc_vault false - credit_card_braintree - visa_braintree + visa_default + braintree braintree, braintree_use_vault Processing test_type:3rd_party_test, severity:S1 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultOnCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultOnCheckoutTest.xml index 35d55784b6762..327a1f8eb2ca2 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultOnCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultOnCheckoutTest.xml @@ -17,8 +17,8 @@ Fixed braintree braintree_cc_vault - credit_card_braintree - visa_braintree + visa_default + braintree Yes braintree, braintree_use_vault Processing diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultWith3dSecureOnCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultWith3dSecureOnCheckoutTest.xml index a5aa7645148e1..8dd9239d38526 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultWith3dSecureOnCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultWith3dSecureOnCheckoutTest.xml @@ -17,7 +17,6 @@ Fixed braintree braintree_cc_vault - credit_card_braintree visa_braintree_3dsecure 1 diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php index cb46e728191bf..be3abf935c5a4 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php @@ -6,9 +6,6 @@ namespace Magento\Bundle\Test\Fixture\Cart; -use Magento\Bundle\Test\Fixture\BundleProduct; -use Magento\Mtf\Fixture\FixtureInterface; - /** * Data for verify cart item block on checkout page. * @@ -18,42 +15,32 @@ class Item extends \Magento\Catalog\Test\Fixture\Cart\Item { /** - * @constructor - * @param FixtureInterface $product + * Return prepared dataset. + * + * @param null|string $key + * @return array */ - public function __construct(FixtureInterface $product) + public function getData($key = null) { - parent::__construct($product); - - /** @var BundleProduct $product */ - $bundleSelection = $product->getBundleSelections(); - $checkoutData = $product->getCheckoutData(); + parent::getData($key); + $bundleSelection = $this->product->getBundleSelections(); + $checkoutData = $this->product->getCheckoutData(); $checkoutBundleOptions = isset($checkoutData['options']['bundle_options']) ? $checkoutData['options']['bundle_options'] : []; + $productSku = [$this->product->getSku()]; foreach ($checkoutBundleOptions as $checkoutOptionKey => $checkoutOption) { - // Find option and value keys - $attributeKey = null; - $optionKey = null; - foreach ($bundleSelection['bundle_options'] as $key => $option) { - if ($option['title'] == $checkoutOption['title']) { - $attributeKey = $key; - - foreach ($option['assigned_products'] as $valueKey => $value) { - if (false !== strpos($value['search_data']['name'], $checkoutOption['value']['name'])) { - $optionKey = $valueKey; - } - } - } - } - + $keys = $this->getKeys($bundleSelection['bundle_options'], $checkoutOption); + $attributeKey = $keys['attribute']; + $optionKey = $keys['option']; // Prepare option data $bundleSelectionAttribute = $bundleSelection['products'][$attributeKey]; $bundleOptions = $bundleSelection['bundle_options'][$attributeKey]; $value = $bundleSelectionAttribute[$optionKey]->getName(); + $this->product->getSkuType() == 'No' ?: $productSku[] = $bundleSelectionAttribute[$optionKey]->getSku(); $qty = $bundleOptions['assigned_products'][$optionKey]['data']['selection_qty']; - $price = $product->getPriceType() == 'Yes' + $price = $this->product->getPriceType() == 'Yes' ? number_format($bundleSelectionAttribute[$optionKey]->getPrice(), 2) : number_format($bundleOptions['assigned_products'][$optionKey]['data']['selection_price_value'], 2); $optionData = [ @@ -64,6 +51,47 @@ public function __construct(FixtureInterface $product) $checkoutBundleOptions[$checkoutOptionKey] = $optionData; } + $this->data['sku'] = implode('-', $productSku); $this->data['options'] += $checkoutBundleOptions; + + return $this->data; + } + + /** + * Get option key. + * + * @param array $assignedProducts + * @param string $checkoutOption + * @return null|string + */ + private function getOptionKey(array $assignedProducts, $checkoutOption) + { + foreach ($assignedProducts as $key => $value) { + if (false !== strpos($value['search_data']['name'], $checkoutOption)) { + return $key; + } + } + + return null; + } + + /** + * Find option and attribute keys. + * + * @param array $bundleOptions + * @param string $checkoutOption + * @return array + */ + private function getKeys(array $bundleOptions, $checkoutOption) + { + $keys = []; + foreach ($bundleOptions as $key => $option) { + if ($option['title'] == $checkoutOption['title']) { + $keys['attribute'] = $key; + $keys['option'] = $this->getOptionKey($option['assigned_products'], $checkoutOption['value']['name']); + } + } + + return $keys; } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Cart/Item.php index c7dbba386958a..fb0ecca863582 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Cart/Item.php @@ -8,7 +8,6 @@ use Magento\Mtf\Fixture\DataSource; use Magento\Mtf\Fixture\FixtureInterface; -use Magento\Catalog\Test\Fixture\CatalogProductSimple; /** * Data for verify cart item block on checkout page. @@ -21,15 +20,31 @@ class Item extends DataSource { /** - * @constructor + * Product fixture. + * + * @var FixtureInterface + */ + protected $product; + + /** * @param FixtureInterface $product */ public function __construct(FixtureInterface $product) { - /** @var CatalogProductSimple $product */ - $checkoutData = $product->getCheckoutData(); + $this->product = $product; + } + + /** + * Return prepared dataset. + * + * @param null|string $key + * @return array + */ + public function getData($key = null) + { + $checkoutData = $this->product->getCheckoutData(); $cartItem = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : []; - $customOptions = $product->hasData('custom_options') ? $product->getCustomOptions() : []; + $customOptions = $this->product->hasData('custom_options') ? $this->product->getCustomOptions() : []; $checkoutCustomOptions = isset($checkoutData['options']['custom_options']) ? $checkoutData['options']['custom_options'] : []; @@ -52,9 +67,12 @@ public function __construct(FixtureInterface $product) ? $cartItem['options'] + $checkoutCustomOptions : $checkoutCustomOptions; $cartItem['qty'] = isset($checkoutData['qty']) - ? $checkoutData['qty'] - : 1; - + ? $checkoutData['qty'] + : 1; + $cartItem['sku'] = $this->product->getSku(); + $cartItem['name'] = $this->product->getName(); $this->data = $cartItem; + + return parent::getData($key); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml index 2fd8c04d1d80d..dc5e9c12ebcae 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml @@ -72,5 +72,18 @@ Yes Yes + + + Category%isolation% + category%isolation% + Yes + Yes + + default_category + + + catalogProductSimple::default + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php index ce8f5a4cbfd99..31002bd8129c4 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php @@ -7,7 +7,7 @@ namespace Magento\Checkout\Test\Block\Onepage; use Magento\Mtf\Block\Block; -use Magento\Mtf\Fixture\InjectableFixture; +use Magento\Payment\Test\Fixture\CreditCard; /** * Checkout payment block. @@ -47,7 +47,7 @@ class Payment extends Block * * @var string */ - protected $placeOrder = '.action.primary.checkout'; + protected $placeOrder = '.payment-method._active .action.primary.checkout'; /** * Wait element. @@ -74,14 +74,19 @@ class Payment extends Block * Select payment method. * * @param array $payment - * @param InjectableFixture|null $creditCard + * @param CreditCard|null $creditCard + * @param bool $fillCreditCardOn3rdParty * @throws \Exception * @return void */ - public function selectPaymentMethod(array $payment, InjectableFixture $creditCard = null) - { - $paymentSelector = sprintf($this->paymentMethodInput, $payment['method']); - $paymentLabelSelector = sprintf($this->paymentMethodLabel, $payment['method']); + public function selectPaymentMethod( + array $payment, + CreditCard $creditCard = null, + $fillCreditCardOn3rdParty = false + ) { + $paymentMethod = $payment['method']; + $paymentSelector = sprintf($this->paymentMethodInput, $paymentMethod); + $paymentLabelSelector = sprintf($this->paymentMethodLabel, $paymentMethod); try { $this->waitForElementNotVisible($this->waitElement); @@ -100,16 +105,15 @@ function () use ($browser, $paymentSelector) { $paymentRadioButton->click(); } - if ($payment['method'] == "purchaseorder") { + if ($paymentMethod == "purchaseorder") { $this->_rootElement->find($this->purchaseOrderNumber)->setValue($payment['po_number']); } - if ($creditCard !== null) { - $class = explode('\\', get_class($creditCard)); - $module = $class[1]; - /** @var \Magento\Payment\Test\Block\Form\Cc $formBlock */ + if ($creditCard !== null && $fillCreditCardOn3rdParty === false) { + $module = $creditCard->hasData('payment_code') ? ucfirst($creditCard->getPaymentCode()) : 'Payment'; + /** @var \Magento\Payment\Test\Block\Form\PaymentCc $formBlock */ $formBlock = $this->blockFactory->create( - "\\Magento\\{$module}\\Test\\Block\\Form\\Cc", - ['element' => $this->_rootElement->find('#payment_form_' . $payment['method'])] + "\\Magento\\{$module}\\Test\\Block\\Form\\{$module}Cc", + ['element' => $this->_rootElement->find('#payment_form_' . $paymentMethod)] ); $formBlock->fill($creditCard); } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart.xml index 04b191b2b6583..5286881980704 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart.xml @@ -10,7 +10,6 @@ module="Magento_Checkout" type="flat" entity_type="quote" - repository_class="Magento\Checkout\Test\Repository\Cart" handler_interface="Magento\Checkout\Test\Handler\Cart\CartInterface" class="Magento\Checkout\Test\Fixture\Cart"> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php index 37df8ea8b8925..d6fb3a272b429 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php @@ -10,6 +10,7 @@ use Magento\Checkout\Test\Page\CheckoutCart; use Magento\Cms\Test\Page\CmsIndex; use Magento\Mtf\Client\BrowserInterface; +use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\TestStep\TestStepInterface; /** @@ -18,46 +19,53 @@ class AddProductsToTheCartStep implements TestStepInterface { /** - * Array with products + * Array with products. * * @var array */ - protected $products; + private $products; /** - * Frontend product view page + * Storefront product view page. * * @var CatalogProductView */ - protected $catalogProductView; + private $catalogProductView; /** - * Page of checkout page + * Page of checkout page. * * @var CheckoutCart */ - protected $checkoutCart; + private $checkoutCart; /** - * Cms index page + * Cms index page. * * @var CmsIndex */ - protected $cmsIndex; + private $cmsIndex; /** - * Interface Browser + * Client Browser instance. * * @var BrowserInterface */ - protected $browser; + private $browser; + + /** + * Fixture factory. + * + * @var FixtureFactory + */ + private $fixtureFactory; /** - * @constructor * @param CatalogProductView $catalogProductView * @param CheckoutCart $checkoutCart * @param CmsIndex $cmsIndex * @param BrowserInterface $browser + * @param FixtureFactory $fixtureFactory * @param array $products */ public function __construct( @@ -65,19 +73,21 @@ public function __construct( CheckoutCart $checkoutCart, CmsIndex $cmsIndex, BrowserInterface $browser, + FixtureFactory $fixtureFactory, array $products ) { - $this->products = $products; $this->catalogProductView = $catalogProductView; $this->checkoutCart = $checkoutCart; $this->cmsIndex = $cmsIndex; $this->browser = $browser; + $this->fixtureFactory = $fixtureFactory; + $this->products = $products; } /** - * Add products to the cart + * Add products to the cart. * - * @return void + * @return array */ public function run() { @@ -89,5 +99,7 @@ public function run() $this->catalogProductView->getViewBlock()->addToCart($product); $this->catalogProductView->getMessagesBlock()->waitSuccessMessage(); } + $cart['data']['items'] = ['products' => $this->products]; + return ['cart' => $this->fixtureFactory->createByCode('cart', $cart)]; } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/GetPlacedOrderIdStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/GetPlacedOrderIdStep.php new file mode 100644 index 0000000000000..8d4fa8e471fbc --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/GetPlacedOrderIdStep.php @@ -0,0 +1,74 @@ +checkoutOnepageSuccess = $checkoutOnepageSuccess; + $this->decorator = $decorator; + } + + /** + * Get success placed order id. + * + * @return array + */ + public function run() + { + $incrementId = $this->checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(); + return [ + 'entityId' => $this->getEntityId($incrementId), + 'orderId' => $incrementId + ]; + } + + /** + * Get order entity id by increment id. + * + * @param string $incrementId + * @return string + */ + private function getEntityId($incrementId) + { + $url = $_ENV['app_frontend_url'] . 'rest/V1/orders/'; + $url .= '?searchCriteria[filterGroups][0][filters][0][field]=increment_id'; + $url .= '&searchCriteria[filterGroups][0][filters][0][value]=' . $incrementId; + $this->decorator->write($url, [], WebapiDecorator::GET); + $response = json_decode($this->decorator->read(), true); + $this->decorator->close(); + return $response['items'][0]['entity_id']; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/PlaceOrderStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/PlaceOrderStep.php index 2bfd346fbcaeb..8beada29036b8 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/PlaceOrderStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/PlaceOrderStep.php @@ -22,41 +22,44 @@ class PlaceOrderStep implements TestStepInterface * * @var CheckoutOnepage */ - protected $checkoutOnepage; + private $checkoutOnepage; /** * Assert that Order Grand Total is correct on checkout page review block. * * @var AssertGrandTotalOrderReview */ - protected $assertGrandTotalOrderReview; + private $assertGrandTotalOrderReview; /** * One page checkout success page. * * @var CheckoutOnepageSuccess */ - protected $checkoutOnepageSuccess; + private $checkoutOnepageSuccess; /** * Price array. * * @var array */ - protected $prices; + private $prices; /** + * Factory for fixtures. + * * @var FixtureFactory */ private $fixtureFactory; /** + * Array of product entities. + * * @var array */ private $products; /** - * @construct * @param CheckoutOnepage $checkoutOnepage * @param AssertGrandTotalOrderReview $assertGrandTotalOrderReview * @param CheckoutOnepageSuccess $checkoutOnepageSuccess @@ -74,10 +77,10 @@ public function __construct( ) { $this->checkoutOnepage = $checkoutOnepage; $this->assertGrandTotalOrderReview = $assertGrandTotalOrderReview; - $this->prices = $prices; $this->checkoutOnepageSuccess = $checkoutOnepageSuccess; $this->fixtureFactory = $fixtureFactory; $this->products = $products; + $this->prices = $prices; } /** @@ -91,18 +94,20 @@ public function run() $this->assertGrandTotalOrderReview->processAssert($this->checkoutOnepage, $this->prices['grandTotal']); } $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + $orderId = $this->checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(); $order = $this->fixtureFactory->createByCode( 'orderInjectable', [ 'data' => [ - 'entity_id' => ['products' => $this->products] + 'id' => $orderId, + 'entity_id' => ['products' => $this->products], ] ] ); return [ - 'orderId' => $this->checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(), - 'order' => $order + 'orderId' => $orderId, + 'order' => $order, ]; } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectPaymentMethodStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectPaymentMethodStep.php index 1f5d80bdbde49..5eea876f02b40 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectPaymentMethodStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectPaymentMethodStep.php @@ -7,68 +7,73 @@ namespace Magento\Checkout\Test\TestStep; use Magento\Checkout\Test\Page\CheckoutOnepage; -use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\TestStep\TestStepInterface; use Magento\Payment\Test\Fixture\CreditCard; /** - * Class SelectPaymentMethodStep - * Selecting payment method + * Select payment method step. */ class SelectPaymentMethodStep implements TestStepInterface { /** - * Onepage checkout page + * Onepage checkout page. * * @var CheckoutOnepage */ protected $checkoutOnepage; /** - * Payment information + * Payment information. * * @var string */ protected $payment; /** - * Credit card information + * Credit card information. * * @var string */ protected $creditCard; /** - * @constructor + * If fill credit card data should be filled on 3rd party side. + * + * @var bool + */ + private $fillCreditCardOn3rdParty; + + /** * @param CheckoutOnepage $checkoutOnepage * @param array $payment - * @param FixtureFactory $fixtureFactory - * @param string $creditCardClass - * @param array|CreditCard|null $creditCard + * @param CreditCard|null $creditCard + * @param bool $fillCreditCardOn3rdParty */ public function __construct( CheckoutOnepage $checkoutOnepage, array $payment, - FixtureFactory $fixtureFactory, - $creditCardClass = 'credit_card', - $creditCard = null + CreditCard $creditCard = null, + $fillCreditCardOn3rdParty = false ) { $this->checkoutOnepage = $checkoutOnepage; $this->payment = $payment; - if (isset($creditCard['dataset'])) { - $this->creditCard = $fixtureFactory->createByCode($creditCardClass, ['dataset' => $creditCard['dataset']]); - } + $this->creditCard = $creditCard; + $this->fillCreditCardOn3rdParty = $fillCreditCardOn3rdParty; } /** - * Run step that selecting payment method + * Run step that selecting payment method. * * @return void */ public function run() { if ($this->payment['method'] !== 'free') { - $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->payment, $this->creditCard); + $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod( + $this->payment, + $this->creditCard, + $this->fillCreditCardOn3rdParty + ); } } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/Cart/Item.php index d2a999627cb95..46cf2ceefe8ac 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/Cart/Item.php @@ -6,9 +6,6 @@ namespace Magento\ConfigurableProduct\Test\Fixture\Cart; -use Magento\ConfigurableProduct\Test\Fixture\ConfigurableProduct; -use Magento\Mtf\Fixture\FixtureInterface; - /** * Data for verify cart item block on checkout page. * @@ -20,25 +17,27 @@ class Item extends \Magento\Catalog\Test\Fixture\Cart\Item { /** - * @constructor - * @param FixtureInterface $product + * Return prepared dataset. + * + * @param null|string $key + * @return array */ - public function __construct(FixtureInterface $product) + public function getData($key = null) { - parent::__construct($product); - - /** @var ConfigurableProduct $product */ - $checkoutData = $product->getCheckoutData(); + parent::getData($key); + $productData = $this->product->getData(); + $checkoutData = $this->product->getCheckoutData(); $cartItem = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : []; - $attributesData = $product->getConfigurableAttributesData()['attributes_data']; + $attributesData = $this->product->getConfigurableAttributesData()['attributes_data']; $checkoutConfigurableOptions = isset($checkoutData['options']['configurable_options']) ? $checkoutData['options']['configurable_options'] : []; + $attributeKey = []; foreach ($checkoutConfigurableOptions as $key => $checkoutConfigurableOption) { $attribute = $checkoutConfigurableOption['title']; $option = $checkoutConfigurableOption['value']; - + $attributeKey[] = "$attribute:$option"; $checkoutConfigurableOptions[$key] = [ 'title' => isset($attributesData[$attribute]['label']) ? $attributesData[$attribute]['label'] @@ -48,10 +47,15 @@ public function __construct(FixtureInterface $product) : $option, ]; } + $attributeKey = implode(' ', $attributeKey); + $cartItem['sku'] = $productData['configurable_attributes_data']['matrix'][$attributeKey]['sku']; + $cartItem['name'] = $productData['name']; $cartItem['options'] = isset($cartItem['options']) ? $cartItem['options'] + $checkoutConfigurableOptions : $checkoutConfigurableOptions; $this->data = $cartItem; + + return $this->data; } } diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml index 3a099d79d370a..77b311bd7a51f 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml @@ -17,7 +17,6 @@ - currency @@ -83,7 +82,6 @@ CHF - currency @@ -127,7 +125,6 @@ GBP - currency @@ -150,6 +147,49 @@ + + + currency + 1 + + AUD + + + + currency + Australian Dollar + 1 + AUD + + + currency + Australian Dollar + 1 + AUD + + + + + currency + 1 + + USD + + + + currency + US Dollar + 1 + USD + + + currency + US Dollar + 1 + USD + + + currency 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 ba85d0d13bfc6..2edc328b5c5df 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 @@ -285,5 +285,17 @@ UK_address_default_billing, US_address_default_shipping + + + John + Doe + Magento %isolation% + Culver City + 24285 Elm + 555-55-555-55 + United States + California + 90230 + diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/Cart/Item.php index dd388ae11d2f6..1d0fabeceb771 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/Cart/Item.php @@ -6,9 +6,6 @@ namespace Magento\Downloadable\Test\Fixture\Cart; -use Magento\Downloadable\Test\Fixture\DownloadableProduct; -use Magento\Mtf\Fixture\FixtureInterface; - /** * Data for verify cart item block on checkout page. * @@ -18,17 +15,17 @@ class Item extends \Magento\Catalog\Test\Fixture\Cart\Item { /** - * @constructor - * @param FixtureInterface $product + * Return prepared dataset. + * + * @param null|string $key + * @return array */ - public function __construct(FixtureInterface $product) + public function getData($key = null) { - parent::__construct($product); - - /** @var DownloadableProduct $product */ + parent::getData($key); $checkoutDownloadableOptions = []; - $checkoutData = $product->getCheckoutData(); - $downloadableOptions = $product->getDownloadableLinks(); + $checkoutData = $this->product->getCheckoutData(); + $downloadableOptions = $this->product->getDownloadableLinks(); foreach ($checkoutData['options']['links'] as $link) { $keyLink = str_replace('link_', '', $link['label']); $checkoutDownloadableOptions[] = [ @@ -38,5 +35,7 @@ public function __construct(FixtureInterface $product) } $this->data['options'] += $checkoutDownloadableOptions; + + return $this->data; } } diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/Cart/Item.php index cc0cd2e9f09a4..2aaf1253885a1 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/Cart/Item.php @@ -6,9 +6,6 @@ namespace Magento\GroupedProduct\Test\Fixture\Cart; -use Magento\GroupedProduct\Test\Fixture\GroupedProduct; -use Magento\Mtf\Fixture\FixtureInterface; - /** * Data for verify cart item block on checkout page. * @@ -18,18 +15,19 @@ class Item extends \Magento\Catalog\Test\Fixture\Cart\Item { /** - * @constructor - * @param FixtureInterface $product + * Return prepared dataset. + * + * @param null|string $key + * @return array */ - public function __construct(FixtureInterface $product) + public function getData($key = null) { - /** @var GroupedProduct $product */ - $checkoutData = $product->getCheckoutData(); + $checkoutData = $this->product->getCheckoutData(); $this->data = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : []; $associatedProducts = []; $cartItem = []; - foreach ($product->getAssociated()['products'] as $key => $product) { + foreach ($this->product->getAssociated()['products'] as $key => $product) { $key = 'product_key_' . $key; $associatedProducts[$key] = $product; } @@ -51,5 +49,7 @@ public function __construct(FixtureInterface $product) } $this->data = $cartItem; + + return $this->data; } } diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml index 7648899060f8f..7f1fd69d8e784 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml @@ -33,6 +33,9 @@ default + + default + diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/CheckoutData.xml index e6529d1afe677..e2e17977b7dd6 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/CheckoutData.xml @@ -7,6 +7,33 @@ --> + + + + product_key_0 + 2 + + + product_key_1 + 1 + + + + + 100 + 560 + + + 2 + 1 + + + 200 + 560 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/DeleteIntegrationEntityTest.xml b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/DeleteIntegrationEntityTest.xml index 56431ee145d18..6594757fe15ee 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/DeleteIntegrationEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/DeleteIntegrationEntityTest.xml @@ -8,6 +8,7 @@ + default diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.php deleted file mode 100644 index 3e8226d371ff4..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.php +++ /dev/null @@ -1,17 +0,0 @@ -getData(); + unset($data['payment_code']); + $mapping = $this->dataMapping($data); + $this->_fill($mapping, $element); + + return $this; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/PaymentCc.xml similarity index 100% rename from dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.xml rename to dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/PaymentCc.xml diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php index 2b1d9bdcf2df8..c8b52ed317d0f 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php @@ -7,7 +7,7 @@ namespace Magento\Payment\Test\Constraint; use Magento\Mtf\Constraint\AbstractConstraint; -use Magento\Payment\Test\Repository\CreditCardAdmin; +use Magento\Payment\Test\Repository\CreditCard; use Magento\Sales\Test\Page\Adminhtml\OrderCreateIndex; /** @@ -30,10 +30,10 @@ class AssertCardRequiredFields extends AbstractConstraint /** * Assert required fields on credit card payment method in backend. * @param OrderCreateIndex $orderCreateIndex - * @param CreditCardAdmin $creditCard + * @param CreditCard $creditCard * @return void */ - public function processAssert(OrderCreateIndex $orderCreateIndex, CreditCardAdmin $creditCard) + public function processAssert(OrderCreateIndex $orderCreateIndex, CreditCard $creditCard) { $actualRequiredFields = $orderCreateIndex->getCreateBlock()->getBillingMethodBlock() ->getJsErrors(); diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCard.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCard.xml index 6fd5d8675b8b0..2fe0da150438a 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCard.xml +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCard.xml @@ -12,6 +12,8 @@ entity_type="credit_card" repository_class="Magento\Payment\Test\Repository\CreditCard" class="Magento\Payment\Test\Fixture\CreditCard"> + + diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCardAdmin.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCardAdmin.xml deleted file mode 100644 index 87e69cee86add..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCardAdmin.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCard.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCard.xml index 8e742ab30ba96..80c337d0a8578 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCard.xml +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCard.xml @@ -14,6 +14,14 @@ 123 + + Visa + 4111111111111111 + 01 - January + 2020 + 123 + + 4012888888881881 02 - February @@ -34,5 +42,13 @@ 2020 123 + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml deleted file mode 100644 index 371c8f350c6af..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - Visa - 4111111111111111 - 01 - January - 2020 - 123 - - - - Visa - 4617747819866651 - 01 - January - 2020 - 123 - - - Please Select - - Month - - - - diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/HostedPro/Cc.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/HostedPro/Cc.php new file mode 100644 index 0000000000000..53fd258b84cbb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/HostedPro/Cc.php @@ -0,0 +1,17 @@ + + + + + + select + #credit_card_type + + + #credit_card_number + + + [name=expiryMonth] + + + [name=expiryYear] + + + [name=cvv2] + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PayflowLink/Cc.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PayflowLink/Cc.php new file mode 100644 index 0000000000000..3f369efc7e829 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PayflowLink/Cc.php @@ -0,0 +1,17 @@ + + + + + + #cc_number + + + #expdate_month + + + #expdate_year + + + #cvv2_number + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PaymentsAdvanced/Cc.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PaymentsAdvanced/Cc.php new file mode 100644 index 0000000000000..a990a41cd69af --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PaymentsAdvanced/Cc.php @@ -0,0 +1,17 @@ + + + + + + #cc_number + + + #expdate_month + + + #expdate_year + + + #cvv2_number + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Onepage/Payment/HostedPro.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Onepage/Payment/HostedPro.php new file mode 100644 index 0000000000000..f7ee9fc20947e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Onepage/Payment/HostedPro.php @@ -0,0 +1,20 @@ +switchToPaypalFrame(); + $formBlock = $this->blockFactory->create( + $this->formBlockCc, + ['element' => $this->_rootElement->find($this->creditCardForm)] + ); + $formBlock->fill($creditCard, $iframeRootElement); + $iframeRootElement->find($this->payNowButton)->click(); + $this->browser->switchToFrame(); + } + + /** + * Check if error message is appeared. + * + * @return bool + */ + public function isErrorMessageVisible() + { + $isErrorMessageVisible = false; + if ($this->_rootElement->find($this->paypalIframe)->isPresent()) { + $iframeRootElement = $this->switchToPaypalFrame(); + $isErrorMessageVisible = $iframeRootElement->find($this->errorMessage)->isVisible(); + $this->browser->switchToFrame(); + } + return $isErrorMessageVisible; + } + + /** + * Change the focus to a PayPal frame. + * + * @return ElementInterface + */ + private function switchToPaypalFrame() + { + $iframeLocator = $this->browser->find($this->paypalIframe)->getLocator(); + $this->browser->switchToFrame($iframeLocator); + return $this->browser->find('body'); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/CheckoutOnepage.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/CheckoutOnepage.xml new file mode 100644 index 0000000000000..da37a44f9bf3d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/CheckoutOnepage.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/ConfigData.xml index 0706f45beeb4b..1669352dc026e 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/ConfigData.xml @@ -7,6 +7,23 @@ --> + + + payment + 1 + United Kingdom + GB + + + + + payment + 1 + United States + US + + + payment @@ -64,32 +81,32 @@ payment 1 - Yes - PAYPAL_BUSINESS_ACCOUNT + Email Associated with PayPal Merchant Account (Optional) + %payflow_pro_business_account% payment 1 - - PAYMENT_PAYFLOWPRO_PARTNER + Partner + %payflow_pro_partner% payment 1 - - PAYMENT_PAYFLOWPRO_USER + User + %payflow_pro_user% payment 1 - - PAYMENT_PAYFLOWPRO_PWD + Password + %payflow_pro_pwd% payment 1 - - PAYMENT_PAYFLOWPRO_VENDOR + Vendor + %payflow_pro_vendor% payment @@ -124,9 +141,133 @@ + payment + 1 + No + 0 + + + + + + payment + 1 + Email Associated with PayPal Merchant Account (Optional) + %payflow_pro_fraud_protection_enabled_business_account% + + + payment + 1 + Partner + %payflow_pro_fraud_protection_enabled_partner% + + + payment + 1 + User + %payflow_pro_fraud_protection_enabled_user% + + + payment + 1 + Password + %payflow_pro_fraud_protection_enabled_pwd% + + + payment + 1 + Vendor + %payflow_pro_fraud_protection_enabled_vendor% + + + payment + 1 + + 1 + + + payment + 1 + Yes + 1 + + + payment + 1 + Yes + 1 + + payment 1 Yes + 1 + + + payment + 1 + Yes + 1 + + + + + payment + 1 + No + 0 + + + + + + payment + 1 + Yes + HOSTED_PRO_BUSINESS_ACCOUNT + + + payment + 1 + + HOSTED_PRO_API_USERNAME + + + payment + 1 + + HOSTED_PRO_API_PASSWORD + + + payment + 1 + + HOSTED_PRO_API_SIGNATURE + + + payment + 1 + Yes + 1 + + + payment + 1 + Yes + 1 + + + payment + 1 + Yes + 1 + + + + + payment + 1 + No 0 @@ -184,41 +325,100 @@ + + + payment + 1 + Email Associated with PayPal Merchant Account + %payflow_link_business_account_email% + + + payment + 1 + Partner + %payflow_link_partner% + + + payment + 1 + User + %payflow_link_user% + + + payment + 1 + Password + %payflow_link_password% + + + payment + 1 + Vendor + %payflow_link_vendor% + + + payment + 1 + Yes + 1 + + + payment + 1 + Yes + 1 + + + + + payment + 1 + No + 0 + + + payment 1 - Yes - PAYPAL_BUSINESS_ACCOUNT + Email Associated with PayPal Merchant Account + %payflow_link_business_account_email% payment 1 - - PAYMENT_PAYFLOWLINK_PARTNER + Partner + %payflow_link_partner% payment 1 - - PAYMENT_PAYFLOWLINK_USER + User + %payflow_link_user% payment 1 - - PAYMENT_PAYFLOWLINK_PWD + Password + %payflow_link_password% payment 1 - - PAYMENT_PAYFLOWLINK_VENDOR + Vendor + %payflow_link_vendor% payment 1 - + Yes + 1 + + + payment + 1 + Yes 1 @@ -250,7 +450,7 @@ payment 1 - Yes + No 0 diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/CreditCard.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/CreditCard.xml similarity index 60% rename from dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/CreditCard.xml rename to dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/CreditCard.xml index c6b8eab58205e..9383dcd3faf4b 100644 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/CreditCard.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/CreditCard.xml @@ -6,10 +6,11 @@ */ --> - - - 4111111111111111 - 01 - January + + + V + 4032034402702800 + 01 2020 123 diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.php new file mode 100644 index 0000000000000..11acf819c9926 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.php @@ -0,0 +1,44 @@ + Orders page. + * 3. Open order. + * 4. Click 'Ship' button and submit shipment. + * 5. Click 'Invoice' button. + * 6. Select Amount=Capture Online. + * 7. Click 'Submit Invoice' button. + * 11. Perform assertions. + * + * @group Paypal + * @ZephyrId MAGETWO-13016 + */ +class CloseSalesWithHostedProTest extends Scenario +{ + /* tags */ + const MVP = 'yes'; + const TEST_TYPE = '3rd_party_test'; + /* end tags */ + + /** + * Complete order paid PayPal Payments Pro Hosted Solution. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.xml new file mode 100644 index 0000000000000..a7e058b4fba44 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.xml @@ -0,0 +1,38 @@ + + + + + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + us_ca_ny_rule + default + US_address_1_without_email + guest + Flat Rate + Fixed + hosted_pro + + 145.98 + + + 145.98 + + credit_card_hostedpro + visa_hosted_pro + false + Complete + merchant_country_gb, hosted_pro, config_base_currency_gb + test_type:3rd_party_test, severity:S0 + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml index 4ad751de68a71..ea4dc7b723146 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml @@ -19,7 +19,6 @@ 15.00 payflowpro - credit_card_admin visa_empty Yes payflowpro, payflowpro_use_vault diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml index ca26ad42a020c..53e9c7b83900a 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml @@ -20,8 +20,7 @@ payflowpro payflowpro_cc_vault - credit_card_admin - visa_default + visa_default_admin Yes payflowpro, payflowpro_use_vault Processing diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.php new file mode 100644 index 0000000000000..12cedd4ffa458 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.php @@ -0,0 +1,51 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.xml new file mode 100644 index 0000000000000..6583aa9cc873c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.xml @@ -0,0 +1,35 @@ + + + + + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + us_ca_ny_rule + default + US_address_1_without_email + guest + Flat Rate + Fixed + hosted_pro + + 145.98 + + credit_card_hostedpro + visa_hosted_pro + false + merchant_country_gb, hosted_pro, config_base_currency_gb + Processing + test_type:3rd_party_test, severity:S0 + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.php new file mode 100644 index 0000000000000..726d6833660be --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.php @@ -0,0 +1,51 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.xml new file mode 100644 index 0000000000000..b23a1c6ae9d79 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.xml @@ -0,0 +1,34 @@ + + + + + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + us_ca_ny_rule + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflow_link + + 145.98 + + visa_default + false + payflowlink + Processing + test_type:3rd_party_test, severity:S0 + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.php new file mode 100644 index 0000000000000..789b5ddd27faa --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.php @@ -0,0 +1,51 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.xml new file mode 100644 index 0000000000000..279a47689548b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.xml @@ -0,0 +1,34 @@ + + + + + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + us_ca_ny_rule + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflow_advanced + + 145.98 + + visa_default + false + payments_advanced + Processing + test_type:3rd_party_test, severity:S0 + + + + + + \ No newline at end of file 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 11f9d9d5270e6..655b2f5f9d3fb 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 @@ -19,7 +19,6 @@ 15.83 - credit_card visa_default false payflowpro @@ -28,5 +27,58 @@ + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + UK_address_without_email + guest + Flat Rate + Fixed + payflowpro + + 15.00 + + credit_card + visa_default + false + payflowpro_fraud_filters_enabled + + Under review by Fraud Service + #N: No Details matched + + Processing + + + + + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + AVS_street_match_address + guest + Flat Rate + Fixed + payflowpro + + 15.00 + + credit_card + visa_default + false + payflowpro_fraud_filters_enabled + + #Y: Yes. Matched Address and five-didgit ZIP + + Processing + + + + + 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 ad937cf472de7..f5dd4b9604e0a 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 @@ -20,7 +20,6 @@ payflowpro payflowpro_cc_vault - credit_card visa_default payflowpro, payflowpro_use_vault Processing diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/UseVaultOnCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/UseVaultOnCheckoutTest.xml index 92b4be03b5937..b81d36ad33038 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/UseVaultOnCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/UseVaultOnCheckoutTest.xml @@ -16,7 +16,6 @@ Fixed payflowpro payflowpro_cc_vault - credit_card visa_default Yes payflowpro, payflowpro_use_vault diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/GetPlacedOrderIdStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/GetPlacedOrderIdStep.php deleted file mode 100644 index bb1e1416dc933..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/GetPlacedOrderIdStep.php +++ /dev/null @@ -1,44 +0,0 @@ -checkoutOnepageSuccess = $checkoutOnepageSuccess; - } - - /** - * Get success placed order id. - * - * @return array - */ - public function run() - { - return [ - 'orderId' => $this->checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(), - ]; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithHostedProStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithHostedProStep.php new file mode 100644 index 0000000000000..cf602190a6286 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithHostedProStep.php @@ -0,0 +1,104 @@ +checkoutOnepage = $checkoutOnepage; + $this->fixtureFactory = $fixtureFactory; + $this->creditCard = $creditCard; + $this->payment = $payment; + $this->products = $products; + } + + /** + * Place order with Hosted Pro. + * + * @return array + */ + public function run() + { + $attempts = 1; + $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->payment); + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + $this->checkoutOnepage->getHostedProBlock()->fillPaymentData($this->creditCard); + // As Paypal Sandbox is not stable there are three attempts given to place order + while ($this->checkoutOnepage->getHostedProBlock()->isErrorMessageVisible() && $attempts <= 3) { + $this->checkoutOnepage->getHostedProBlock()->fillPaymentData($this->creditCard); + $attempts++; + } + /** @var OrderInjectable $order */ + $order = $this->fixtureFactory->createByCode( + 'orderInjectable', + [ + 'data' => [ + 'entity_id' => ['products' => $this->products] + ] + ] + ); + return ['order' => $order]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPayflowLinkStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPayflowLinkStep.php new file mode 100644 index 0000000000000..926dabe9722b6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPayflowLinkStep.php @@ -0,0 +1,98 @@ +checkoutOnepage = $checkoutOnepage; + $this->fixtureFactory = $fixtureFactory; + $this->creditCard = $creditCard; + $this->payment = $payment; + $this->products = $products; + } + + /** + * Place order with Payflow Link. + * + * @return array + */ + public function run() + { + $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->payment); + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + $this->checkoutOnepage->getPayflowLinkBlock()->fillPaymentData($this->creditCard); + + /** @var OrderInjectable $order */ + $order = $this->fixtureFactory->createByCode( + 'orderInjectable', + [ + 'data' => [ + 'entity_id' => ['products' => $this->products] + ] + ] + ); + return ['order' => $order]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPaymentsAdvancedStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPaymentsAdvancedStep.php new file mode 100644 index 0000000000000..c39a742c07c09 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPaymentsAdvancedStep.php @@ -0,0 +1,98 @@ +checkoutOnepage = $checkoutOnepage; + $this->fixtureFactory = $fixtureFactory; + $this->creditCard = $creditCard; + $this->payment = $payment; + $this->products = $products; + } + + /** + * Place order with Payments Advanced. + * + * @return array + */ + public function run() + { + $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->payment); + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + $this->checkoutOnepage->getPaymentsAdvancedBlock()->fillPaymentData($this->creditCard); + + /** @var OrderInjectable $order */ + $order = $this->fixtureFactory->createByCode( + 'orderInjectable', + [ + 'data' => [ + 'entity_id' => ['products' => $this->products] + ] + ] + ); + return ['order' => $order]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml index 89cf35b73bc3e..e333b4b4ffefc 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml @@ -13,7 +13,7 @@ - + @@ -59,7 +59,7 @@ - + @@ -85,4 +85,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractItems.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractItems.php index d76461b9ae5f0..d7a89b68c5538 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractItems.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractItems.php @@ -7,6 +7,7 @@ namespace Magento\Sales\Test\Block\Adminhtml\Order; use Magento\Mtf\Block\Block; +use Magento\Mtf\Client\ElementInterface; /** * Base Items block on Credit Memo, Invoice, Shipment view page. @@ -18,56 +19,63 @@ class AbstractItems extends Block * * @var string */ - protected $rowItem = 'tbody'; + private $rowItem = 'tbody'; /** - * Locator for "Product" column. + * Locator for product sku column. * * @var string */ - protected $product = '.col-product'; + private $sku = '.col-product .product-sku-block'; + + /** + * Locator for product title column. + * + * @var string + */ + private $title = '.col-product .product-title'; /** * Locator for "Price" column. * * @var string */ - protected $price = '.col-price .price'; + private $price = '.col-price .price'; /** * Locator for "Qty" column. * * @var string */ - protected $qty = '.col-qty'; + private $qty = '.col-qty'; /** * Locator for "Subtotal" column. * * @var string */ - protected $subtotal = '.col-subtotal .price'; + private $subtotal = '.col-subtotal .price'; /** * Locator for "Tax Amount" column. * * @var string */ - protected $taxAmount = '.col-tax .price'; + private $taxAmount = '.col-tax .price'; /** * Locator for "Discount Amount" column. * * @var string */ - protected $discountAmount = '.col-discount .price'; + private $discountAmount = '.col-discount .price'; /** * Locator for "Row total" column. * * @var string */ - protected $rowTotal = '.col-total .price'; + private $rowTotal = '.col-total .price'; /** * Get items data. @@ -82,9 +90,10 @@ public function getData() foreach ($items as $item) { $itemData = []; - $itemData += $this->parseProductName($item->find($this->product)->getText()); + $itemData['product'] = preg_replace('/\n|\r/', '', $item->find($this->title)->getText()); + $itemData['sku'] = $this->getSku($item); $itemData['price'] = $this->escapePrice($item->find($this->price)->getText()); - $itemData['qty'] = $item->find($this->qty)->getText(); + $itemData['qty'] = $this->getQty($item); $itemData['subtotal'] = $this->escapePrice($item->find($this->subtotal)->getText()); $itemData['tax'] = $this->escapePrice($item->find($this->taxAmount)->getText()); $itemData['discount'] = $this->escapePrice($item->find($this->discountAmount)->getText()); @@ -97,18 +106,33 @@ public function getData() } /** - * Parse product name to title and sku product. + * Get product quantity. * - * @param string $product - * @return array + * @param ElementInterface $item + * @return null|int + */ + private function getQty(ElementInterface $item) + { + $qty = null; + $elements = $item->getElements($this->qty); + foreach ($elements as $element) { + $qty += (int) $element->getText(); + } + return $qty; + } + + /** + * Get product SKU. + * + * @param ElementInterface $item + * @return string */ - protected function parseProductName($product) + private function getSku(ElementInterface $item) { - $data = array_map('trim', explode('SKU:', str_replace("\n", '', $product))); - return [ - 'product' => $data[0], - 'sku' => isset($data[1]) ? $data[1] : '' - ]; + $itemContent = $item->find($this->sku)->getText(); + $itemContent = preg_replace('/\n|\r/', '', $itemContent); + $itemContent = str_replace('SKU: ', '', $itemContent); + return $itemContent; } /** @@ -117,7 +141,7 @@ protected function parseProductName($product) * @var string $price * @return string */ - protected function escapePrice($price) + private function escapePrice($price) { return preg_replace('[^0-9\.]', '', $price); } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php index 8477af0087fd4..0d443eb1db9ff 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php @@ -7,8 +7,8 @@ namespace Magento\Sales\Test\Block\Adminhtml\Order\Create\Billing; use Magento\Mtf\Block\Block; -use Magento\Mtf\Fixture\InjectableFixture; use Magento\Mtf\Client\Locator; +use Magento\Payment\Test\Fixture\CreditCard; /** * Adminhtml sales order create payment method block. @@ -20,66 +20,60 @@ class Method extends Block * * @var string */ - protected $paymentMethod = '#p_method_%s'; + private $paymentMethod = '#p_method_%s'; /** * Purchase order number selector. * * @var string */ - protected $purchaseOrderNumber = '#po_number'; - - /** - * Payment form. - * - * @var string - */ - protected $paymentForm = '#payment_form_%s'; + private $purchaseOrderNumber = '#po_number'; /** * Magento loader selector. * * @var string */ - protected $loader = '[data-role=loader]'; + private $loader = '[data-role=loader]'; /** * Field with Mage error. * * @var string */ - protected $mageErrorField = '//fieldset/*[contains(@class,"field ")][.//*[contains(@class,"error")]]'; + private $mageErrorField = './/*[contains(@name, "payment[")]/following-sibling::label[@class="mage-error"]'; /** - * Mage error text. + * Error label preceding field of credit card form. * * @var string */ - protected $mageErrorText = './/label[contains(@class,"error")]'; + private $errorLabelPrecedingField = './preceding-sibling::*[1][contains(@name, "payment")]'; /** * Select payment method. * - * @param array $paymentCode - * @param InjectableFixture|null $creditCard + * @param array $payment + * @param CreditCard|null $creditCard + * @return void */ - public function selectPaymentMethod(array $paymentCode, InjectableFixture $creditCard = null) + public function selectPaymentMethod(array $payment, CreditCard $creditCard = null) { - $paymentInput = $this->_rootElement->find(sprintf($this->paymentMethod, $paymentCode['method'])); + $paymentMethod = $payment['method']; + $paymentInput = $this->_rootElement->find(sprintf($this->paymentMethod, $paymentMethod)); if ($paymentInput->isVisible()) { $paymentInput->click(); $this->waitForElementNotVisible($this->loader); } - if (isset($paymentCode['po_number'])) { - $this->_rootElement->find($this->purchaseOrderNumber)->setValue($paymentCode['po_number']); + if (isset($payment['po_number'])) { + $this->_rootElement->find($this->purchaseOrderNumber)->setValue($payment['po_number']); } if ($creditCard !== null) { - $class = explode('\\', get_class($creditCard)); - $module = $class[1]; - /** @var \Magento\Payment\Test\Block\Form\Cc $formBlock */ + $module = $creditCard->hasData('payment_code') ? ucfirst($creditCard->getPaymentCode()) : 'Payment'; + /** @var \Magento\Payment\Test\Block\Form\PaymentCc $formBlock */ $formBlock = $this->blockFactory->create( - "\\Magento\\{$module}\\Test\\Block\\Form\\Cc", - ['element' => $this->_rootElement->find('#payment_form_' . $paymentCode['method'])] + "\\Magento\\{$module}\\Test\\Block\\Form\\{$module}Cc", + ['element' => $this->_rootElement->find('#payment_form_' . $paymentMethod)] ); $formBlock->fill($creditCard); } @@ -92,10 +86,9 @@ public function getJsErrors() { $data = []; $elements = $this->_rootElement->getElements($this->mageErrorField, Locator::SELECTOR_XPATH); - foreach ($elements as $element) { - $error = $element->find($this->mageErrorText, Locator::SELECTOR_XPATH); + foreach ($elements as $error) { if ($error->isVisible()) { - $label = $element->find('.//*[contains(@name,"payment")]', Locator::SELECTOR_XPATH); + $label = $error->find($this->errorLabelPrecedingField, Locator::SELECTOR_XPATH); $label = $label->getAttribute('name'); $label = preg_replace('/payment\[(.*)\]/u', '$1', $label); $data[$label] = $error->getText(); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Totals.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Totals.php index b6b14670c0f56..3433447222ccb 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Totals.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Totals.php @@ -28,6 +28,13 @@ class Totals extends \Magento\Sales\Test\Block\Adminhtml\Order\Totals */ protected $capture = '[name="invoice[capture_case]"]'; + /** + * Offline capture text message selector. + * + * @var string + */ + private $captureOfflineMessage = './/input[@value="offline"]/following-sibling::div[1]'; + /** * Submit invoice * @@ -58,4 +65,15 @@ public function setCaptureOption($option) { $this->_rootElement->find($this->capture, Locator::SELECTOR_CSS, 'select')->setValue($option); } + + /** + * Get message that invoice can be created only offline. + * + * @return null|string + */ + public function getCaptureOfflineMessage() + { + $captureCaseMessage = $this->_rootElement->find($this->captureOfflineMessage, Locator::SELECTOR_XPATH); + return $captureCaseMessage->isVisible() ? $captureCaseMessage->getText() : null; + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.php index 757a025605b9b..2261257ca70fe 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.php @@ -7,30 +7,11 @@ namespace Magento\Sales\Test\Block\Adminhtml\Order\View; use Magento\Backend\Test\Block\Widget\FormTabs; -use Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info as OrderInformationBlock; /** - * Order view tabs + * Order view tabs. */ class OrderForm extends FormTabs { - /** - * Order information block. - * - * @var string - */ - protected $orderInfoBlock = '[data-ui-id="sales-order-tabs-tab-content-order-info"]'; - - /** - * Get order information block. - * - * @return OrderInformationBlock - */ - public function getOrderInfoBlock() - { - return $this->blockFactory->create( - \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info::class, - ['element' => $this->_rootElement->find($this->orderInfoBlock)] - ); - } + // } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.xml index 383dfb8b7b6aa..0a5aa8e1993a8 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.xml @@ -6,6 +6,11 @@ */ --> + + Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info + #sales_order_view_tabs_order_info + css selector + Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Invoices #sales_order_view_tabs_order_invoices diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info.php index 50c5a077e9b55..146e3facccb61 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info.php @@ -6,22 +6,30 @@ namespace Magento\Sales\Test\Block\Adminhtml\Order\View\Tab; -use Magento\Mtf\Block\Block; +use Magento\Backend\Test\Block\Widget\Tab; +use Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info\PaymentInfoBlock; /** * Order information tab block. */ -class Info extends Block +class Info extends Tab { /** - * Order status selector + * Order status selector. * * @var string */ protected $orderStatus = '#order_status'; /** - * Get order status from info block + * Selector for 'Payment Information' block. + * + * @var string + */ + private $paymentInfoBlockSelector = '.order-payment-method'; + + /** + * Get order status from info block. * * @return array|string */ @@ -29,4 +37,17 @@ public function getOrderStatus() { return $this->_rootElement->find($this->orderStatus)->getText(); } + + /** + * Returns Payment Information block. + * + * @return PaymentInfoBlock + */ + public function getPaymentInfoBlock() + { + return $this->blockFactory->create( + PaymentInfoBlock::class, + ['element' => $this->_rootElement->find($this->paymentInfoBlockSelector)] + ); + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info/PaymentInfoBlock.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info/PaymentInfoBlock.php new file mode 100644 index 0000000000000..818a9b9717cb9 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info/PaymentInfoBlock.php @@ -0,0 +1,40 @@ +_rootElement->getElements($this->info); + foreach ($elements as $row) { + $key = rtrim($row->find('th')->getText(), ':'); + $value = $row->find('td')->getText(); + $result[$key] = $value; + } + + return $result; + } +} 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 4b37682957996..41fbd8979b58d 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 @@ -25,6 +25,13 @@ class Grid extends \Magento\Ui\Test\Block\Adminhtml\DataGrid */ protected $invoiceId = 'tbody td:nth-child(2)'; + /** + * Invoices data grid loader locator. + * + * @var string + */ + protected $loader = '[data-component="sales_order_view_invoice_grid"]'; + /** * Filters array mapping. * @@ -57,6 +64,7 @@ class Grid extends \Magento\Ui\Test\Block\Adminhtml\DataGrid public function getIds() { $result = []; + $this->waitForElementNotVisible($this->loader); $invoiceIds = $this->_rootElement->getElements($this->invoiceId); foreach ($invoiceIds as $invoiceId) { $result[] = trim($invoiceId->getText()); @@ -72,6 +80,7 @@ public function getIds() */ public function viewInvoice() { + $this->waitForElementNotVisible($this->loader); $this->_rootElement->find($this->invoiceId)->click(); } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertItems.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertItems.php index 26978343fb2c2..fc9bd8275d650 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertItems.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertItems.php @@ -6,25 +6,25 @@ namespace Magento\Sales\Test\Constraint; -use Magento\Catalog\Test\Fixture\CatalogProductSimple; -use Magento\Sales\Test\Fixture\OrderInjectable; +use Magento\Checkout\Test\Fixture\Cart; use Magento\Mtf\Constraint\AbstractAssertForm; +use Magento\Mtf\Fixture\FixtureFactory; +use Magento\Sales\Test\Fixture\OrderInjectable; /** - * Class AbstractAssertArchiveItems - * Assert items represented in order's entity view page + * Assert items represented in order's entity view page. */ abstract class AbstractAssertItems extends AbstractAssertForm { /** - * Key for sort data + * Key for sort data. * * @var string */ protected $sortKey = "::sku"; /** - * List compare fields + * List compare fields. * * @var array */ @@ -35,25 +35,29 @@ abstract class AbstractAssertItems extends AbstractAssertForm ]; /** - * Prepare order products + * Prepare order products. * * @param OrderInjectable $order * @param array|null $data [optional] + * @param Cart|null $cart [optional] * @return array */ - protected function prepareOrderProducts(OrderInjectable $order, array $data = null) + protected function prepareOrderProducts(OrderInjectable $order, array $data = null, Cart $cart = null) { - $products = $order->getEntityId()['products']; $productsData = []; - - /** @var CatalogProductSimple $product */ - foreach ($products as $key => $product) { + if ($cart === null) { + $cart['data']['items'] = ['products' => $order->getEntityId()['products']]; + $fixtureFactory = $this->objectManager->create(FixtureFactory::class); + $cart = $fixtureFactory->createByCode('cart', $cart); + } + /** @var \Magento\Catalog\Test\Fixture\Cart\Item $item */ + foreach ($cart->getItems() as $key => $item) { $productsData[] = [ - 'product' => $product->getName(), - 'sku' => $product->getSku(), + 'product' => $item->getData()['name'], + 'sku' => $item->getData()['sku'], 'qty' => (isset($data[$key]['qty']) && $data[$key]['qty'] != '-') ? $data[$key]['qty'] - : $product->getCheckoutData()['qty'], + : $item->getData()['qty'], ]; } @@ -61,7 +65,7 @@ protected function prepareOrderProducts(OrderInjectable $order, array $data = nu } /** - * Prepare invoice data + * Prepare invoice data. * * @param array $itemsData * @return array diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php index a6b8e8983d2b6..8b34837bc8df3 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php @@ -6,8 +6,8 @@ namespace Magento\Sales\Test\Constraint; -use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; use Magento\Sales\Test\Page\Adminhtml\OrderIndex; +use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; use Magento\Mtf\Constraint\AbstractConstraint; /** @@ -16,9 +16,9 @@ class AssertAuthorizationInCommentsHistory extends AbstractConstraint { /** - * Message about authorized amount in order. + * Pattern of message about authorized amount in order. */ - const AUTHORIZED_AMOUNT = 'Authorized amount of $'; + const AUTHORIZED_AMOUNT_PATTERN = '/(IPN "Pending" )*Authorized amount of \w*\W{1,2}%s. Transaction ID: "[\w\-]*"/'; /** * Assert that comment about authorized amount exist in Comments History section on order page in Admin. @@ -37,11 +37,10 @@ public function processAssert( ) { $salesOrder->open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); - $actualAuthorizedAmount = $salesOrderView->getOrderHistoryBlock()->getAuthorizedAmount(); - \PHPUnit_Framework_Assert::assertContains( - self::AUTHORIZED_AMOUNT . $prices['grandTotal'], + \PHPUnit_Framework_Assert::assertRegExp( + sprintf(self::AUTHORIZED_AMOUNT_PATTERN, $prices['grandTotal']), $actualAuthorizedAmount, 'Incorrect authorized amount value for the order #' . $orderId ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php index c46a161cc6372..90e0e7b091a11 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php @@ -6,6 +6,7 @@ namespace Magento\Sales\Test\Constraint; +use Magento\Sales\Test\Fixture\OrderInjectable; use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; use Magento\Sales\Test\Page\Adminhtml\OrderIndex; use Magento\Mtf\Constraint\AbstractConstraint; @@ -16,9 +17,9 @@ class AssertCaptureInCommentsHistory extends AbstractConstraint { /** - * Message about captured amount in order. + * Pattern of message about captured amount in order. */ - const CAPTURED_AMOUNT = 'Captured amount of $'; + const CAPTURED_AMOUNT_PATTERN = '/^Captured amount of \w*\W{1,2}%s online. Transaction ID: "[\w\-]*"/'; /** * Assert that comment about captured amount exist in Comments History section on order page in Admin. @@ -40,8 +41,8 @@ public function processAssert( $actualCapturedAmount = $salesOrderView->getOrderHistoryBlock()->getCapturedAmount(); foreach ($capturedPrices as $key => $capturedPrice) { - \PHPUnit_Framework_Assert::assertContains( - self::CAPTURED_AMOUNT . $capturedPrice, + \PHPUnit_Framework_Assert::assertRegExp( + sprintf(self::CAPTURED_AMOUNT_PATTERN, $capturedPrice), $actualCapturedAmount[$key], 'Incorrect captured amount value for the order #' . $orderId ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php index 9b43a3917aac1..cbcb725df05ff 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php @@ -6,6 +6,7 @@ namespace Magento\Sales\Test\Constraint; +use Magento\Checkout\Test\Fixture\Cart; use Magento\Sales\Test\Fixture\OrderInjectable; use Magento\Sales\Test\Page\Adminhtml\InvoiceIndex; use Magento\Sales\Test\Page\Adminhtml\SalesInvoiceView; @@ -23,6 +24,7 @@ class AssertInvoiceItems extends AbstractAssertItems * @param OrderInjectable $order * @param array $ids * @param array|null $data [optional] + * @param Cart|null $cart [optional] * @return void */ public function processAssert( @@ -30,10 +32,11 @@ public function processAssert( SalesInvoiceView $salesInvoiceView, OrderInjectable $order, array $ids, - array $data = null + array $data = null, + Cart $cart = null ) { $orderId = $order->getId(); - $productsData = $this->prepareOrderProducts($order, $data['items_data']); + $productsData = $this->prepareOrderProducts($order, $data['items_data'], $cart); foreach ($ids['invoiceIds'] as $invoiceId) { $filter = [ 'order_id' => $orderId, diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOnlineInvoiceCannotBeCreated.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOnlineInvoiceCannotBeCreated.php new file mode 100644 index 0000000000000..437dc8cc1be28 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOnlineInvoiceCannotBeCreated.php @@ -0,0 +1,59 @@ +open(); + $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); + $salesOrderView->getPageActions()->invoice(); + + \PHPUnit_Framework_Assert::assertEquals( + self::OFFLINE_INVOICE_MESSAGE, + $orderInvoiceNew->getTotalsBlock()->getCaptureOfflineMessage(), + 'Message incorrect or is not present.' + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Message that invoice can be created only offline is present."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php index 4c30d5f68d208..1de6de5061248 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php @@ -6,29 +6,29 @@ namespace Magento\Sales\Test\Constraint; -use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; use Magento\Sales\Test\Page\Adminhtml\OrderIndex; +use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; use Magento\Mtf\Constraint\AbstractConstraint; /** - * Assert that Order Grand Total is correct on order page in backend + * Assert that Order Grand Total is correct on order page in Admin. */ class AssertOrderGrandTotal extends AbstractConstraint { /** - * Assert that Order Grand Total is correct on order page in backend + * Assert that Order Grand Total is correct on order page in Admin. * * @param SalesOrderView $salesOrderView - * @param string $orderId * @param OrderIndex $salesOrder * @param array $prices + * @param string $orderId * @return void */ public function processAssert( SalesOrderView $salesOrderView, OrderIndex $salesOrder, - $orderId, - array $prices + array $prices, + $orderId ) { $salesOrder->open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); @@ -41,7 +41,7 @@ public function processAssert( } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderPaymentInformation.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderPaymentInformation.php new file mode 100644 index 0000000000000..18119ddbf95d6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderPaymentInformation.php @@ -0,0 +1,55 @@ +open(); + $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $actualPaymentInformation = $infoTab->getPaymentInfoBlock()->getData(); + + \PHPUnit_Framework_Assert::assertEmpty( + array_diff($paymentInfo, $actualPaymentInformation), + 'Payment Information missmatch with expected values.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Payment Information valid and matches with expected values.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php index 056e97c1b6262..3623de40b06f1 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php @@ -11,13 +11,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Class AssertOrderStatusIsCorrect - * Assert that status is correct on order page in backend (same with value of orderStatus variable) + * Assert that status is correct on order page in admin panel (same with value of orderStatus variable). */ class AssertOrderStatusIsCorrect extends AbstractConstraint { /** - * Assert that status is correct on order page in backend (same with value of orderStatus variable) + * Assert that status is correct on order page in admin panel (same with value of orderStatus variable). * * @param string $status * @param string $orderId @@ -37,14 +36,16 @@ public function processAssert( $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); $orderStatus = $statusToCheck == null ? $status : $statusToCheck; + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); \PHPUnit_Framework_Assert::assertEquals( - $salesOrderView->getOrderForm()->getOrderInfoBlock()->getOrderStatus(), + $infoTab->getOrderStatus(), $orderStatus ); } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php index 9cbb7b2c9ebbb..c0ce2a87fc1c3 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php @@ -16,9 +16,9 @@ class AssertRefundInCommentsHistory extends AbstractConstraint { /** - * Message about refunded amount in order. + * Pattern of message about refunded amount in order. */ - const REFUNDED_AMOUNT = 'We refunded $'; + const REFUNDED_AMOUNT_PATTERN = '/^We refunded \w*\W{1,2}%s online. Transaction ID: "[\w\-]*"/'; /** * Assert that comment about refunded amount exist in Comments History section on order page in Admin. @@ -40,8 +40,8 @@ public function processAssert( $actualRefundedAmount = $salesOrderView->getOrderHistoryBlock()->getRefundedAmount(); foreach ($refundedPrices as $key => $refundedPrice) { - \PHPUnit_Framework_Assert::assertContains( - self::REFUNDED_AMOUNT . $refundedPrice, + \PHPUnit_Framework_Assert::assertRegExp( + sprintf(self::REFUNDED_AMOUNT_PATTERN, $refundedPrice), $actualRefundedAmount[$key], 'Incorrect refunded amount value for the order #' . $orderId ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php index 89faffc8ec072..557e29a0b9830 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php @@ -11,7 +11,7 @@ use Magento\Sales\Test\Fixture\OrderInjectable; /** - * Class AssertRefundOrderStatusInCommentsHistory + * Assert that comment about refunded amount exist in Comments History section on order page in Admin. */ class AssertRefundOrderStatusInCommentsHistory extends AbstractConstraint { @@ -30,8 +30,11 @@ public function processAssert( ) { $salesOrder->open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); + + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); \PHPUnit_Framework_Assert::assertContains( - $salesOrderView->getOrderForm()->getOrderInfoBlock()->getOrderStatus(), + $infoTab->getOrderStatus(), $salesOrderView->getOrderHistoryBlock()->getStatus() ); } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php index 804c607814a3d..9c034d2ea7085 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php @@ -12,13 +12,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Class AssertReorderStatusIsCorrect - * Assert that status is correct on order page in backend + * Assert that status is correct on order page in admin panel. */ class AssertReorderStatusIsCorrect extends AbstractConstraint { /** - * Assert that status is correct on order page in backend (same with value of orderStatus variable) + * Assert that status is correct on order page in admin panel (same with value of orderStatus variable). * * @param string $previousOrderStatus * @param OrderInjectable $order @@ -35,15 +34,17 @@ public function processAssert( $salesOrder->open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); \PHPUnit_Framework_Assert::assertEquals( $previousOrderStatus, - $salesOrderView->getOrderForm()->getOrderInfoBlock()->getOrderStatus(), + $infoTab->getOrderStatus(), 'Order status is incorrect on order page in backend.' ); } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddProductsStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddProductsStep.php index 594f7098e4559..0caeb235119c8 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddProductsStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddProductsStep.php @@ -6,44 +6,55 @@ namespace Magento\Sales\Test\TestStep; +use Magento\Mtf\Fixture\FixtureFactory; use Magento\Sales\Test\Page\Adminhtml\OrderCreateIndex; use Magento\Mtf\TestStep\TestStepInterface; /** - * Class AddProductsStep - * Add Products Step + * Add Products Step. */ class AddProductsStep implements TestStepInterface { /** - * Sales order create index page + * Sales order create index page. * * @var OrderCreateIndex */ - protected $orderCreateIndex; + private $orderCreateIndex; /** - * Array products + * Array products. * * @var array */ - protected $products; + private $products; + + /** + * Fixture factory. + * + * @var FixtureFactory + */ + private $fixtureFactory; /** - * @constructor * @param OrderCreateIndex $orderCreateIndex + * @param FixtureFactory $fixtureFactory * @param array $products */ - public function __construct(OrderCreateIndex $orderCreateIndex, array $products) - { + public function __construct( + OrderCreateIndex $orderCreateIndex, + FixtureFactory $fixtureFactory, + array $products + ) { $this->orderCreateIndex = $orderCreateIndex; $this->products = $products; + $this->fixtureFactory = $fixtureFactory; } /** - * Add product to sales + * Add product to sales. * - * @return void + * @return array */ public function run() { @@ -58,5 +69,8 @@ public function run() } $createBlock->addSelectedProductsToOrder(); $createBlock->getTemplateBlock()->waitLoader(); + + $cart['data']['items'] = ['products' => $this->products]; + return ['cart' => $this->fixtureFactory->createByCode('cart', $cart)]; } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SelectPaymentMethodForOrderStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SelectPaymentMethodForOrderStep.php index c05dfc4fac2dc..fa0a62d79625e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SelectPaymentMethodForOrderStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SelectPaymentMethodForOrderStep.php @@ -6,7 +6,6 @@ namespace Magento\Sales\Test\TestStep; -use Magento\Mtf\Fixture\FixtureFactory; use Magento\Sales\Test\Page\Adminhtml\OrderCreateIndex; use Magento\Mtf\TestStep\TestStepInterface; use Magento\Payment\Test\Fixture\CreditCard; @@ -38,29 +37,22 @@ class SelectPaymentMethodForOrderStep implements TestStepInterface private $creditCard; /** - * @constructor * @param OrderCreateIndex $orderCreateIndex * @param array $payment - * @param FixtureFactory $fixtureFactory - * @param string $creditCardClass - * @param array|CreditCard|null $creditCard + * @param CreditCard|null $creditCard */ public function __construct( OrderCreateIndex $orderCreateIndex, array $payment, - FixtureFactory $fixtureFactory, - $creditCardClass = 'credit_card', - array $creditCard = null + CreditCard $creditCard = null ) { $this->orderCreateIndex = $orderCreateIndex; $this->payment = $payment; - if (isset($creditCard['dataset'])) { - $this->creditCard = $fixtureFactory->createByCode($creditCardClass, ['dataset' => $creditCard['dataset']]); - } + $this->creditCard = $creditCard; } /** - * Fill Payment data + * Fill Payment data. * * @return void */ 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 df10cccbd8213..157dfc0f77302 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 @@ -91,4 +91,19 @@ S0 + + + S1 + + + + + S1 + + + + + S1 + + diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.php index e6462e4697aa6..37aa17e95b2ff 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.php @@ -6,6 +6,7 @@ namespace Magento\Vault\Test\TestCase; use Magento\Checkout\Test\Page\CheckoutOnepage; +use Magento\Customer\Test\Fixture\Customer; use Magento\Mtf\ObjectManager; use Magento\Mtf\TestCase\Injectable; use Magento\Vault\Test\Constraint\AssertCreditCardNotPresentOnCheckout; @@ -95,7 +96,7 @@ public function test( if ($key >= 2) { // if this order will be placed via stored credit card $this->useSavedCreditCard($payment['vault']); } else { - $this->selectPaymentMethod($payment, $payment['creditCardClass'], $payment['creditCard']); + $this->selectPaymentMethod($payment, $payment['creditCard']); $this->saveCreditCard($payment, $creditCardSave); } $this->placeOrder(); @@ -105,8 +106,7 @@ public function test( for ($i = 2; $i < $paymentsCount; $i++) { $deletedCard = $this->deleteCreditCardFromMyAccount( $customer, - $payments[$i]['creditCard'], - $payments[$i]['creditCardClass'] + $payments[$i]['creditCard'] ); $this->addToCart($products); $this->proceedToCheckout(); @@ -119,9 +119,12 @@ public function test( } /** + * Setup configuration step. + * * @param $configData + * @return void */ - protected function setupConfiguration($configData) + private function setupConfiguration($configData) { $setupConfigurationStep = ObjectManager::getInstance()->create( \Magento\Config\Test\TestStep\SetupConfigurationStep::class, @@ -132,7 +135,7 @@ protected function setupConfiguration($configData) } /** - * Create products + * Create products step. * * @param string $productList * @return array @@ -149,6 +152,8 @@ protected function prepareProducts($productList) } /** + * Add to cart step. + * * @param array $products * @return void */ @@ -162,6 +167,8 @@ protected function addToCart(array $products) } /** + * Proceed to checkout step. + * * @return void */ protected function proceedToCheckout() @@ -173,7 +180,10 @@ protected function proceedToCheckout() } /** + * Create customer step. + * * @param array $customer + * @return Customer */ protected function createCustomer(array $customer) { @@ -186,8 +196,11 @@ protected function createCustomer(array $customer) } /** + * Select Checkout method step. + * * @param $checkoutMethod * @param $customer + * @return void */ protected function selectCheckoutMethod($checkoutMethod, $customer) { @@ -202,7 +215,10 @@ protected function selectCheckoutMethod($checkoutMethod, $customer) } /** + * Fill shipping address step. + * * @param array $shippingAddress + * @return void */ protected function fillShippingAddress(array $shippingAddress) { @@ -214,9 +230,10 @@ protected function fillShippingAddress(array $shippingAddress) } /** - * Add products to cart + * Add products to cart. * * @param array $shipping + * @return void */ protected function fillShippingMethod(array $shipping) { @@ -228,17 +245,18 @@ protected function fillShippingMethod(array $shipping) } /** + * Select payment method step. + * * @param array $payment - * @param $creditCardClass * @param array $creditCard + * @return void */ - protected function selectPaymentMethod(array $payment, $creditCardClass, array $creditCard) + protected function selectPaymentMethod(array $payment, array $creditCard) { $selectPaymentMethodStep = ObjectManager::getInstance()->create( \Magento\Checkout\Test\TestStep\SelectPaymentMethodStep::class, [ 'payment' => $payment, - 'creditCardClass' => $creditCardClass, 'creditCard' => $creditCard, ] ); @@ -250,6 +268,7 @@ protected function selectPaymentMethod(array $payment, $creditCardClass, array $ * * @param $payment * @param $creditCardSave + * @return void */ protected function saveCreditCard($payment, $creditCardSave) { @@ -264,6 +283,8 @@ protected function saveCreditCard($payment, $creditCardSave) } /** + * Fill billing information step. + * * @return void */ protected function fillBillingInformation() @@ -275,6 +296,8 @@ protected function fillBillingInformation() } /** + * Place order step. + * * @return void */ protected function placeOrder() @@ -286,7 +309,10 @@ protected function placeOrder() } /** + * Use saved credit card step. + * * @param $payment + * @return void */ protected function useSavedCreditCard($payment) { @@ -298,18 +324,19 @@ protected function useSavedCreditCard($payment) } /** + * Delete credit card from My Account step. + * * @param $customer * @param $creditCard - * @param $creditCardClass + * @return array */ - protected function deleteCreditCardFromMyAccount($customer, $creditCard, $creditCardClass) + protected function deleteCreditCardFromMyAccount($customer, $creditCard) { $deleteCreditCardFromMyAccountStep = ObjectManager::getInstance()->create( \Magento\Vault\Test\TestStep\DeleteCreditCardFromMyAccountStep::class, [ 'customer' => $customer, - 'creditCard' => $creditCard, - 'creditCardClass' => $creditCardClass + 'creditCard' => $creditCard ] ); $deletedCard = $deleteCreditCardFromMyAccountStep->run(); diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.xml b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.xml index 2cafc815fed1d..c6daa6ac89d58 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.xml +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.xml @@ -17,23 +17,29 @@ braintree - credit_card_braintree - visa_braintree + visa_default + + braintree + payflowpro - credit_card visa_alt + + payment + braintree - credit_card_braintree - visa_braintree + visa_default + + braintree + braintree_cc_vault @@ -41,9 +47,11 @@ payflowpro - credit_card visa_alt + + payment + payflowpro_cc_vault diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteCreditCardFromMyAccountStep.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteCreditCardFromMyAccountStep.php index c3cb46347dd8c..f751108d28b16 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteCreditCardFromMyAccountStep.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteCreditCardFromMyAccountStep.php @@ -7,86 +7,87 @@ use Magento\Customer\Test\Fixture\Customer; use Magento\Customer\Test\Page\CustomerAccountIndex; -use Magento\Mtf\Fixture\FixtureFactory; -use Magento\Mtf\Fixture\InjectableFixture; use Magento\Mtf\ObjectManager; use Magento\Mtf\TestStep\TestStepInterface; +use Magento\Payment\Test\Fixture\CreditCard; use Magento\Vault\Test\Constraint\AssertStoredPaymentDeletedMessage; use Magento\Vault\Test\Page\StoredPaymentMethods; /** + * Delete credit card from My Account step. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DeleteCreditCardFromMyAccountStep implements TestStepInterface { /** + * Customer Fixture. + * * @var Customer */ private $customer; /** + * Object manager. + * * @var ObjectManager */ private $objectManager; /** + * Customer account index page. + * * @var CustomerAccountIndex */ private $customerAccountIndex; /** - * @var FixtureFactory - */ - private $fixtureFactory; - - /** - * @var \Magento\Mtf\Fixture\FixtureInterface + * Credit card fixture. + * + * @var CreditCard */ private $creditCard; /** + * Assert message of success deletion of stored payment method. + * * @var AssertStoredPaymentDeletedMessage */ private $assertStoredPaymentDeletedMessage; /** + * Stored payment methods page. + * * @var StoredPaymentMethods */ private $storedPaymentMethodsPage; /** - * DeleteCreditCardFromMyAccountStep constructor. - * * @param StoredPaymentMethods $storedPaymentMethodsPage * @param Customer $customer * @param ObjectManager $objectManager * @param CustomerAccountIndex $customerAccountIndex - * @param FixtureFactory $fixtureFactory * @param AssertStoredPaymentDeletedMessage $assertStoredPaymentDeletedMessage - * @param array $creditCard - * @param string $creditCardClass + * @param CreditCard $creditCard */ public function __construct( StoredPaymentMethods $storedPaymentMethodsPage, Customer $customer, ObjectManager $objectManager, CustomerAccountIndex $customerAccountIndex, - FixtureFactory $fixtureFactory, AssertStoredPaymentDeletedMessage $assertStoredPaymentDeletedMessage, - array $creditCard, - $creditCardClass = 'credit_card' + CreditCard $creditCard ) { $this->storedPaymentMethodsPage = $storedPaymentMethodsPage; $this->customer = $customer; $this->objectManager = $objectManager; $this->customerAccountIndex = $customerAccountIndex; - $this->fixtureFactory = $fixtureFactory; $this->assertStoredPaymentDeletedMessage = $assertStoredPaymentDeletedMessage; - $this->creditCard = $fixtureFactory->createByCode($creditCardClass, ['dataset' => $creditCard['dataset']]); + $this->creditCard = $creditCard; } /** - * @inheritdoc + * Run Delete credit card from My Account step. * * @return array */ diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/SaveCreditCardOnBackendStep.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/SaveCreditCardOnBackendStep.php index 24d1c76c01621..3a378633bd403 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/SaveCreditCardOnBackendStep.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/SaveCreditCardOnBackendStep.php @@ -5,13 +5,12 @@ */ namespace Magento\Vault\Test\TestStep; -use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\TestStep\TestStepInterface; use Magento\Payment\Test\Fixture\CreditCard; use Magento\Sales\Test\Page\Adminhtml\OrderCreateIndex; /** - * Class SaveCreditCardOnBackendStep + * Save credit card during order placement from Admin. */ class SaveCreditCardOnBackendStep implements TestStepInterface { @@ -44,22 +43,18 @@ class SaveCreditCardOnBackendStep implements TestStepInterface /** * @param OrderCreateIndex $orderCreateIndex * @param array $payment - * @param FixtureFactory $fixtureFactory - * @param $creditCardClass - * @param array $creditCard + * @param CreditCard $creditCard * @param string $creditCardSave */ public function __construct( OrderCreateIndex $orderCreateIndex, array $payment, - FixtureFactory $fixtureFactory, - $creditCardClass, - array $creditCard, + CreditCard $creditCard, $creditCardSave = 'No' ) { $this->orderCreatePage = $orderCreateIndex; $this->payment = $payment; - $this->creditCard = $fixtureFactory->createByCode($creditCardClass, ['dataset' => $creditCard['dataset']]); + $this->creditCard = $creditCard; $this->creditCardSave = $creditCardSave; } diff --git a/dev/tests/functional/utils/generate.php b/dev/tests/functional/utils/generate.php index e374dae4ccfc2..d53ac44451376 100644 --- a/dev/tests/functional/utils/generate.php +++ b/dev/tests/functional/utils/generate.php @@ -3,12 +3,17 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Filesystem; + require_once dirname(__FILE__) . '/' . 'bootstrap.php'; // Generate fixtures $magentoObjectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER); $magentoObjectManager = $magentoObjectManagerFactory->create($_SERVER); - +// Remove previously generated static classes +$fs = $magentoObjectManager->create(Filesystem::class); +$fs->getDirectoryWrite(DirectoryList::ROOT)->delete('dev/tests/functional/generated/'); // Generate factories for old end-to-end tests $magentoObjectManager->create(\Magento\Mtf\Util\Generate\Factory::class)->launch(); diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/MassactionTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/MassactionTest.php index 1bbf40ca6dc72..8c0a7dd201d62 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/MassactionTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/MassactionTest.php @@ -3,11 +3,10 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ - -// @codingStandardsIgnoreFile - namespace Magento\Backend\Block\Widget\Grid; +use Magento\TestFramework\App\State; + /** * @magentoAppArea adminhtml * @magentoComponentsDir Magento/Backend/Block/_files/design @@ -25,18 +24,43 @@ class MassactionTest extends \PHPUnit_Framework_TestCase */ protected $_layout; + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $mageMode; + protected function setUp() { - $this->markTestIncomplete('MAGETWO-6406'); - parent::setUp(); - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $this->mageMode = $this->objectManager->get(State::class)->getMode(); + /** @var \Magento\Theme\Model\Theme\Registration $registration */ - $registration = $objectManager->get(\Magento\Theme\Model\Theme\Registration::class); + $registration = $this->objectManager->get(\Magento\Theme\Model\Theme\Registration::class); $registration->register(); - $objectManager->get(\Magento\Framework\View\DesignInterface::class)->setDesignTheme('BackendTest/test_default'); - $this->_layout = $objectManager->create( + $this->objectManager->get(\Magento\Framework\View\DesignInterface::class) + ->setDesignTheme('BackendTest/test_default'); + } + + protected function tearDown() + { + $this->objectManager->get(State::class)->setMode($this->mageMode); + } + + /** + * @param string $mageMode + */ + private function loadLayout($mageMode = State::MODE_DEVELOPER) + { + $this->objectManager->get(State::class)->setMode($mageMode); + $this->_layout = $this->objectManager->create( \Magento\Framework\View\LayoutInterface::class, ['area' => 'adminhtml'] ); @@ -48,20 +72,14 @@ protected function setUp() $this->assertNotFalse($this->_block, 'Could not load the block for testing'); } - /** - * @covers \Magento\Backend\Block\Widget\Grid\Massaction::getItems - * @covers \Magento\Backend\Block\Widget\Grid\Massaction::getCount - * @covers \Magento\Backend\Block\Widget\Grid\Massaction::getItemsJson - * @covers \Magento\Backend\Block\Widget\Grid\Massaction::isAvailable - */ public function testMassactionDefaultValues() { + $this->loadLayout(); + /** @var $blockEmpty \Magento\Backend\Block\Widget\Grid\Massaction */ - $blockEmpty = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\View\LayoutInterface::class - )->createBlock( - \Magento\Backend\Block\Widget\Grid\Massaction::class - ); + $blockEmpty = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Framework\View\LayoutInterface::class) + ->createBlock(\Magento\Backend\Block\Widget\Grid\Massaction::class); $this->assertEmpty($blockEmpty->getItems()); $this->assertEquals(0, $blockEmpty->getCount()); $this->assertSame('[]', $blockEmpty->getItemsJson()); @@ -71,6 +89,8 @@ public function testMassactionDefaultValues() public function testGetJavaScript() { + $this->loadLayout(); + $javascript = $this->_block->getJavaScript(); $expectedItemFirst = '#"option_id1":{"label":"Option One",' . @@ -86,6 +106,8 @@ public function testGetJavaScript() public function testGetJavaScriptWithAddedItem() { + $this->loadLayout(); + $input = [ 'id' => 'option_id3', 'label' => 'Option Three', @@ -100,20 +122,49 @@ public function testGetJavaScriptWithAddedItem() $this->assertRegExp($expected, $this->_block->getJavaScript()); } - public function testGetCount() + /** + * @param string $mageMode + * @param int $expectedCount + * @dataProvider getCountDataProvider + */ + public function testGetCount($mageMode, $expectedCount) { - $this->assertEquals(2, $this->_block->getCount()); + $this->loadLayout($mageMode); + $this->assertEquals($expectedCount, $this->_block->getCount()); + } + + /** + * @return array + */ + public function getCountDataProvider() + { + return [ + [ + 'mageMode' => State::MODE_DEVELOPER, + 'expectedCount' => 3, + ], + [ + 'mageMode' => State::MODE_DEFAULT, + 'expectedCount' => 3, + ], + [ + 'mageMode' => State::MODE_PRODUCTION, + 'expectedCount' => 2, + ], + ]; } /** - * @param $itemId - * @param $expectedItem + * @param string $itemId + * @param array $expectedItem * @dataProvider getItemsDataProvider */ public function testGetItems($itemId, $expectedItem) { + $this->loadLayout(); + $items = $this->_block->getItems(); - $this->assertCount(2, $items); + $this->assertCount(3, $items); $this->assertArrayHasKey($itemId, $items); $actualItem = $items[$itemId]; @@ -149,19 +200,29 @@ public function getItemsDataProvider() 'selected' => false, 'blockname' => '' ] + ], + [ + 'option_id3', + [ + 'id' => 'option_id3', + 'label' => 'Option Three', + 'url' => '#http:\/\/localhost\/index\.php\/(?:key\/([\w\d]+)\/)?#', + 'selected' => false, + 'blockname' => '' + ] ] ]; } public function testGridContainsMassactionColumn() { + $this->loadLayout(); $this->_layout->getBlock('admin.test.grid')->toHtml(); - $gridMassactionColumn = $this->_layout->getBlock( - 'admin.test.grid' - )->getColumnSet()->getChildBlock( - 'massaction' - ); + $gridMassactionColumn = $this->_layout->getBlock('admin.test.grid') + ->getColumnSet() + ->getChildBlock('massaction'); + $this->assertNotNull($gridMassactionColumn, 'Massaction column does not exist in the grid column set'); $this->assertInstanceOf( \Magento\Backend\Block\Widget\Grid\Column::class, diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/Magento_Backend/layout/layout_test_grid_handle.xml b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/Magento_Backend/layout/layout_test_grid_handle.xml index 5f9a80a5a3dbd..c072532a1c27c 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/Magento_Backend/layout/layout_test_grid_handle.xml +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/Magento_Backend/layout/layout_test_grid_handle.xml @@ -6,60 +6,68 @@ */ --> - + - Magento\Framework\Data\Collection + Magento\Framework\Data\Collection - - + + -
Product name 1
- product_name - text + Product name 1 + product_name + product_name + text
- + -
User Description
- description - text + User Description + description + description + text
- + -
Qty
- qty - number - 60px + Qty + qty + qty + number + 60
- + -
Date Added
- added_at - 1 - date + Date Added + added_at + added_at + date + 1
- + - test_id - test_id - test - 1 - - - - */*/option1 - Test - - - - */*/option2 - Are you sure? - - + test_id + test_id + 1 + + + Option One + */*/option1 + Test + + + Option Two + */*/option2 + Are you sure? + + + Option Three + */*/option3 + Magento\Backend\Block\Cache\Grid\Massaction\ProductionModeVisibilityChecker + + diff --git a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/MassActionTest.php b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/MassActionTest.php index e9fbb76f513d5..a1034643ae3dc 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/MassActionTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/MassActionTest.php @@ -3,13 +3,13 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Backend\Controller\Adminhtml\Cache; use Magento\Framework\App\Cache\State; use Magento\TestFramework\Helper\Bootstrap; use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\TestFramework\App\State as AppState; class MassActionTest extends \Magento\TestFramework\TestCase\AbstractBackendController { @@ -20,6 +20,11 @@ class MassActionTest extends \Magento\TestFramework\TestCase\AbstractBackendCont */ private static $typesConfig; + /** + * @var string + */ + private $mageState; + public static function setUpBeforeClass() { /** @var \Magento\Framework\App\DeploymentConfig $config */ @@ -27,8 +32,15 @@ public static function setUpBeforeClass() self::$typesConfig = $config->get(State::CACHE_KEY); } + protected function setUp() + { + parent::setUp(); + $this->mageState = Bootstrap::getObjectManager()->get(AppState::class)->getMode(); + } + protected function tearDown() { + Bootstrap::getObjectManager()->get(AppState::class)->setMode($this->mageState); /** @var $cacheState \Magento\Framework\App\Cache\StateInterface */ $cacheState = Bootstrap::getObjectManager()->get(\Magento\Framework\App\Cache\StateInterface::class); foreach (self::$typesConfig as $type => $value) { @@ -42,7 +54,7 @@ protected function tearDown() * @dataProvider massActionsDataProvider * @param array $typesToEnable */ - public function testMassEnableAction($typesToEnable = []) + public function testMassEnableActionDeveloperMode($typesToEnable = []) { $this->setAll(false); @@ -53,16 +65,33 @@ public function testMassEnableAction($typesToEnable = []) if (in_array($cacheType, $typesToEnable)) { $this->assertEquals(1, $cacheState, "Type '{$cacheType}' has not been enabled"); } else { - $this->assertEquals(0, $cacheState, "Type '{$cacheType}' has not been enabled"); + $this->assertEquals(0, $cacheState, "Type '{$cacheType}' must remain disabled"); } } } + /** + * @dataProvider massActionsDataProvider + * @param array $typesToEnable + */ + public function testMassEnableActionProductionMode($typesToEnable = []) + { + Bootstrap::getObjectManager()->get(AppState::class)->setMode(AppState::MODE_PRODUCTION); + $this->setAll(false); + + $this->getRequest()->setParams(['types' => $typesToEnable]); + $this->dispatch('backend/admin/cache/massEnable'); + + foreach ($this->getCacheStates() as $cacheType => $cacheState) { + $this->assertEquals(0, $cacheState, "Type '{$cacheType}' must remain disabled"); + } + } + /** * @dataProvider massActionsDataProvider * @param array $typesToDisable */ - public function testMassDisableAction($typesToDisable = []) + public function testMassDisableActionDeveloperMode($typesToDisable = []) { $this->setAll(true); @@ -78,6 +107,23 @@ public function testMassDisableAction($typesToDisable = []) } } + /** + * @dataProvider massActionsDataProvider + * @param array $typesToDisable + */ + public function testMassDisableActionProductionMode($typesToDisable = []) + { + Bootstrap::getObjectManager()->get(AppState::class)->setMode(AppState::MODE_PRODUCTION); + $this->setAll(true); + + $this->getRequest()->setParams(['types' => $typesToDisable]); + $this->dispatch('backend/admin/cache/massDisable'); + + foreach ($this->getCacheStates() as $cacheType => $cacheState) { + $this->assertEquals(1, $cacheState, "Type '{$cacheType}' must remain enabled"); + } + } + /** * Retrieve cache states (enabled/disabled) information * diff --git a/dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php new file mode 100644 index 0000000000000..1e2b6aacc9314 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php @@ -0,0 +1,103 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->model = $this->objectManager->get(EnvironmentPlaceholder::class); + $this->env = $_ENV; + } + + public function testProcess() + { + $_ENV = array_merge( + $_ENV, + [ + 'CONFIG__DEFAULT__WEB__UNSECURE__BASE_URL' => 'http://expected.local', + 'CONFIG__TEST__TEST__DESIGN__HEADER__WELCOME' => 'Expected header', + 'TEST__TEST__WEB__SECURE__BASE_URL' => 'http://wrong_pattern.local', + 'CONFIG__DEFAULT__GENERAL__REGION__DISPLAY_ALL' => 1 + ] + ); + $expected = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://expected.local' + ], + 'secure' => [ + 'base_url' => 'https://original.local' + ] + ], + 'general' => [ + 'region' => [ + 'display_all' => 1 + ], + ], + ], + 'test' => [ + 'test' => [ + 'design' => [ + 'header' => [ + 'welcome' => 'Expected header' + ] + ], + ], + ] + ]; + $config = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://original.local', + ], + 'secure' => [ + 'base_url' => 'https://original.local' + ] + ] + ], + 'test' => [ + 'test' => [ + 'design' => [ + 'header' => [ + 'welcome' => 'Original header' + ] + ], + ], + ] + ]; + + $this->assertSame( + $expected, + $this->model->process($config) + ); + } + + protected function tearDown() + { + $_ENV = $this->env; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php index a229b64bb7dd1..170d186e20af8 100644 --- a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php +++ b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php @@ -7,7 +7,6 @@ use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\App\ObjectManager; use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Filesystem\DriverPool; use Magento\Framework\ObjectManagerInterface; @@ -18,37 +17,73 @@ class ApplicationDumpCommandTest extends \PHPUnit_Framework_TestCase { /** - * @var ApplicationDumpCommand + * @var ObjectManagerInterface */ - private $command; + private $objectManager; /** - * @var ObjectManagerInterface + * @var DeploymentConfig\Reader */ - private $objectManager; + private $reader; public function setUp() { - $this->command = Bootstrap::getObjectManager()->get(ApplicationDumpCommand::class); $this->objectManager = Bootstrap::getObjectManager(); + $this->reader = $this->objectManager->get(DeploymentConfig\Reader::class); } + /** + * @magentoDbIsolation enabled + * @magentoDataFixture Magento/Deploy/_files/config_data.php + */ public function testExecute() { - $inputMock = $this->getMock(InputInterface::class); + $this->objectManager->configure([ + \Magento\Config\Model\Config\Export\ExcludeList::class => [ + 'arguments' => [ + 'configs' => [ + 'web/test/test_value_1' => '', + 'web/test/test_value_2' => '', + 'web/test/test_sensitive' => '1', + ], + ], + ], + ]); + + $comment = 'The configuration file doesn\'t contain sensitive data for security reasons. ' + . 'Sensitive data can be stored in the following environment variables:' + . "\nCONFIG__DEFAULT__WEB__TEST__TEST_SENSITIVE for web/test/test_sensitive"; $outputMock = $this->getMock(OutputInterface::class); - $outputMock->expects($this->once()) + $outputMock->expects($this->at(0)) + ->method('writeln') + ->with(['system' => $comment]); + $outputMock->expects($this->at(1)) ->method('writeln') ->with('Done.'); - $this->assertEquals(0, $this->command->run($inputMock, $outputMock)); + + /** @var ApplicationDumpCommand command */ + $command = $this->objectManager->create(ApplicationDumpCommand::class); + $command->run($this->getMock(InputInterface::class), $outputMock); + + $config = $this->reader->loadConfigFile(ConfigFilePool::APP_CONFIG, $this->getFileName()); + + $this->assertArrayHasKey( + 'test_value_1', + $config['system']['default']['web']['test'] + ); + $this->assertArrayHasKey( + 'test_value_2', + $config['system']['default']['web']['test'] + ); + $this->assertArrayNotHasKey( + 'test_sensitive', + $config['system']['default']['web']['test'] + ); } public function tearDown() { - /** @var ConfigFilePool $configFilePool */ - $configFilePool = $this->objectManager->get(ConfigFilePool::class); - $filePool = $configFilePool->getInitialFilePools(); - $file = $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG]; + $file = $this->getFileName(); /** @var DirectoryList $dirList */ $dirList = $this->objectManager->get(DirectoryList::class); $path = $dirList->getPath(DirectoryList::CONFIG); @@ -61,4 +96,16 @@ public function tearDown() $deploymentConfig = $this->objectManager->get(DeploymentConfig::class); $deploymentConfig->resetData(); } + + /** + * @return string + */ + private function getFileName() + { + /** @var ConfigFilePool $configFilePool */ + $configFilePool = $this->objectManager->get(ConfigFilePool::class); + $filePool = $configFilePool->getInitialFilePools(); + + return $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php b/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php new file mode 100644 index 0000000000000..bd8e69262e1e0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php @@ -0,0 +1,33 @@ + [ + '' => [ + 'web/test/test_value_1' => 'http://local2.test/', + 'web/test/test_value_2' => 5, + 'web/test/test_sensitive' => 10, + ] + ], +]; + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$configFactory = $objectManager->create(\Magento\Config\Model\Config\Factory::class); + +foreach ($configData as $scope => $data) { + foreach ($data as $scopeCode => $scopeData) { + foreach ($scopeData as $path => $value) { + $config = $configFactory->create(); + $config->setCope($scope); + + if ($scopeCode) { + $config->setScopeCode($scopeCode); + } + + $config->setDataByPath($path, $value); + $config->save(); + } + } +} diff --git a/lib/internal/Magento/Framework/App/Config/CommentInterface.php b/lib/internal/Magento/Framework/App/Config/CommentInterface.php new file mode 100644 index 0000000000000..902d63668f368 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/CommentInterface.php @@ -0,0 +1,21 @@ +processors = $processors; + } + + /** + * @inheritdoc + */ + public function process(array $config) + { + /** @var PreProcessorInterface $processor */ + foreach ($this->processors as $processor) { + $config = $processor->process($config); + } + + return $config; + } +} diff --git a/lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php b/lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php new file mode 100644 index 0000000000000..1be0783d7f7de --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php @@ -0,0 +1,20 @@ +isExists($path . '/' . $initialFiles[$fileKey])) { $fileBuffer = include $path . '/' . $initialFiles[$fileKey]; - $result = array_replace_recursive($result, $fileBuffer); + if (is_array($fileBuffer)) { + $result = array_replace_recursive($result, $fileBuffer); + } } } } @@ -159,6 +161,13 @@ public function loadConfigFile($fileKey, $pathConfig, $ignoreInitialConfigFiles $result = array_replace_recursive($result, $fileBuffer); } + if ($fileDriver->isExists($path . '/' . $pathConfig)) { + $configResult = include $path . '/' . $pathConfig; + if (is_array($configResult)) { + $result = array_replace_recursive($result, $configResult); + } + } + return $result; } diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php index 6cead0305a6c6..2d8e7a14aaf55 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php @@ -94,10 +94,11 @@ public function checkIfWritable() * @param array $data * @param bool $override * @param string $pool + * @param array $comments * @return void * @throws FileSystemException */ - public function saveConfig(array $data, $override = false, $pool = null) + public function saveConfig(array $data, $override = false, $pool = null, array $comments = []) { foreach ($data as $fileKey => $config) { $paths = $pool ? $this->configFilePool->getPathsByPool($pool) : $this->configFilePool->getPaths(); @@ -112,7 +113,7 @@ public function saveConfig(array $data, $override = false, $pool = null) } } - $contents = $this->formatter->format($config); + $contents = $this->formatter->format($config, $comments); try { $writeFilePath = $paths[$fileKey]; $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile($writeFilePath, $contents); diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php index 24e31074501f3..640bcb61d2031 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php @@ -12,7 +12,8 @@ interface FormatterInterface * Format deployment configuration * * @param array $data + * @param array $comments * @return string */ - public function format($data); + public function format($data, array $comments = []); } diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php index 1ab99358cef1a..91bd906e3ca4d 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php @@ -12,10 +12,26 @@ class PhpFormatter implements FormatterInterface { /** + * Format deployment configuration. + * If $comments is present, each item will be added + * as comment to the corresponding section + * * {@inheritdoc} */ - public function format($data) + public function format($data, array $comments = []) { + if (!empty($comments) && is_array($data)) { + $elements = []; + foreach ($data as $key => $value) { + $comment = ' '; + if (!empty($comments[$key])) { + $comment = " /**\n * " . str_replace("\n", "\n * ", var_export($comments[$key], true)) . "\n */\n"; + } + $space = is_array($value) ? " \n" : ' '; + $elements[] = $comment . var_export($key, true) . ' =>' . $space . var_export($value, true); + } + return "preProcessorMock = $this->getMockBuilder(PreProcessorInterface::class) + ->getMockForAbstractClass(); + + $this->model = new PreProcessorComposite([$this->preProcessorMock]); + } + + public function testProcess() + { + $this->preProcessorMock->expects($this->once()) + ->method('process') + ->with(['test' => 'data']) + ->willReturn(['test' => 'data2']); + + $this->assertSame(['test' => 'data2'], $this->model->process(['test' => 'data'])); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php index a9b5bc04a1276..2ab8b209272f1 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php @@ -10,10 +10,128 @@ class PhpFormatterTest extends \PHPUnit_Framework_TestCase { - public function testFormat() + /** + * @dataProvider formatWithCommentDataProvider + * @param string|array $data + * @param array $comments + * @param string $expectedResult + */ + public function testFormat($data, $comments, $expectedResult) { $formatter = new PhpFormatter(); - $data = 'test'; - $this->assertEquals("format($data)); + $this->assertEquals($expectedResult, $formatter->format($data, $comments)); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function formatWithCommentDataProvider() + { + $array = [ + 'ns1' => [ + 's1' => [ + 's11', + 's12' + ], + 's2' => [ + 's21', + 's22' + ], + ], + 'ns2' => [ + 's1' => [ + 's11' + ], + ], + 'ns3' => 'just text', + 'ns4' => 'just text' + ]; + $comments1 = ['ns2' => 'comment for namespace 2']; + $comments2 = [ + 'ns1' => 'comment for namespace 1', + 'ns2' => "comment for namespace 2.\nNext comment for namespace 2", + 'ns3' => 'comment for namespace 3', + 'ns4' => 'comment for namespace 4', + 'ns5' => 'comment for unexisted namespace 5', + ]; + $expectedResult1 = << + array ( + 's1' => + array ( + 0 => 's11', + 1 => 's12', + ), + 's2' => + array ( + 0 => 's21', + 1 => 's22', + ), + ), + /** + * 'comment for namespace 2' + */ + 'ns2' => + array ( + 's1' => + array ( + 0 => 's11', + ), + ), + 'ns3' => 'just text', + 'ns4' => 'just text' +); + +TEXT; + $expectedResult2 = << + array ( + 's1' => + array ( + 0 => 's11', + 1 => 's12', + ), + 's2' => + array ( + 0 => 's21', + 1 => 's22', + ), + ), + /** + * 'comment for namespace 2. + * Next comment for namespace 2' + */ + 'ns2' => + array ( + 's1' => + array ( + 0 => 's11', + ), + ), + /** + * 'comment for namespace 3' + */ + 'ns3' => 'just text', + /** + * 'comment for namespace 4' + */ + 'ns4' => 'just text' +); + +TEXT; + return [ + ['string', [], "shell = $shell; + $this->filesystem = $filesystem; + } + + /** + * {@inheritdoc} + */ + public function getTasks() + { + $this->checkSupportedOs(); + $content = $this->getCrontabContent(); + $pattern = '!(' . self::TASKS_BLOCK_START . ')(.*?)(' . self::TASKS_BLOCK_END . ')!s'; + + if (preg_match($pattern, $content, $matches)) { + $tasks = trim($matches[2], PHP_EOL); + $tasks = explode(PHP_EOL, $tasks); + return $tasks; + } + + return []; + } + + /** + * {@inheritdoc} + */ + public function saveTasks(array $tasks) + { + $this->checkSupportedOs(); + $baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath(); + $logDir = $this->filesystem->getDirectoryRead(DirectoryList::LOG)->getAbsolutePath(); + + if (!$tasks) { + throw new LocalizedException(new Phrase('List of tasks is empty')); + } + + foreach ($tasks as $key => $task) { + if (empty($task['expression'])) { + $tasks[$key]['expression'] = '* * * * *'; + } + + if (empty($task['command'])) { + throw new LocalizedException(new Phrase('Command should not be empty')); + } + + $tasks[$key]['command'] = str_replace( + ['{magentoRoot}', '{magentoLog}'], + [$baseDir, $logDir], + $task['command'] + ); + } + + $content = $this->getCrontabContent(); + $content = $this->cleanMagentoSection($content); + $content = $this->generateSection($content, $tasks); + + $this->save($content); + } + + /** + * {@inheritdoc} + * @throws LocalizedException + */ + public function removeTasks() + { + $this->checkSupportedOs(); + $content = $this->getCrontabContent(); + $content = $this->cleanMagentoSection($content); + $this->save($content); + } + + /** + * Generate Magento Tasks Section + * + * @param string $content + * @param array $tasks + * @return string + */ + private function generateSection($content, $tasks = []) + { + if ($tasks) { + $content .= self::TASKS_BLOCK_START . PHP_EOL; + foreach ($tasks as $task) { + $content .= $task['expression'] . ' ' . PHP_BINARY . ' '. $task['command'] . PHP_EOL; + } + $content .= self::TASKS_BLOCK_END . PHP_EOL; + } + + return $content; + } + + /** + * Clean Magento Tasks Section in crontab content + * + * @param string $content + * @return string + */ + private function cleanMagentoSection($content) + { + $content = preg_replace( + '!' . preg_quote(self::TASKS_BLOCK_START) . '.*?' . preg_quote(self::TASKS_BLOCK_END . PHP_EOL) . '!s', + '', + $content + ); + + return $content; + } + + /** + * Get crontab content without Magento Tasks Section + * + * In case of some exceptions the empty content is returned + * + * @return string + */ + private function getCrontabContent() + { + try { + $content = (string)$this->shell->execute('crontab -l'); + } catch (LocalizedException $e) { + return ''; + } + + return $content; + } + + /** + * Save crontab + * + * @param string $content + * @return void + * @throws LocalizedException + */ + private function save($content) + { + $content = str_replace('%', '%%', $content); + + try { + $this->shell->execute('echo "' . $content . '" | crontab -'); + } catch (LocalizedException $e) { + throw new LocalizedException( + new Phrase('Error during saving of crontab: %1', [$e->getPrevious()->getMessage()]), + $e + ); + } + } + + /** + * Check that OS is supported + * + * If OS is not supported then no possibility to work with crontab + * + * @return void + * @throws LocalizedException + */ + private function checkSupportedOs() + { + if (stripos(PHP_OS, 'WIN') === 0) { + throw new LocalizedException( + new Phrase('Your operation system is not supported to work with this command') + ); + } + } +} diff --git a/lib/internal/Magento/Framework/Crontab/CrontabManagerInterface.php b/lib/internal/Magento/Framework/Crontab/CrontabManagerInterface.php new file mode 100644 index 0000000000000..c00ab41d8b873 --- /dev/null +++ b/lib/internal/Magento/Framework/Crontab/CrontabManagerInterface.php @@ -0,0 +1,43 @@ +tasks = $tasks; + } + + /** + * {@inheritdoc} + */ + public function getTasks() + { + return $this->tasks; + } +} diff --git a/lib/internal/Magento/Framework/Crontab/TasksProviderInterface.php b/lib/internal/Magento/Framework/Crontab/TasksProviderInterface.php new file mode 100644 index 0000000000000..bb02c30797be4 --- /dev/null +++ b/lib/internal/Magento/Framework/Crontab/TasksProviderInterface.php @@ -0,0 +1,16 @@ +shellMock = $this->getMockBuilder(ShellInterface::class) + ->getMockForAbstractClass(); + $this->filesystemMock = $this->getMockBuilder(Filesystem::class) + ->disableOriginalClone() + ->disableOriginalConstructor() + ->getMock(); + + $this->crontabManager = new CrontabManager($this->shellMock, $this->filesystemMock); + } + + /** + * @return void + */ + public function testGetTasksNoCrontab() + { + $exception = new \Exception('crontab: no crontab for user'); + $localizedException = new LocalizedException(new Phrase('Some error'), $exception); + + $this->shellMock->expects($this->once()) + ->method('execute') + ->with('crontab -l', []) + ->willThrowException($localizedException); + + $this->assertEquals([], $this->crontabManager->getTasks()); + } + + /** + * @param string $content + * @param array $tasks + * @return void + * @dataProvider getTasksDataProvider + */ + public function testGetTasks($content, $tasks) + { + $this->shellMock->expects($this->once()) + ->method('execute') + ->with('crontab -l', []) + ->willReturn($content); + + $this->assertEquals($tasks, $this->crontabManager->getTasks()); + } + + /** + * @return array + */ + public function getTasksDataProvider() + { + return [ + [ + 'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + 'tasks' => ['* * * * * /bin/php /var/www/magento/bin/magento cron:run'], + ], + [ + 'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + 'tasks' => [ + '* * * * * /bin/php /var/www/magento/bin/magento cron:run', + '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run', + ], + ], + [ + 'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL, + 'tasks' => [], + ], + [ + 'content' => '', + 'tasks' => [], + ], + ]; + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Shell error + */ + public function testRemoveTasksWithException() + { + $exception = new \Exception('Shell error'); + $localizedException = new LocalizedException(new Phrase('Some error'), $exception); + + $this->shellMock->expects($this->at(0)) + ->method('execute') + ->with('crontab -l', []) + ->willReturn(''); + + $this->shellMock->expects($this->at(1)) + ->method('execute') + ->with('echo "" | crontab -', []) + ->willThrowException($localizedException); + + $this->crontabManager->removeTasks(); + } + + /** + * @param string $contentBefore + * @param string $contentAfter + * @return void + * @dataProvider removeTasksDataProvider + */ + public function testRemoveTasks($contentBefore, $contentAfter) + { + $this->shellMock->expects($this->at(0)) + ->method('execute') + ->with('crontab -l', []) + ->willReturn($contentBefore); + + $this->shellMock->expects($this->at(1)) + ->method('execute') + ->with('echo "' . $contentAfter . '" | crontab -', []); + + $this->crontabManager->removeTasks(); + } + + /** + * @return array + */ + public function removeTasksDataProvider() + { + return [ + [ + 'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + 'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + ], + [ + 'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + 'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + ], + [ + 'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL, + 'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + ], + [ + 'contentBefore' => '', + 'contentAfter' => '' + ], + ]; + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage List of tasks is empty + */ + public function testSaveTasksWithEmptyTasksList() + { + $baseDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $baseDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/'); + $logDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $logDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/var/log/'); + + $this->filesystemMock->expects($this->any()) + ->method('getDirectoryRead') + ->willReturnMap([ + [DirectoryList::ROOT, DriverPool::FILE, $baseDirMock], + [DirectoryList::LOG, DriverPool::FILE, $logDirMock], + ]); + + $this->crontabManager->saveTasks([]); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Command should not be empty + */ + public function testSaveTasksWithoutCommand() + { + $baseDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $baseDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/'); + $logDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $logDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/var/log/'); + + $this->filesystemMock->expects($this->any()) + ->method('getDirectoryRead') + ->willReturnMap([ + [DirectoryList::ROOT, DriverPool::FILE, $baseDirMock], + [DirectoryList::LOG, DriverPool::FILE, $logDirMock], + ]); + + $this->crontabManager->saveTasks([ + 'myCron' => ['expression' => '* * * * *'] + ]); + } + + /** + * @param array $tasks + * @param string $content + * @param string $contentToSave + * @return void + * @dataProvider saveTasksDataProvider + */ + public function testSaveTasks($tasks, $content, $contentToSave) + { + $baseDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $baseDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/'); + $logDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $logDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/var/log/'); + + $this->filesystemMock->expects($this->any()) + ->method('getDirectoryRead') + ->willReturnMap([ + [DirectoryList::ROOT, DriverPool::FILE, $baseDirMock], + [DirectoryList::LOG, DriverPool::FILE, $logDirMock], + ]); + + $this->shellMock->expects($this->at(0)) + ->method('execute') + ->with('crontab -l', []) + ->willReturn($content); + + $this->shellMock->expects($this->at(1)) + ->method('execute') + ->with('echo "' . $contentToSave . '" | crontab -', []); + + $this->crontabManager->saveTasks($tasks); + } + + /** + * @return array + */ + public function saveTasksDataProvider() + { + $content = '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL; + + return [ + [ + 'tasks' => [ + ['expression' => '* * * * *', 'command' => 'run.php'] + ], + 'content' => $content, + 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * ' . PHP_BINARY . ' run.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + ], + [ + 'tasks' => [ + ['expression' => '1 2 3 4 5', 'command' => 'run.php'] + ], + 'content' => $content, + 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '1 2 3 4 5 ' . PHP_BINARY . ' run.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + ], + [ + 'tasks' => [ + ['command' => '{magentoRoot}run.php >> {magentoLog}cron.log'] + ], + 'content' => $content, + 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * ' . PHP_BINARY . ' /var/www/magento2/run.php >>' + . ' /var/www/magento2/var/log/cron.log' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + ], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Crontab/Test/Unit/TasksProviderTest.php b/lib/internal/Magento/Framework/Crontab/Test/Unit/TasksProviderTest.php new file mode 100644 index 0000000000000..80be47cda5ef4 --- /dev/null +++ b/lib/internal/Magento/Framework/Crontab/Test/Unit/TasksProviderTest.php @@ -0,0 +1,34 @@ +assertSame([], $tasksProvider->getTasks()); + } + + public function testTasksProvider() + { + $tasks = [ + 'magentoCron' => ['expressin' => '* * * * *', 'command' => 'bin/magento cron:run'], + 'magentoSetup' => ['command' => 'bin/magento setup:cron:run'], + ]; + + /** @var $tasksProvider $tasksProvider */ + $tasksProvider = new TasksProvider($tasks); + $this->assertSame($tasks, $tasksProvider->getTasks()); + } +} diff --git a/lib/internal/Magento/Framework/Data/CollectionDataSourceInterface.php b/lib/internal/Magento/Framework/Data/CollectionDataSourceInterface.php index eeff60c1f61c8..4bdf29fd1c8fc 100644 --- a/lib/internal/Magento/Framework/Data/CollectionDataSourceInterface.php +++ b/lib/internal/Magento/Framework/Data/CollectionDataSourceInterface.php @@ -5,9 +5,11 @@ */ namespace Magento\Framework\Data; +use Magento\Framework\View\Element\Block\ArgumentInterface; + /** * Interface CollectionDataSourceInterface */ -interface CollectionDataSourceInterface +interface CollectionDataSourceInterface extends ArgumentInterface { } diff --git a/lib/internal/Magento/Framework/View/Element/Block/ArgumentInterface.php b/lib/internal/Magento/Framework/View/Element/Block/ArgumentInterface.php new file mode 100644 index 0000000000000..123a75946ba77 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Element/Block/ArgumentInterface.php @@ -0,0 +1,14 @@ + self::EXPECTED_CLASS]; - $this->_objectManager->expects( - $this->once() - )->method( - 'create' - )->with( - self::EXPECTED_CLASS - )->will( - $this->returnValue($this) - ); + $input = ['name' => 'dataSource', 'value' => self::EXPECTED_CLASS]; + $this->_objectManager->expects($this->once()) + ->method('create') + ->with(self::EXPECTED_CLASS) + ->willReturn($this); $actual = $this->_model->evaluate($input); $this->assertSame($this, $actual); @@ -56,17 +51,18 @@ public function testEvaluateWrongClass($input, $expectedException, $expectedExce { $this->setExpectedException($expectedException, $expectedExceptionMessage); $self = $this; - $this->_objectManager->expects($this->any())->method('create')->will( - $this->returnCallback( - function ($className) use ($self) { - return $self->getMock($className); - } - ) + $this->_objectManager->expects($this->any())->method('create')->willReturnCallback( + function ($className) use ($self) { + return $self->getMock($className); + } ); $this->_model->evaluate($input); } + /** + * @return array + */ public function evaluateWrongClassDataProvider() { return [