diff --git a/.gitignore b/.gitignore index 61d970a274b8dc1a573bf8fd31083ab984197bff..1dc24183ad30092742a351bd094b4ae5573052be 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ atlassian* /var/* !/var/.htaccess /vendor +!/vendor/.htaccess diff --git a/.htaccess b/.htaccess index bef5869dd2fdf6a38d9769fee0c8e7ab8d683a2d..13564585ac2274e074728c844aa119b8df9d61a6 100644 --- a/.htaccess +++ b/.htaccess @@ -171,13 +171,83 @@ </IfModule> ########################################### -## Deny access to release notes to prevent disclosure of the installed Magento version +## Deny access to root files to hide sensitive application information + RedirectMatch 404 /\.git - <Files RELEASE_NOTES.txt> - Order allow,deny - Deny from all + <Files composer.json> + order allow,deny + deny from all </Files> -############################################ + <Files composer.lock> + order allow,deny + deny from all + </Files> + <Files .gitignore> + order allow,deny + deny from all + </Files> + <Files .htaccess> + order allow,deny + deny from all + </Files> + <Files .htaccess.sample> + order allow,deny + deny from all + </Files> + <Files .php_cs> + order allow,deny + deny from all + </Files> + <Files .travis.yml> + order allow,deny + deny from all + </Files> + <Files CHANGELOG.md> + order allow,deny + deny from all + </Files> + <Files CONTRIBUTING.md> + order allow,deny + deny from all + </Files> + <Files CONTRIBUTOR_LICENSE_AGREEMENT.html> + order allow,deny + deny from all + </Files> + <Files COPYING.txt> + order allow,deny + deny from all + </Files> + <Files Gruntfile.js> + order allow,deny + deny from all + </Files> + <Files LICENSE.txt> + order allow,deny + deny from all + </Files> + <Files LICENSE_AFL.txt> + order allow,deny + deny from all + </Files> + <Files nginx.conf.sample> + order allow,deny + deny from all + </Files> + <Files package.json> + order allow,deny + deny from all + </Files> + <Files php.ini.sample> + order allow,deny + deny from all + </Files> + <Files README.md> + order allow,deny + deny from all + </Files> + +################################ ## If running in cluster environment, uncomment this ## http://developer.yahoo.com/performance/rules.html#etags diff --git a/.htaccess.sample b/.htaccess.sample index 133ce7de2c59badd5df4a159bb921e8a99f05eb7..891dad19d642b5f958c9c33c71476dd4d39247c8 100644 --- a/.htaccess.sample +++ b/.htaccess.sample @@ -36,7 +36,7 @@ ############################################ ## adjust memory limit - php_value memory_limit 256M + php_value memory_limit 768M php_value max_execution_time 18000 ############################################ @@ -65,13 +65,6 @@ SecFilterScanPOST Off </IfModule> -<IfModule mod_headers.c> -############################################ -## prevent clickjacking - - Header set X-Frame-Options SAMEORIGIN -</IfModule> - <IfModule mod_deflate.c> ############################################ @@ -136,9 +129,11 @@ RewriteRule .* - [L,R=405] ############################################ -## always send 404 on missing files in these folders +## redirect for mobile user agents - RewriteCond %{REQUEST_URI} !^/pub/(media|js)/ + #RewriteCond %{REQUEST_URI} !^/mobiledirectoryhere/.*$ + #RewriteCond %{HTTP_USER_AGENT} "android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile" [NC] + #RewriteRule ^(.*)$ /mobiledirectoryhere/ [L,R=302] ############################################ ## never rewrite for existing files, directories and links @@ -175,16 +170,84 @@ </IfModule> ########################################### -## Deny access to release notes to prevent disclosure of the installed Magento version +## Deny access to root files to hide sensitive application information + RedirectMatch 404 /\.git - <Files RELEASE_NOTES.txt> - Order allow,deny - Deny from all + <Files composer.json> + order allow,deny + deny from all + </Files> + <Files composer.lock> + order allow,deny + deny from all + </Files> + <Files .gitignore> + order allow,deny + deny from all + </Files> + <Files .htaccess> + order allow,deny + deny from all + </Files> + <Files .htaccess.sample> + order allow,deny + deny from all + </Files> + <Files .php_cs> + order allow,deny + deny from all + </Files> + <Files .travis.yml> + order allow,deny + deny from all + </Files> + <Files CHANGELOG.md> + order allow,deny + deny from all + </Files> + <Files CONTRIBUTING.md> + order allow,deny + deny from all + </Files> + <Files CONTRIBUTOR_LICENSE_AGREEMENT.html> + order allow,deny + deny from all + </Files> + <Files COPYING.txt> + order allow,deny + deny from all + </Files> + <Files Gruntfile.js> + order allow,deny + deny from all + </Files> + <Files LICENSE.txt> + order allow,deny + deny from all + </Files> + <Files LICENSE_AFL.txt> + order allow,deny + deny from all + </Files> + <Files nginx.conf.sample> + order allow,deny + deny from all + </Files> + <Files package.json> + order allow,deny + deny from all + </Files> + <Files php.ini.sample> + order allow,deny + deny from all + </Files> + <Files README.md> + order allow,deny + deny from all </Files> -############################################ +################################ ## If running in cluster environment, uncomment this ## http://developer.yahoo.com/performance/rules.html#etags #FileETag none - diff --git a/app/code/Magento/Backend/Block/Widget/Grid.php b/app/code/Magento/Backend/Block/Widget/Grid.php index ee8b36cdea847789cdde5e7876e7d5609a586848..66bc193719784b684d6b7b212790aa49686b831e 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid.php +++ b/app/code/Magento/Backend/Block/Widget/Grid.php @@ -760,7 +760,7 @@ class Grid extends \Magento\Backend\Block\Widget */ public function getJsObjectName() { - return $this->getId() . 'JsObject'; + return preg_replace("~[^a-z0-9_]*~i", '', $this->getId()) . 'JsObject'; } /** diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php index 0a0e612eab9ced6d7cdcaa0715cc28a9f4b6f535..a512da3522c4229e7b41114a2559879f4f5993a7 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php @@ -67,7 +67,7 @@ class AbstractFilter extends \Magento\Backend\Block\AbstractBlock implements */ protected function _getHtmlName() { - return $this->getColumn()->getId(); + return $this->escapeHtml($this->getColumn()->getId()); } /** @@ -77,7 +77,7 @@ class AbstractFilter extends \Magento\Backend\Block\AbstractBlock implements */ protected function _getHtmlId() { - return $this->getColumn()->getHtmlId(); + return $this->escapeHtml($this->getColumn()->getHtmlId()); } /** @@ -88,7 +88,7 @@ class AbstractFilter extends \Magento\Backend\Block\AbstractBlock implements */ public function getEscapedValue($index = null) { - return htmlspecialchars((string)$this->getValue($index)); + return $this->escapeHtml((string)$this->getValue($index)); } /** diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/TextTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/TextTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a59b23f8d3ca722854983f16833b773dd432f87a --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/TextTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\Unit\Block\Widget\Grid\Column\Filter; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class TextTest extends \PHPUnit_Framework_TestCase +{ + /** @var \Magento\Backend\Block\Widget\Grid\Column\Filter\Text*/ + protected $block; + + /** @var ObjectManagerHelper */ + protected $objectManagerHelper; + + /** @var \Magento\Backend\Block\Context|\PHPUnit_Framework_MockObject_MockObject */ + protected $context; + + /** @var \Magento\Framework\DB\Helper|\PHPUnit_Framework_MockObject_MockObject */ + protected $helper; + + /** @var \Magento\Framework\Escaper|\PHPUnit_Framework_MockObject_MockObject */ + protected $escaper; + + protected function setUp() + { + $this->context = $this->getMockBuilder('Magento\Backend\Block\Context') + ->setMethods(['getEscaper']) + ->disableOriginalConstructor() + ->getMock(); + $this->escaper = $this->getMock('Magento\Framework\Escaper', ['escapeHtml'], [], '', false); + $this->helper = $this->getMock('Magento\Framework\DB\Helper', [], [], '', false); + + $this->context->expects($this->once())->method('getEscaper')->willReturn($this->escaper); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->block = $this->objectManagerHelper->getObject( + 'Magento\Backend\Block\Widget\Grid\Column\Filter\Text', + [ + 'context' => $this->context, + 'resourceHelper' => $this->helper + ] + ); + } + + public function testGetHtml() + { + $resultHtml = '<input type="text" name="escapedHtml" ' . + 'id="escapedHtml" value="escapedHtml" ' . + 'class="input-text admin__control-text no-changes" data-ui-id="filter-escapedhtml" />'; + + $column = $this->getMockBuilder('Magento\Backend\Block\Widget\Grid\Column') + ->setMethods(['getId', 'getHtmlId']) + ->disableOriginalConstructor() + ->getMock(); + + $this->block->setColumn($column); + + $this->escaper->expects($this->any())->method('escapeHtml')->willReturn('escapedHtml'); + $column->expects($this->any())->method('getId')->willReturn('id'); + $column->expects($this->once())->method('getHtmlId')->willReturn('htmlId'); + + $this->assertEquals($resultHtml, $this->block->getHtml()); + } +} diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml index 12dcacd1a035648d05e278c7da386e971d7686a6..6e32f5eed660512ef634b71aceb5443e08ee48a1 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml @@ -24,7 +24,7 @@ $numColumns = sizeof($block->getColumns()); <?php if ($block->getCollection()): ?> <?php if ($block->canDisplayContainer()): ?> -<div id="<?php /* @escapeNotVerified */ echo $block->getId() ?>" data-grid-id="<?php /* @escapeNotVerified */ echo $block->getId() ?>"> +<div id="<?php echo $block->escapeHtml($block->getId()) ?>" data-grid-id="<?php echo $block->escapeHtml($block->getId()) ?>"> <?php else: ?> <?php echo $block->getLayout()->getMessagesBlock()->getGroupedHtml() ?> <?php endif; ?> @@ -50,17 +50,17 @@ $numColumns = sizeof($block->getColumns()); <?php endif; ?> <?php $countRecords = $block->getCollection()->getSize(); ?> <div class="admin__control-support-text"> - <span id="<?php echo $block->getHtmlId() ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>> + <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>> <?php /* @escapeNotVerified */ echo $countRecords ?> </span> <?php /* @escapeNotVerified */ echo __('records found') ?> - <span id="<?php echo $block->getHtmlId() ?>_massaction-count" + <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>_massaction-count" class="mass-select-info _empty"><strong data-role="counter">0</strong> <span><?php /* @escapeNotVerified */ echo __('selected') ?></span></span> </div> <?php if ($block->getPagerVisibility()): ?> <div class="admin__data-grid-pager-wrap"> <select name="<?php /* @escapeNotVerified */ echo $block->getVarNameLimit() ?>" - id="<?php echo $block->getHtmlId()?>_page-limit" + id="<?php echo $block->escapeHtml($block->getHtmlId())?>_page-limit" onchange="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.loadByElement(this)" <?php /* @escapeNotVerified */ echo $block->getUiId('per-page') ?> class="admin__control-select"> <option value="20"<?php if ($block->getCollection()->getPageSize() == 20): ?> @@ -79,7 +79,7 @@ $numColumns = sizeof($block->getColumns()); selected="selected"<?php endif; ?>>200 </option> </select> - <label for="<?php echo $block->getHtmlId()?>_page-limit" + <label for="<?php echo $block->escapeHtml($block->getHtmlId())?>_page-limit" class="admin__control-support-text"><?php /* @escapeNotVerified */ echo __('per page') ?></label> <div class="admin__data-grid-pager"> <?php $_curPage = $block->getCollection()->getCurPage() ?> @@ -96,13 +96,13 @@ $numColumns = sizeof($block->getColumns()); <?php endif; ?> <input type="text" - id="<?php echo $block->getHtmlId()?>_page-current" + id="<?php echo $block->escapeHtml($block->getHtmlId())?>_page-current" name="<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>" value="<?php /* @escapeNotVerified */ echo $_curPage ?>" class="admin__control-text" onkeypress="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.inputPage(event, '<?php /* @escapeNotVerified */ echo $_lastPage ?>')" <?php /* @escapeNotVerified */ echo $block->getUiId('current-page') ?> /> - <label class="admin__control-support-text" for="<?php echo $block->getHtmlId() + <label class="admin__control-support-text" for="<?php echo $block->escapeHtml($block->getHtmlId()) ?>_page-current"> <?php /* @escapeNotVerified */ echo __('of %1', '<span>' . $block->getCollection()->getLastPageNumber() . '</span>') ?> </label> @@ -122,13 +122,13 @@ $numColumns = sizeof($block->getColumns()); </div> <div class="admin__data-grid-wrap admin__data-grid-wrap-static"> <?php if ($block->getGridCssClass()): ?> - <table class="<?php /* @escapeNotVerified */ echo $block->getGridCssClass() ?> data-grid" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_table"> + <table class="<?php /* @escapeNotVerified */ echo $block->getGridCssClass() ?> data-grid" id="<?php echo $block->escapeHtml($block->getId()) ?>_table"> <!-- Rendering column set --> <?php echo $block->getChildHtml('grid.columnSet'); ?> </table> <?php else: ?> - <table class="data-grid" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_table"> + <table class="data-grid" id="<?php echo $block->escapeHtml($block->getId()) ?>_table"> <!-- Rendering column set --> <?php echo $block->getChildHtml('grid.columnSet'); ?> </table> @@ -161,7 +161,7 @@ $numColumns = sizeof($block->getColumns()); registry.get('<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>', function (<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>) { <?php endif; ?> - <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid('<?php /* @escapeNotVerified */ echo $block->getId() ?>', '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>'); + <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid('<?php echo $block->escapeHtml($block->getId()) ?>', '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>'); <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.useAjax = <?php /* @escapeNotVerified */ echo $block->getUseAjax() ? 'true' : 'false' ?>; <?php if ($block->getRowClickCallback()): ?> <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.rowClickCallback = <?php /* @escapeNotVerified */ echo $block->getRowClickCallback() ?>; diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml index 385a5a1393c16698ed543ce292d3e18c398ca8ec..ddd9fa5f2f18ae565d365c090d2ad2c8dd35f55a 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml @@ -26,7 +26,7 @@ $numColumns = sizeof($block->getColumns()); <?php if ($block->getCollection()): ?> <?php if ($block->canDisplayContainer()): ?> - <div id="<?php /* @escapeNotVerified */ echo $block->getId() ?>" data-grid-id="<?php /* @escapeNotVerified */ echo $block->getId() ?>"> + <div id="<?php echo $block->escapeHtml($block->getId()) ?>" data-grid-id="<?php echo $block->escapeHtml($block->getId()) ?>"> <?php else: ?> <?php echo $block->getLayout()->getMessagesBlock()->getGroupedHtml() ?> <?php endif; ?> @@ -41,8 +41,8 @@ $numColumns = sizeof($block->getColumns()); <div class="admin__data-grid-export"> <label class="admin__control-support-text" - for="<?php /* @escapeNotVerified */ echo $block->getId() ?>_export"><?php /* @escapeNotVerified */ echo __('Export to:') ?></label> - <select name="<?php /* @escapeNotVerified */ echo $block->getId() ?>_export" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_export" + for="<?php echo $block->escapeHtml($block->getId()) ?>_export"><?php /* @escapeNotVerified */ echo __('Export to:') ?></label> + <select name="<?php echo $block->escapeHtml($block->getId()) ?>_export" id="<?php echo $block->escapeHtml($block->getId()) ?>_export" class="admin__control-select"> <?php foreach ($block->getExportTypes() as $_type): ?> <option value="<?php /* @escapeNotVerified */ echo $_type->getUrl() ?>"><?php /* @escapeNotVerified */ echo $_type->getLabel() ?></option> @@ -61,18 +61,18 @@ $numColumns = sizeof($block->getColumns()); <?php endif; ?> <?php $countRecords = $block->getCollection()->getSize(); ?> <div class="admin__control-support-text"> - <span id="<?php echo $block->getHtmlId() ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>> + <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>> <?php /* @escapeNotVerified */ echo $countRecords ?> </span> <?php /* @escapeNotVerified */ echo __('records found') ?> - <span id="<?php echo $block->getHtmlId() ?>_massaction-count" + <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>_massaction-count" class="mass-select-info _empty"><strong data-role="counter">0</strong> <span><?php /* @escapeNotVerified */ echo __('selected') ?></span></span> </div> <?php if ($block->getPagerVisibility()): ?> <div class="admin__data-grid-pager-wrap"> <select name="<?php /* @escapeNotVerified */ echo $block->getVarNameLimit() ?>" - id="<?php echo $block->getHtmlId()?>_page-limit" + id="<?php echo $block->escapeHTML($block->getHtmlId())?>_page-limit" onchange="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.loadByElement(this)" class="admin__control-select"> <option value="20"<?php if ($block->getCollection()->getPageSize() == 20): ?> @@ -91,7 +91,7 @@ $numColumns = sizeof($block->getColumns()); selected="selected"<?php endif; ?>>200 </option> </select> - <label for="<?php echo $block->getHtmlId()?><?php echo $block->getHtmlId()?>_page-limit" + <label for="<?php echo $block->escapeHTML($block->getHtmlId())?><?php echo $block->escapeHTML($block->getHtmlId())?>_page-limit" class="admin__control-support-text"><?php /* @escapeNotVerified */ echo __('per page') ?></label> <div class="admin__data-grid-pager"> @@ -107,12 +107,12 @@ $numColumns = sizeof($block->getColumns()); <button type="button" class="action-previous disabled"><span><?php /* @escapeNotVerified */ echo __('Previous page') ?></span></button> <?php endif; ?> <input type="text" - id="<?php echo $block->getHtmlId()?>_page-current" + id="<?php echo $block->escapeHTML($block->getHtmlId())?>_page-current" name="<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>" value="<?php /* @escapeNotVerified */ echo $_curPage ?>" class="admin__control-text" onkeypress="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.inputPage(event, '<?php /* @escapeNotVerified */ echo $_lastPage ?>')" <?php /* @escapeNotVerified */ echo $block->getUiId('current-page') ?> /> - <label class="admin__control-support-text" for="<?php echo $block->getHtmlId()?>_page-current"> + <label class="admin__control-support-text" for="<?php echo $block->escapeHTML($block->getHtmlId())?>_page-current"> <?php /* @escapeNotVerified */ echo __('of %1', '<span>' . $block->getCollection()->getLastPageNumber() . '</span>') ?> </label> <?php if ($_curPage < $_lastPage): ?> @@ -133,7 +133,7 @@ $numColumns = sizeof($block->getColumns()); <?php endif; ?> <div class="admin__data-grid-wrap admin__data-grid-wrap-static"> - <table class="data-grid" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_table"> + <table class="data-grid" id="<?php echo $block->escapeHtml($block->getId()) ?>_table"> <?php /* This part is commented to remove all <col> tags from the code. */ /* foreach ($block->getColumns() as $_column): ?> @@ -263,7 +263,7 @@ $numColumns = sizeof($block->getColumns()); registry.get('<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>', function (<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>) { <?php endif; ?> - <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid('<?php /* @escapeNotVerified */ echo $block->getId() ?>', '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>'); + <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid(<?php /* @noEscape */ echo $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($block->getId()) ?>, '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>'); <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.useAjax = '<?php /* @escapeNotVerified */ echo $block->getUseAjax() ?>'; <?php if ($block->getRowClickCallback()): ?> <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.rowClickCallback = <?php /* @escapeNotVerified */ echo $block->getRowClickCallback() ?>; diff --git a/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php b/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php index 85ce181f5eb1957de3c5c205593d496931caf82e..684eb43e4ad6019b28243f9ef932f74d4e7f16e9 100644 --- a/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php +++ b/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php @@ -13,13 +13,16 @@ class Grid extends \Magento\Backend\App\Action */ public function execute() { + $index = $this->getRequest()->getParam('index'); + if (!preg_match('/^[a-z0-9_.]*$/i', $index)) { + throw new \InvalidArgumentException('Invalid parameter "index"'); + } + return $this->getResponse()->setBody( $this->_view->getLayout()->createBlock( 'Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Bundle\Option\Search\Grid', 'adminhtml.catalog.product.edit.tab.bundle.option.search.grid' - )->setIndex( - $this->getRequest()->getParam('index') - )->toHtml() + )->setIndex($index)->toHtml() ); } } diff --git a/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php b/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php index 267dade65be131b972fdaa5e9254603cc8ef9bc6..c0a7342f8249fe51452f5b762116455f814a9581 100644 --- a/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php @@ -90,4 +90,15 @@ class GridTest extends \PHPUnit_Framework_TestCase $this->assertEquals($this->response, $this->controller->execute()); } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid parameter "index" + */ + public function testExecuteWithException() + { + $this->request->expects($this->once())->method('getParam')->with('index')->willReturn('<index"'); + + $this->controller->execute(); + } } diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/options.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/options.phtml index 40f152cf2581d7a3cd05841f0aca24eb1e7a4941..717bf12da25a03ac35628b16738660bfa929e344 100644 --- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/options.phtml +++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/options.phtml @@ -25,7 +25,7 @@ $helper = $this->helper('Magento\Catalog\Helper\Output'); } } </script> - <fieldset class="fieldset bundle options"> + <fieldset class="fieldset fieldset-bundle-options"> <legend id="customizeTitle" class="legend title"> <span><?php /* @escapeNotVerified */ echo __('Customize %1', $helper->productAttribute($product, $product->getName(), 'name')) ?></span> </legend><br /> diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php index 72ad16576f1ca238d01a068f5cf53be714755b30..5cf7b922ac980d1a20c5be02b284b946dc109d22 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php @@ -134,13 +134,14 @@ class Inventory extends \Magento\Backend\Block\Widget public function getFieldValue($field) { $stockItem = $this->getStockItem(); + $value = null; if ($stockItem->getItemId()) { $method = 'get' . SimpleDataObjectConverter::snakeCaseToUpperCamelCase($field); - if (method_exists($stockItem, $method)) { - return $stockItem->{$method}(); + if (is_callable([$stockItem, $method])) { + $value = $stockItem->{$method}(); } } - return $this->stockConfiguration->getDefaultConfigValue($field); + return $value === null ? $this->stockConfiguration->getDefaultConfigValue($field) : $value; } /** diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php index 2f99d45e092e8458fd1c6d6c38eb9cd26becd14c..4276ab20af7d39f4abd3fc5da3d2728de6683045 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php @@ -189,15 +189,15 @@ class Tabs extends \Magento\Backend\Block\Widget\Tabs unset($advancedGroups['advanced-pricing']); } - if ($this->_moduleManager->isEnabled('Magento_CatalogInventory')) { + if ($this->_moduleManager->isEnabled('Magento_CatalogInventory') + && $this->getChildBlock('advanced-inventory') + ) { $this->addTab( 'advanced-inventory', [ 'label' => __('Advanced Inventory'), 'content' => $this->_translateHtml( - $this->getLayout()->createBlock( - 'Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Inventory' - )->toHtml() + $this->getChildHtml('advanced-inventory') ), 'group_code' => self::ADVANCED_TAB_GROUP_CODE ] diff --git a/app/code/Magento/Catalog/Block/Product/View/Options/Type/Select.php b/app/code/Magento/Catalog/Block/Product/View/Options/Type/Select.php index bfaba7215694333216076f799e490a09a34b14e6..f07a069b38daea127b38797a5564ec1e6ab8207a 100644 --- a/app/code/Magento/Catalog/Block/Product/View/Options/Type/Select.php +++ b/app/code/Magento/Catalog/Block/Product/View/Options/Type/Select.php @@ -160,7 +160,7 @@ class Select extends \Magento\Catalog\Block\Product\View\Options\AbstractOptions $count . '"><span>' . $_value->getTitle() . - '</span>' . + '</span> ' . $priceStr . '</label>'; $selectHtml .= '</div>'; diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index dd0f5ec4ead4f93ae5a12313ada595359471ef03..2453c4395345b2b20bbfc1ee09ab3a7e29c5171d 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -2504,6 +2504,9 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements */ public function setTypeId($typeId) { + if ($typeId !== $this->_getData('type_id')) { + $this->_typeInstance = null; + } return $this->setData(self::TYPE_ID, $typeId); } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php index 97f42ea1d09ab40dba23ae24684f516fb520b74d..9cbc587f0cb84a8f347e3feb9c35553969bb5272 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php @@ -1407,4 +1407,19 @@ class ProductTest extends \PHPUnit_Framework_TestCase $this->productTypeInstanceMock->expects($this->never())->method('priceFactory'); $this->assertEquals($finalPrice, $this->model->getFinalPrice($qty)); } + + public function testGetTypeId() + { + $productType = $this->getMockBuilder('Magento\Catalog\Model\Product\Type\Virtual') + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->productTypeInstanceMock->expects($this->exactly(2))->method('factory')->will( + $this->returnValue($productType) + ); + + $this->model->getTypeInstance(); + $this->model->setTypeId('typeId'); + $this->model->getTypeInstance(); + } } diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml index 55e9ebee91f5bcbbcc6b77c4d81fd3638dec7592..4377b74674bd39520293cbab250d994fe33be3e6 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml @@ -37,6 +37,12 @@ <argument name="class" xsi:type="string">ajax</argument> </arguments> </block> + <block class="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Inventory" name="product_tabs.advanced-inventory" as="advanced-inventory"> + <arguments> + <argument name="label" xsi:type="string" translate="true">Advanced Inventory</argument> + <argument name="group_code" xsi:type="string">advanced</argument> + </arguments> + </block> <block class="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Alerts" name="product_tabs.product-alerts" as="product-alerts"> <arguments> <argument name="label" xsi:type="string" translate="true">Product Alerts</argument> diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml index 3f6215626ad827c7a2791828b4886b958ce4bfc4..d3c382f9276b8a2d9df9ec1473fbe1707779fc42 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml @@ -63,7 +63,7 @@ data: {attribute_id: ui.item.id, template_id: templateId, group: $(this).data('group')}, showLoader: true }).done(function() { - setTimeout(function() { //do defered + setTimeout(function() { //do deferred $('[data-form=edit-product]').trigger('changeAttributeSet', {id: templateId}); }, 10); }); diff --git a/app/code/Magento/CatalogInventory/Model/Resource/QtyCounterInterface.php b/app/code/Magento/CatalogInventory/Model/Resource/QtyCounterInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..e36a04a2b3d40630ee819410f7f86aa4c283f6dd --- /dev/null +++ b/app/code/Magento/CatalogInventory/Model/Resource/QtyCounterInterface.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\CatalogInventory\Model\Resource; + +/** + * Correct particular stock products qty + */ +interface QtyCounterInterface +{ + /** + * Correct particular stock products qty based on operator + * + * @param int[] $items + * @param int $websiteId + * @param string $operator +/- + * @return void + */ + public function correctItemsQty(array $items, $websiteId, $operator); +} diff --git a/app/code/Magento/CatalogInventory/Model/Resource/Stock.php b/app/code/Magento/CatalogInventory/Model/Resource/Stock.php index e5c9c696404fb1dcd6b1a096be6190f09b16822f..6948b642136d19844f92273987dcf9c8ee3b299d 100644 --- a/app/code/Magento/CatalogInventory/Model/Resource/Stock.php +++ b/app/code/Magento/CatalogInventory/Model/Resource/Stock.php @@ -12,7 +12,7 @@ use Magento\Store\Model\StoreManagerInterface; /** * Stock resource model */ -class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb +class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb implements QtyCounterInterface { /** * @var StockConfigurationInterface @@ -134,14 +134,9 @@ class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb } /** - * Correct particular stock products qty based on operator - * - * @param array $items - * @param int $websiteId - * @param string $operator +/- - * @return $this + * {@inheritdoc} */ - public function correctItemsQty(array $items, $websiteId, $operator = '-') + public function correctItemsQty(array $items, $websiteId, $operator) { if (empty($items)) { return $this; @@ -161,8 +156,6 @@ class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb $connection->beginTransaction(); $connection->update($this->getTable('cataloginventory_stock_item'), ['qty' => $value], $where); $connection->commit(); - - return $this; } /** diff --git a/app/code/Magento/CatalogInventory/Model/StockManagement.php b/app/code/Magento/CatalogInventory/Model/StockManagement.php index 3d5fee6d9cef90eb8bfcf98d78b6c45e68c0bca2..c487ab15394e79dce91848c9fa45dafddef19161 100644 --- a/app/code/Magento/CatalogInventory/Model/StockManagement.php +++ b/app/code/Magento/CatalogInventory/Model/StockManagement.php @@ -9,6 +9,7 @@ use Magento\Catalog\Model\ProductFactory; use Magento\CatalogInventory\Api\Data\StockItemInterface; use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockManagementInterface; +use Magento\CatalogInventory\Model\Resource\QtyCounterInterface; use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface; use Magento\Catalog\Api\ProductRepositoryInterface; @@ -38,26 +39,37 @@ class StockManagement implements StockManagementInterface protected $productRepository; /** - * @var \Magento\CatalogInventory\Model\Resource\Stock + * @var Resource\Stock */ protected $resource; /** + * @var QtyCounterInterface + */ + private $qtyCounter; + + /** + * @param Resource\Stock $stockResource * @param StockRegistryProviderInterface $stockRegistryProvider * @param StockState $stockState * @param StockConfigurationInterface $stockConfiguration * @param ProductRepositoryInterface $productRepository + * @param Resource\QtyCounterInterface $qtyCounter */ public function __construct( + Resource\Stock $stockResource, StockRegistryProviderInterface $stockRegistryProvider, StockState $stockState, StockConfigurationInterface $stockConfiguration, - ProductRepositoryInterface $productRepository + ProductRepositoryInterface $productRepository, + QtyCounterInterface $qtyCounter ) { $this->stockRegistryProvider = $stockRegistryProvider; $this->stockState = $stockState; $this->stockConfiguration = $stockConfiguration; $this->productRepository = $productRepository; + $this->qtyCounter = $qtyCounter; + $this->resource = $stockResource; } /** @@ -108,7 +120,7 @@ class StockManagement implements StockManagementInterface $fullSaveItems[] = $stockItem; } } - $this->getResource()->correctItemsQty($registeredItems, $websiteId, '-'); + $this->qtyCounter->correctItemsQty($registeredItems, $websiteId, '-'); $this->getResource()->commit(); return $fullSaveItems; } @@ -123,7 +135,7 @@ class StockManagement implements StockManagementInterface //if (!$websiteId) { $websiteId = $this->stockConfiguration->getDefaultWebsiteId(); //} - $this->getResource()->correctItemsQty($items, $websiteId, '+'); + $this->qtyCounter->correctItemsQty($items, $websiteId, '+'); return true; } @@ -168,15 +180,10 @@ class StockManagement implements StockManagementInterface } /** - * @return \Magento\CatalogInventory\Model\Resource\Stock + * @return Stock */ protected function getResource() { - if (empty($this->resource)) { - $this->resource = \Magento\Framework\App\ObjectManager::getInstance()->get( - 'Magento\CatalogInventory\Model\Resource\Stock' - ); - } return $this->resource; } diff --git a/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php b/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php index 789fc3748dcd9a32b78b5cd3333020992c4d0e71..653f77000c8c45be8f4333f02d42b0501b5f9f3d 100644 --- a/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php +++ b/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php @@ -8,6 +8,7 @@ namespace Magento\CatalogInventory\Observer; use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockIndexInterface; +use Magento\CatalogInventory\Api\StockItemRepositoryInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; use Magento\Framework\Event\Observer as EventObserver; @@ -32,7 +33,7 @@ class SaveInventoryDataObserver protected $stockRegistry; /** - * @var \Magento\CatalogInventory\Api\StockItemRepositoryInterface + * @var StockItemRepositoryInterface */ protected $stockItemRepository; @@ -74,13 +75,13 @@ class SaveInventoryDataObserver * @param StockIndexInterface $stockIndex * @param StockConfigurationInterface $stockConfiguration * @param StockRegistryInterface $stockRegistry - * @param \Magento\CatalogInventory\Api\StockItemRepositoryInterface $stockItemRepository + * @param StockItemRepositoryInterface $stockItemRepository */ public function __construct( StockIndexInterface $stockIndex, StockConfigurationInterface $stockConfiguration, StockRegistryInterface $stockRegistry, - \Magento\CatalogInventory\Api\StockItemRepositoryInterface $stockItemRepository + StockItemRepositoryInterface $stockItemRepository ) { $this->stockIndex = $stockIndex; $this->stockConfiguration = $stockConfiguration; diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml index a57b542a0b12cf390a47524aaedd62f1100041bb..4332e525c3260619830f2e5f2102759edf2e346e 100644 --- a/app/code/Magento/CatalogInventory/etc/di.xml +++ b/app/code/Magento/CatalogInventory/etc/di.xml @@ -30,6 +30,8 @@ <preference for="Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface" type="Magento\CatalogInventory\Model\StockRegistryProvider" /> <preference for="Magento\CatalogInventory\Model\Spi\StockStateProviderInterface" type="Magento\CatalogInventory\Model\StockStateProvider" /> + + <preference for="Magento\CatalogInventory\Model\Resource\QtyCounterInterface" type="\Magento\CatalogInventory\Model\Resource\Stock" /> <type name="Magento\CatalogInventory\Observer\UpdateItemsStockUponConfigChangeObserver"> <arguments> diff --git a/app/code/Magento/CatalogRule/composer.json b/app/code/Magento/CatalogRule/composer.json index 8abce05a972830229256bd5475aad5b4452b38ad..887ed8b40e83cf9513fb518be418a16b42bc284e 100644 --- a/app/code/Magento/CatalogRule/composer.json +++ b/app/code/Magento/CatalogRule/composer.json @@ -9,10 +9,12 @@ "magento/module-customer": "1.0.0-beta", "magento/module-backend": "1.0.0-beta", "magento/module-eav": "1.0.0-beta", - "magento/module-import-export": "1.0.0-beta", "magento/framework": "1.0.0-beta", "magento/magento-composer-installer": "*" }, + "suggest": { + "magento/module-import-export": "1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/CatalogRuleConfigurable/composer.json b/app/code/Magento/CatalogRuleConfigurable/composer.json index c689ed54a3ca963774116d0b90c2b13073029c6a..fc6bea322d3c59aacb561c8b166823a5d3ea0720 100644 --- a/app/code/Magento/CatalogRuleConfigurable/composer.json +++ b/app/code/Magento/CatalogRuleConfigurable/composer.json @@ -3,11 +3,13 @@ "description": "N/A", "require": { "php": "~5.5.0|~5.6.0|~7.0.0", - "magento/module-catalog-rule": "1.0.0-beta", "magento/module-configurable-product": "1.0.0-beta", "magento/framework": "1.0.0-beta", "magento/magento-composer-installer": "*" }, + "suggest": { + "magento/module-catalog-rule": "1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php index 037e4c3629e034b6ef57564abbcf8daa025f8644..8f8fb11c19d8513f40427af224ee2fe6921cb783 100644 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php +++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php @@ -97,29 +97,26 @@ class Preprocessor implements PreprocessorInterface */ private function processQueryWithField(FilterInterface $filter, $isNegation, $query) { - $currentStoreId = $this->scopeResolver->getScope()->getId(); - $select = null; /** @var \Magento\Catalog\Model\Resource\Eav\Attribute $attribute */ $attribute = $this->config->getAttribute(Product::ENTITY, $filter->getField()); - $table = $attribute->getBackendTable(); if ($filter->getField() === 'price') { - $filterQuery = str_replace( + $resultQuery = str_replace( $this->connection->quoteIdentifier('price'), $this->connection->quoteIdentifier('price_index.min_price'), $query ); - return $filterQuery; } elseif ($filter->getField() === 'category_ids') { return 'category_ids_index.category_id = ' . $filter->getValue(); } elseif ($attribute->isStatic()) { $alias = $this->tableMapper->getMappingAlias($filter); - $filterQuery = str_replace( + $resultQuery = str_replace( $this->connection->quoteIdentifier($attribute->getAttributeCode()), $this->connection->quoteIdentifier($alias . '.' . $attribute->getAttributeCode()), $query ); - return $filterQuery; - } elseif ($filter->getType() === FilterInterface::TYPE_TERM) { + } elseif ($filter->getType() === FilterInterface::TYPE_TERM + && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true) + ) { $alias = $this->tableMapper->getMappingAlias($filter); if (is_array($filter->getValue())) { $value = sprintf( @@ -130,16 +127,18 @@ class Preprocessor implements PreprocessorInterface } else { $value = ($isNegation ? '!' : '') . '= ' . $filter->getValue(); } - $filterQuery = sprintf( + $resultQuery = sprintf( '%1$s.value %2$s', $alias, $value ); - return $filterQuery; } else { + $table = $attribute->getBackendTable(); $select = $this->connection->select(); $ifNullCondition = $this->connection->getIfNullSql('current_store.value', 'main_table.value'); + $currentStoreId = $this->scopeResolver->getScope()->getId(); + $select->from(['main_table' => $table], 'entity_id') ->joinLeft( ['current_store' => $table], @@ -154,10 +153,12 @@ class Preprocessor implements PreprocessorInterface ) ->where('main_table.store_id = ?', Store::DEFAULT_STORE_ID) ->having($query); - } - return 'search_index.entity_id IN ( - select entity_id from ' . $this->conditionManager->wrapBrackets($select) . ' as filter + $resultQuery = 'search_index.entity_id IN ( + select entity_id from ' . $this->conditionManager->wrapBrackets($select) . ' as filter )'; + } + + return $resultQuery; } } diff --git a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php index c951e9b538f12e22367e682ce335742c3c2cccdf..5dd7633026068b4dea7253e9d5d36e1611a265c0 100644 --- a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php +++ b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php @@ -103,9 +103,10 @@ class TableMapper if ($fieldToTableMap) { list($alias, $table, $mapOn, $mappedFields) = $fieldToTableMap; $table = $this->resource->getTableName($table); - } elseif ($filter->getType() === FilterInterface::TYPE_TERM) { - $attribute = $this->getAttributeByCode($field); - if ($attribute) { + } elseif ($attribute = $this->getAttributeByCode($field)) { + if ($filter->getType() === FilterInterface::TYPE_TERM + && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true) + ) { $table = $this->resource->getTableName('catalog_product_index_eav'); $alias = $field . '_filter'; $mapOn = sprintf( @@ -115,21 +116,14 @@ class TableMapper $this->getStoreId() ); $mappedFields = []; - } - } else { - $attribute = $this->getAttributeByCode($field); - if ($attribute && $attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) { + } elseif ($attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) { $table = $attribute->getBackendTable(); - $alias = $this->getTableAlias($table); + $alias = $field . '_filter'; $mapOn = 'search_index.entity_id = ' . $alias . '.entity_id'; $mappedFields = null; } } - if (!$alias && $table) { - $alias = $this->getTableAlias($table); - } - return [$alias, $table, $mapOn, $mappedFields]; } @@ -242,15 +236,6 @@ class TableMapper return array_key_exists($field, $fieldToTableMap) ? $fieldToTableMap[$field] : null; } - /** - * @param string $table - * @return string - */ - private function getTableAlias($table) - { - return md5($table); - } - /** * @param string $field * @return \Magento\Catalog\Model\Resource\Eav\Attribute diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php index 2e5241e8e91f028334a05d333f623bc7981b473f..1208bf32c77a01fe1c692b7142660570be305b38 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php @@ -7,6 +7,7 @@ namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Filter; use Magento\Framework\DB\Select; +use Magento\Framework\Search\Request\FilterInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; use PHPUnit_Framework_MockObject_MockObject as MockObject; @@ -46,7 +47,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase private $select; /** - * @var \Magento\Framework\Search\Request\FilterInterface|MockObject + * @var FilterInterface|MockObject */ private $filter; @@ -86,7 +87,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->setMethods(['getId']) ->getMockForAbstractClass(); - $this->scopeResolver->expects($this->once()) + $this->scopeResolver->expects($this->any()) ->method('getScope') ->will($this->returnValue($this->scope)); $this->config = $this->getMockBuilder('\Magento\Eav\Model\Config') @@ -95,7 +96,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase ->getMock(); $this->attribute = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute\AbstractAttribute') ->disableOriginalConstructor() - ->setMethods(['getBackendTable', 'isStatic', 'getAttributeId', 'getAttributeCode']) + ->setMethods(['getBackendTable', 'isStatic', 'getAttributeId', 'getAttributeCode', 'getFrontendInput']) ->getMockForAbstractClass(); $this->resource = $resource = $this->getMockBuilder('\Magento\Framework\App\Resource') ->disableOriginalConstructor() @@ -120,7 +121,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue($this->connection)); $this->filter = $this->getMockBuilder('\Magento\Framework\Search\Request\FilterInterface') ->disableOriginalConstructor() - ->setMethods(['getField', 'getValue']) + ->setMethods(['getField', 'getValue', 'getType']) ->getMockForAbstractClass(); $this->conditionManager->expects($this->any()) @@ -154,11 +155,9 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase public function testProcessPrice() { $expectedResult = 'price_index.min_price = 23'; - $scopeId = 0; $isNegation = false; $query = 'price = 23'; - $this->scope->expects($this->once())->method('getId')->will($this->returnValue($scopeId)); $this->filter->expects($this->exactly(2)) ->method('getField') ->will($this->returnValue('price')); @@ -174,11 +173,9 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase public function testProcessCategoryIds() { $expectedResult = 'category_ids_index.category_id = FilterValue'; - $scopeId = 0; $isNegation = false; $query = 'SELECT category_ids FROM catalog_product_entity'; - $this->scope->expects($this->once())->method('getId')->will($this->returnValue($scopeId)); $this->filter->expects($this->exactly(3)) ->method('getField') ->will($this->returnValue('category_ids')); @@ -199,7 +196,6 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase public function testProcessStaticAttribute() { $expectedResult = 'attr_table_alias.static_attribute LIKE %name%'; - $scopeId = 0; $isNegation = false; $query = 'static_attribute LIKE %name%'; @@ -207,7 +203,6 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase ->willReturn('static_attribute'); $this->tableMapper->expects($this->once())->method('getMappingAlias') ->willReturn('attr_table_alias'); - $this->scope->expects($this->once())->method('getId')->will($this->returnValue($scopeId)); $this->filter->expects($this->exactly(3)) ->method('getField') ->will($this->returnValue('static_attribute')); @@ -218,14 +213,100 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase $this->attribute->expects($this->once()) ->method('isStatic') ->will($this->returnValue(true)); - $this->attribute->expects($this->once()) - ->method('getBackendTable') - ->will($this->returnValue('backend_table')); $actualResult = $this->target->process($this->filter, $isNegation, $query); $this->assertSame($expectedResult, $this->removeWhitespaces($actualResult)); } + /** + * @dataProvider testTermFilterDataProvider + */ + public function testProcessTermFilter($frontendInput, $fieldValue, $isNegation, $expected) + { + $this->config->expects($this->exactly(1)) + ->method('getAttribute') + ->with(\Magento\Catalog\Model\Product::ENTITY, 'termField') + ->will($this->returnValue($this->attribute)); + + $this->attribute->expects($this->once()) + ->method('isStatic') + ->will($this->returnValue(false)); + + $this->filter->expects($this->once()) + ->method('getType') + ->willReturn(FilterInterface::TYPE_TERM); + $this->attribute->expects($this->once()) + ->method('getFrontendInput') + ->willReturn($frontendInput); + + $this->tableMapper->expects($this->once())->method('getMappingAlias') + ->willReturn('termAttrAlias'); + + $this->filter->expects($this->exactly(3)) + ->method('getField') + ->willReturn('termField'); + $this->filter->expects($this->exactly(2)) + ->method('getValue') + ->willReturn($fieldValue); + + $actualResult = $this->target->process($this->filter, $isNegation, 'This filter is not depends on used query'); + $this->assertSame($expected, $this->removeWhitespaces($actualResult)); + } + + public function testTermFilterDataProvider() + { + return [ + 'selectPositiveEqual' => [ + 'frontendInput' => 'select', + 'fieldValue' => 'positiveValue', + 'isNegation' => false, + 'expected' => 'termAttrAlias.value = positiveValue', + ], + 'selectPositiveArray' => [ + 'frontendInput' => 'select', + 'fieldValue' => [2, 3, 15], + 'isNegation' => false, + 'expected' => 'termAttrAlias.value IN (2,3,15)', + ], + 'selectNegativeEqual' => [ + 'frontendInput' => 'select', + 'fieldValue' => 'positiveValue', + 'isNegation' => true, + 'expected' => 'termAttrAlias.value != positiveValue', + ], + 'selectNegativeArray' => [ + 'frontendInput' => 'select', + 'fieldValue' => [4, 3, 42], + 'isNegation' => true, + 'expected' => 'termAttrAlias.value NOT IN (4,3,42)', + ], + 'multiSelectPositiveEqual' => [ + 'frontendInput' => 'multiselect', + 'fieldValue' => 'positiveValue', + 'isNegation' => false, + 'expected' => 'termAttrAlias.value = positiveValue', + ], + 'multiSelectPositiveArray' => [ + 'frontendInput' => 'multiselect', + 'fieldValue' => [2, 3, 15], + 'isNegation' => false, + 'expected' => 'termAttrAlias.value IN (2,3,15)', + ], + 'multiSelectNegativeEqual' => [ + 'frontendInput' => 'multiselect', + 'fieldValue' => 'negativeValue', + 'isNegation' => true, + 'expected' => 'termAttrAlias.value != negativeValue', + ], + 'multiSelectNegativeArray' => [ + 'frontendInput' => 'multiselect', + 'fieldValue' => [4, 3, 42], + 'isNegation' => true, + 'expected' => 'termAttrAlias.value NOT IN (4,3,42)', + ], + ]; + } + public function testProcessNotStaticAttribute() { $expectedResult = 'search_index.entity_id IN (select entity_id from (TEST QUERY PART) as filter)'; diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php index 60a8bbbd47b827d32b4dc7c0994cb4422e66742b..f888803a1db621e6c9af3c07da658a9a8d32b5ee 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php @@ -167,15 +167,15 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase { $priceFilter = $this->createRangeFilter('static'); $query = $this->createFilterQuery($priceFilter); - $this->createAttributeMock('static', 'static', 'backend_table', 0); + $this->createAttributeMock('static', 'static', 'backend_table', 0, 'select'); $this->request->expects($this->once()) ->method('getQuery') ->willReturn($query); $this->select->expects($this->once()) ->method('joinLeft') ->with( - ['4111c4a3daddb5c5dba31cdac705114b' => 'backend_table'], - 'search_index.entity_id = 4111c4a3daddb5c5dba31cdac705114b.entity_id', + ['static_filter' => 'backend_table'], + 'search_index.entity_id = static_filter.entity_id', null ) ->willReturnSelf(); @@ -204,7 +204,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddTermFilter() { - $this->createAttributeMock('color', null, null, 132, 0); + $this->createAttributeMock('color', null, null, 132, 'select', 0); $categoryIdsFilter = $this->createTermFilter('color'); $query = $this->createFilterQuery($categoryIdsFilter); $this->request->expects($this->once()) @@ -226,9 +226,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddBoolQueryWithTermFiltersInside() { - $this->createAttributeMock('must1', null, null, 101, 0); - $this->createAttributeMock('should1', null, null, 102, 1); - $this->createAttributeMock('mustNot1', null, null, 103, 2); + $this->createAttributeMock('must1', null, null, 101, 'select', 0); + $this->createAttributeMock('should1', null, null, 102, 'select', 1); + $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2); $query = $this->createBoolQuery( [ @@ -280,9 +280,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddBoolQueryWithTermAndPriceFiltersInside() { - $this->createAttributeMock('must1', null, null, 101, 0); - $this->createAttributeMock('should1', null, null, 102, 1); - $this->createAttributeMock('mustNot1', null, null, 103, 2); + $this->createAttributeMock('must1', null, null, 101, 'select', 0); + $this->createAttributeMock('should1', null, null, 102, 'select', 1); + $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2); $query = $this->createBoolQuery( [ $this->createFilterQuery($this->createTermFilter('must1')), @@ -342,9 +342,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddBoolFilterWithTermFiltersInside() { - $this->createAttributeMock('must1', null, null, 101, 0); - $this->createAttributeMock('should1', null, null, 102, 1); - $this->createAttributeMock('mustNot1', null, null, 103, 2); + $this->createAttributeMock('must1', null, null, 101, 'select', 0); + $this->createAttributeMock('should1', null, null, 102, 'select', 1); + $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2); $query = $this->createFilterQuery( $this->createBoolFilter( [ @@ -397,9 +397,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddBoolFilterWithBoolFiltersInside() { - $this->createAttributeMock('must1', null, null, 101, 0); - $this->createAttributeMock('should1', null, null, 102, 1); - $this->createAttributeMock('mustNot1', null, null, 103, 2); + $this->createAttributeMock('must1', null, null, 101, 'select', 0); + $this->createAttributeMock('should1', null, null, 102, 'select', 1); + $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2); $query = $this->createFilterQuery( $this->createBoolFilter( [ @@ -563,6 +563,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase * @param string $backendType * @param string $backendTable * @param int $attributeId + * @param string $frontendInput * @param int $positionInCollection */ private function createAttributeMock( @@ -570,10 +571,11 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase $backendType = null, $backendTable = null, $attributeId = 120, + $frontendInput = 'select', $positionInCollection = 0 ) { $attribute = $this->getMockBuilder('\Magento\Catalog\Model\Resource\Eav\Attribute') - ->setMethods(['getBackendType', 'getBackendTable', 'getId']) + ->setMethods(['getBackendType', 'getBackendTable', 'getId', 'getFrontendInput']) ->disableOriginalConstructor() ->getMock(); $attribute->method('getId') @@ -582,6 +584,8 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase ->willReturn($backendType); $attribute->method('getBackendTable') ->willReturn($backendTable); + $attribute->method('getFrontendInput') + ->willReturn($frontendInput); $this->attributeCollection->expects($this->at($positionInCollection)) ->method('getItemByColumnValue') ->with('attribute_code', $code) diff --git a/app/code/Magento/CatalogSearch/view/frontend/layout/default.xml b/app/code/Magento/CatalogSearch/view/frontend/layout/default.xml index c04fedb21f0f325e1a96e05c03610ba5e0746325..892395ec75e3ec1735901258972bc4a589ca97eb 100644 --- a/app/code/Magento/CatalogSearch/view/frontend/layout/default.xml +++ b/app/code/Magento/CatalogSearch/view/frontend/layout/default.xml @@ -15,6 +15,9 @@ <arguments> <argument name="label" xsi:type="string">Advanced Search</argument> <argument name="path" xsi:type="string">catalogsearch/advanced</argument> + <argument name="attributes" xsi:type="array"> + <item name="data-action" xsi:type="string">advanced-search</item> + </argument> </arguments> </block> </referenceBlock> diff --git a/app/code/Magento/CatalogSearch/view/frontend/templates/advanced/link.phtml b/app/code/Magento/CatalogSearch/view/frontend/templates/advanced/link.phtml index d2558ea32ae0a181fc5895594e21de6acb6a1451..4b84bb7c6e7d1d3a878f992e3c60e2d18f7fe6ee 100644 --- a/app/code/Magento/CatalogSearch/view/frontend/templates/advanced/link.phtml +++ b/app/code/Magento/CatalogSearch/view/frontend/templates/advanced/link.phtml @@ -10,7 +10,7 @@ $helper = $this->helper('Magento\CatalogSearch\Helper\Data'); ?> <div class="nested"> - <a class="action advanced" href="<?php /* @escapeNotVerified */ echo $helper->getAdvancedSearchUrl(); ?>"> + <a class="action advanced" href="<?php /* @escapeNotVerified */ echo $helper->getAdvancedSearchUrl(); ?>" data-action="advanced-search"> <?php /* @escapeNotVerified */ echo __('Advanced Search'); ?> </a> </div> diff --git a/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php b/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php index 118108189fd5f6052a607e85b7824f38e72a7a56..a7271b7441e2609acb4c54e5f1a0fe9aa0c989df 100644 --- a/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php +++ b/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php @@ -51,11 +51,11 @@ class Sorting extends \Magento\Config\Model\Config\Structure\AbstractMapper { $sortIndexA = 0; if ($this->_hasValue('sortOrder', $elementA)) { - $sortIndexA = intval($elementA['sortOrder']); + $sortIndexA = floatval($elementA['sortOrder']); } $sortIndexB = 0; if ($this->_hasValue('sortOrder', $elementB)) { - $sortIndexB = intval($elementB['sortOrder']); + $sortIndexB = floatval($elementB['sortOrder']); } if ($sortIndexA == $sortIndexB) { diff --git a/app/code/Magento/Config/etc/system.xsd b/app/code/Magento/Config/etc/system.xsd index 4703d178f1a9e5c0c18df0eb67063d5bc9b310c5..3585f499ddc2429197369c0babbb8de74927ba40 100644 --- a/app/code/Magento/Config/etc/system.xsd +++ b/app/code/Magento/Config/etc/system.xsd @@ -48,7 +48,7 @@ <xs:attributeGroup name="tabAttributeGroup"> <xs:attribute name="id" type="typeId" use="required" /> <xs:attribute name="translate" type="xs:string" use="optional" /> - <xs:attribute name="sortOrder" type="xs:int" use="optional" /> + <xs:attribute name="sortOrder" type="xs:float" use="optional" /> <xs:attribute name="class" type="xs:string" use="optional" /> </xs:attributeGroup> @@ -56,7 +56,7 @@ <xs:attribute name="id" type="typeId" use="required" /> <xs:attribute name="translate" type="xs:string" use="optional" /> <xs:attribute name="type" type="xs:string" use="optional" /> - <xs:attribute name="sortOrder" type="xs:int" use="optional" /> + <xs:attribute name="sortOrder" type="xs:float" use="optional" /> <xs:attribute name="showInDefault" type="xs:int" use="optional" /> <xs:attribute name="showInStore" type="xs:int" use="optional" /> <xs:attribute name="showInWebsite" type="xs:int" use="optional" /> diff --git a/app/code/Magento/Config/etc/system_file.xsd b/app/code/Magento/Config/etc/system_file.xsd index 89c8f2db61d9d649255c44d261a128cb98ee384f..0bbc99c6a07f7da7e44237e4f8bc716bf47bde92 100644 --- a/app/code/Magento/Config/etc/system_file.xsd +++ b/app/code/Magento/Config/etc/system_file.xsd @@ -49,7 +49,7 @@ <xs:attributeGroup name="tabAttributeGroup"> <xs:attribute name="id" type="typeId" use="required" /> <xs:attribute name="translate" type="xs:string" use="optional" /> - <xs:attribute name="sortOrder" type="xs:int" use="optional" /> + <xs:attribute name="sortOrder" type="xs:float" use="optional" /> <xs:attribute name="class" type="xs:string" use="optional" /> </xs:attributeGroup> @@ -57,7 +57,7 @@ <xs:attribute name="id" type="typeId" use="required" /> <xs:attribute name="translate" type="xs:string" use="optional" /> <xs:attribute name="type" type="xs:string" use="optional" /> - <xs:attribute name="sortOrder" type="xs:int" use="optional" /> + <xs:attribute name="sortOrder" type="xs:float" use="optional" /> <xs:attribute name="showInDefault" type="xs:int" use="optional" /> <xs:attribute name="showInStore" type="xs:int" use="optional" /> <xs:attribute name="showInWebsite" type="xs:int" use="optional" /> diff --git a/app/code/Magento/ConfigurableProduct/composer.json b/app/code/Magento/ConfigurableProduct/composer.json index 1b6f0a5a8aea66ae6ccae51733bb3e4edac036fb..a90d56be9beb6ef47032c0d38dc8b6f22e724d28 100644 --- a/app/code/Magento/ConfigurableProduct/composer.json +++ b/app/code/Magento/ConfigurableProduct/composer.json @@ -6,7 +6,6 @@ "magento/module-store": "1.0.0-beta", "magento/module-catalog": "1.0.0-beta", "magento/module-catalog-inventory": "1.0.0-beta", - "magento/module-sales": "1.0.0-beta", "magento/module-checkout": "1.0.0-beta", "magento/module-msrp": "1.0.0-beta", "magento/module-backend": "1.0.0-beta", @@ -20,7 +19,8 @@ "magento/magento-composer-installer": "*" }, "suggest": { - "magento/module-webapi": "1.0.0-beta" + "magento/module-webapi": "1.0.0-beta", + "magento/module-sales": "1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/Cron/composer.json b/app/code/Magento/Cron/composer.json index b1afc6a19518bbc523a02f2c0db4f669510a0e67..653e1f8443cbba8f049eb397c299bde7ec9ac3f6 100644 --- a/app/code/Magento/Cron/composer.json +++ b/app/code/Magento/Cron/composer.json @@ -3,11 +3,13 @@ "description": "N/A", "require": { "php": "~5.5.0|~5.6.0|~7.0.0", - "magento/module-config": "1.0.0-beta", "magento/module-store": "1.0.0-beta", "magento/framework": "1.0.0-beta", "magento/magento-composer-installer": "*" }, + "suggest": { + "magento/module-config": "1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php old mode 100644 new mode 100755 diff --git a/app/code/Magento/Customer/Model/Resource/CustomerRepository.php b/app/code/Magento/Customer/Model/Resource/CustomerRepository.php index 45bca42044092acc519258e045ebcdd864e70782..429210512de90ab81b93290918b34e533ba1d879 100644 --- a/app/code/Magento/Customer/Model/Resource/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/Resource/CustomerRepository.php @@ -340,8 +340,7 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte $isEmailAddress = \Zend_Validate::is( $customer->getEmail(), - 'EmailAddress', - ['allow' => ['allow' => \Zend_Validate_Hostname::ALLOW_ALL, 'tld' => false]] + 'EmailAddress' ); if (!$isEmailAddress) { diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php old mode 100644 new mode 100755 diff --git a/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml b/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml index 4d208d4136c981d6204278a72dd19139d3afb926..8bc96494817b8a969c280243a6248a190b7b38dc 100644 --- a/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml @@ -19,7 +19,8 @@ <span data-bind="text: customer().fullname"></span> <button type="button" class="action switch" - tabindex="-1"> + tabindex="-1" + data-action="customer-menu-toggle"> <span><?php /* @escapeNotVerified */ echo __('Change')?></span> </button> </span> diff --git a/app/code/Magento/Dhl/composer.json b/app/code/Magento/Dhl/composer.json index 033291581ecafaa67d0cb60d76d38aa6f75b3c85..1f577af21d55cb1100238b9b8ce5a9bfc43ab029 100644 --- a/app/code/Magento/Dhl/composer.json +++ b/app/code/Magento/Dhl/composer.json @@ -9,7 +9,6 @@ "magento/module-backend": "1.0.0-beta", "magento/module-directory": "1.0.0-beta", "magento/module-sales": "1.0.0-beta", - "magento/module-checkout": "1.0.0-beta", "magento/module-catalog": "1.0.0-beta", "magento/module-catalog-inventory": "1.0.0-beta", "magento/module-quote": "1.0.0-beta", @@ -17,6 +16,9 @@ "lib-libxml": "*", "magento/magento-composer-installer": "*" }, + "suggest": { + "magento/module-checkout": "1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/GiftMessage/composer.json b/app/code/Magento/GiftMessage/composer.json index c3662869435b747e9c1ebbfc828ed2e2316f1dc9..6230e36ff13e4051816047af7c4960e4b94dc0e5 100644 --- a/app/code/Magento/GiftMessage/composer.json +++ b/app/code/Magento/GiftMessage/composer.json @@ -6,7 +6,6 @@ "magento/module-store": "1.0.0-beta", "magento/module-catalog": "1.0.0-beta", "magento/module-checkout": "1.0.0-beta", - "magento/module-multishipping": "1.0.0-beta", "magento/module-sales": "1.0.0-beta", "magento/module-backend": "1.0.0-beta", "magento/module-customer": "1.0.0-beta", @@ -15,6 +14,9 @@ "magento/framework": "1.0.0-beta", "magento/magento-composer-installer": "*" }, + "suggest": { + "magento/module-multishipping": "1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/Msrp/composer.json b/app/code/Magento/Msrp/composer.json index 14446581255e6b3fd52a7c5dce2fe32077a34a63..b5d603e700e321f17c6233a065f913d76782285c 100644 --- a/app/code/Magento/Msrp/composer.json +++ b/app/code/Magento/Msrp/composer.json @@ -4,7 +4,6 @@ "require": { "php": "~5.5.0|~5.6.0|~7.0.0", "magento/module-store": "1.0.0-beta", - "magento/module-bundle": "1.0.0-beta", "magento/module-catalog": "1.0.0-beta", "magento/module-downloadable": "1.0.0-beta", "magento/module-eav": "1.0.0-beta", @@ -14,6 +13,9 @@ "magento/framework": "1.0.0-beta", "magento/magento-composer-installer": "*" }, + "suggest": { + "magento/module-bundle": "1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/OfflineShipping/composer.json b/app/code/Magento/OfflineShipping/composer.json index 8a0287dd1dc6496b18ae5742406cec7799c2a05b..88ac36533cbf5bd62183cb8722ef2613e241dd49 100644 --- a/app/code/Magento/OfflineShipping/composer.json +++ b/app/code/Magento/OfflineShipping/composer.json @@ -11,11 +11,13 @@ "magento/module-sales": "1.0.0-beta", "magento/module-sales-rule": "1.0.0-beta", "magento/module-directory": "1.0.0-beta", - "magento/module-checkout": "1.0.0-beta", "magento/module-quote": "1.0.0-beta", "magento/framework": "1.0.0-beta", "magento/magento-composer-installer": "*" }, + "suggest": { + "magento/module-checkout": "1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/Store/etc/cache.xml b/app/code/Magento/Store/etc/cache.xml index 6dae6b683b09121e6bc3820d0d797fda2d7877bc..715a5a12e55b2534294eb688907d3522cbfa5e5e 100644 --- a/app/code/Magento/Store/etc/cache.xml +++ b/app/code/Magento/Store/etc/cache.xml @@ -22,6 +22,10 @@ <label>Collections Data</label> <description>Collection data files.</description> </type> + <type name="reflection" translate="label,description" instance="Magento\Framework\App\Cache\Type\Reflection"> + <label>Reflection Data</label> + <description>API interfaces reflection data.</description> + </type> <type name="db_ddl" translate="label,description" instance="Magento\Framework\DB\Adapter\DdlCache"> <label>Database DDL operations</label> <description>Results of DDL queries, such as describing tables or indexes.</description> diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml index c8bc755197c49bb0f7aa5e0351784fe7a8b04ef9..617fefa4091297f0d0ef9cd76b8a3f97d309b2bc 100644 --- a/app/code/Magento/Store/etc/di.xml +++ b/app/code/Magento/Store/etc/di.xml @@ -225,6 +225,11 @@ </argument> </arguments> </type> + <type name="Magento\Framework\Reflection\MethodsMap"> + <arguments> + <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Reflection</argument> + </arguments> + </type> <type name="Magento\Framework\Url"> <arguments> <argument name="scopeType" xsi:type="const">Magento\Store\Model\ScopeInterface::SCOPE_STORE</argument> diff --git a/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml b/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml index a43a5c7885a96a19534c859bf0051cb225044c18..8ce4c95f94275746b0df6182cbf15052c4ff1934 100644 --- a/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml +++ b/app/code/Magento/Swagger/view/frontend/layout/swagger_index_index.xml @@ -37,9 +37,8 @@ </head> <body> <!--Remove Magento page content--> - <remove name="page.wrapper"/> - <remove name="after.body.start"/> - <remove name="page.bottom"/> + <referenceContainer name="page.wrapper" remove="true"/> + <referenceBlock name="requirejs-config" remove="true"/> <referenceContainer name="root"> <block name="swaggerUiContent" class="Magento\Framework\View\Element\Template" template="Magento_Swagger::swagger-ui/index.phtml"/> </referenceContainer> diff --git a/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml b/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml index b9c6e924b3dc9575ea6ed19f867810402f6bf4bc..16f25fd80861cd9e2918969aaa9036507a36de22 100644 --- a/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml +++ b/app/code/Magento/Swagger/view/frontend/templates/swagger-ui/index.phtml @@ -18,7 +18,7 @@ $schemaUrl = rtrim($block->getBaseUrl(), '/') . '/rest/default/schema?services=a ?> <!DOCTYPE html> -<script language="text/javascript"> +<script> $(function () { var url = window.location.search.match(/url=([^&]+)/); if (url && url.length > 1) { diff --git a/app/code/Magento/Swatches/composer.json b/app/code/Magento/Swatches/composer.json index da38b6169f45d180cc72f4716ee5eae31b51a5d3..6cc94c567d3e8195cf6e7ded5d1d162b3fc193dc 100644 --- a/app/code/Magento/Swatches/composer.json +++ b/app/code/Magento/Swatches/composer.json @@ -11,11 +11,13 @@ "magento/module-backend": "1.0.0-beta", "magento/module-media-storage": "1.0.0-beta", "magento/module-config": "1.0.0-beta", - "magento/module-layered-navigation": "1.0.0-beta", "magento/module-theme": "1.0.0-beta", "magento/framework": "1.0.0-beta", "magento/magento-composer-installer": "*" }, + "suggest": { + "magento/module-layered-navigation": "1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/Theme/etc/di.xml b/app/code/Magento/Theme/etc/di.xml index e8da51653dbcbd691b2fe595c9fd3c8a525089db..6b32e65b7ec19a9caa7b1af6ae4029b3b4ca9f11 100644 --- a/app/code/Magento/Theme/etc/di.xml +++ b/app/code/Magento/Theme/etc/di.xml @@ -82,7 +82,7 @@ <type name="Magento\Theme\Model\View\Design"> <arguments> <argument name="themes" xsi:type="array"> - <item name="frontend" xsi:type="string">Magento/blank</item> + <item name="frontend" xsi:type="string">Magento/luma</item> <item name="adminhtml" xsi:type="string">Magento/backend</item> </argument> </arguments> diff --git a/app/code/Magento/User/Model/Resource/User.php b/app/code/Magento/User/Model/Resource/User.php index 9f2bf7f3d36599da3d9a48a0e6cd7291f89ef5dd..dc2f9c55f35ec5bcec961f881d6ed42c1129424e 100644 --- a/app/code/Magento/User/Model/Resource/User.php +++ b/app/code/Magento/User/Model/Resource/User.php @@ -522,8 +522,8 @@ class User extends \Magento\Framework\Model\Resource\Db\AbstractDb * Increment failures count along with updating lock expire and first failure dates * * @param ModelUser $user - * @param int|false $setLockExpires - * @param int|false $setFirstFailure + * @param int|bool $setLockExpires + * @param int|bool $setFirstFailure * @return void */ public function updateFailure($user, $setLockExpires = false, $setFirstFailure = false) diff --git a/app/code/Magento/User/Test/Unit/Model/Resource/UserTest.php b/app/code/Magento/User/Test/Unit/Model/Resource/UserTest.php new file mode 100755 index 0000000000000000000000000000000000000000..961cc40d5f3304599b2610c780d2d2774424af3b --- /dev/null +++ b/app/code/Magento/User/Test/Unit/Model/Resource/UserTest.php @@ -0,0 +1,442 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\User\Test\Unit\Model\Resource; + +/** + * Test class for \Magento\User\Model\Resource\User testing + */ +class UserTest extends \PHPUnit_Framework_TestCase +{ + /** @var \Magento\User\Model\Resource\User */ + protected $model; + + /** @var \Magento\User\Model\User|\PHPUnit_framework_MockObject_MockObject */ + protected $userMock; + + /** @var \Magento\Framework\Acl\CacheInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $aclCacheMock; + + /** @var \Magento\Framework\Model\Resource\Db\Context|\PHPUnit_Framework_MockObject_MockObject */ + protected $contextMock; + + /** @var \Magento\Authorization\Model\RoleFactory|\PHPUnit_Framework_MockObject_MockObject */ + protected $roleFactoryMock; + + /** @var \Magento\Framework\Stdlib\DateTime|\PHPUnit_Framework_MockObject_MockObject */ + protected $dateTimeMock; + + /** @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject */ + protected $resourceMock; + + /** @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $dbAdapterMock; + + /** @var \Magento\Framework\DB\Select|\PHPUnit_Framework_MockObject_MockObject */ + protected $selectMock; + + /** @var \Magento\Authorization\Model\Role|\PHPUnit_Framework_MockObject_MockObject */ + protected $roleMock; + + protected function setUp() + { + $this->userMock = $this->getMockBuilder('Magento\User\Model\User') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->resourceMock = $this->getMockBuilder('Magento\Framework\App\Resource') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->aclCacheMock = $this->getMockBuilder('Magento\Framework\Acl\CacheInterface') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->roleFactoryMock = $this->getMockBuilder('Magento\Authorization\Model\RoleFactory') + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->roleMock = $this->getMockBuilder('Magento\Authorization\Model\Role') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + + $this->dateTimeMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->selectMock = $this->getMockBuilder('Magento\Framework\DB\Select') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->dbAdapterMock = $this->getMockBuilder('Magento\Framework\DB\Adapter\AdapterInterface') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $helper->getObject( + 'Magento\User\Model\Resource\User', + [ + 'resource' => $this->resourceMock, + 'aclCache' => $this->aclCacheMock, + 'roleFactory' => $this->roleFactoryMock, + 'dateTime' => $this->dateTimeMock + ] + ); + } + + public function testIsUserUnique() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchRow')->willReturn([true]); + + $this->assertFalse($this->model->isUserUnique($this->userMock)); + } + + public function testRecordLogin() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update'); + + $this->assertInstanceOf('Magento\User\Model\Resource\User', $this->model->recordLogin($this->userMock)); + } + + public function testLoadByUsername() + { + $returnData = [1, 2, 3]; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchRow')->willReturn($returnData); + + $this->assertEquals($returnData, $this->model->loadByUsername('user1')); + } + + + public function testHasAssigned2Role() + { + $returnData = [1, 2, 3]; + $uid = 1234; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchAll')->willReturn($returnData); + + $this->assertEquals($returnData, $this->model->hasAssigned2Role($uid)); + $this->assertNull($this->model->hasAssigned2Role(0)); + } + + public function testHasAssigned2RolePassAnObject() + { + $methodUserMock = $this->getMockBuilder('\Magento\Framework\Model\AbstractModel') + ->disableOriginalConstructor() + ->setMethods(['getUserId']) + ->getMock(); + $returnData = [1, 2, 3]; + $uid = 1234; + $methodUserMock->expects($this->once())->method('getUserId')->willReturn($uid); + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchAll')->willReturn($returnData); + + $this->assertEquals($returnData, $this->model->hasAssigned2Role($methodUserMock)); + } + + public function testClearUserRoles() + { + $uid = 123; + $this->userMock->expects($this->once())->method('getId')->willReturn($uid); + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('delete'); + $this->model->_clearUserRoles($this->userMock); + } + + public function testDeleteSucess() + { + $uid = 123; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('beginTransaction'); + $this->userMock->expects($this->once())->method('getId')->willReturn($uid); + $this->dbAdapterMock->expects($this->atLeastOnce())->method('delete'); + + $this->assertTrue($this->model->delete($this->userMock)); + } + + public function testGetRolesEmptyId() + { + $this->assertEquals([], $this->model->getRoles($this->userMock)); + } + + public function testGetRolesReturnFilledArray() + { + $uid = 123; + $this->userMock->expects($this->atLeastOnce())->method('getId')->willReturn($uid); + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('joinLeft')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchCol')->willReturn([1, 2, 3]); + $this->assertEquals([1, 2, 3], $this->model->getRoles($this->userMock)); + } + + public function testGetRolesFetchRowFailure() + { + $uid = 123; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->userMock->expects($this->atLeastOnce())->method('getId')->willReturn($uid); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('joinLeft')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchCol')->willReturn(false); + $this->assertEquals([], $this->model->getRoles($this->userMock)); + } + + public function testSaveExtraEmptyId() + { + $this->resourceMock->expects($this->never())->method('getConnection'); + $this->assertInstanceOf( + 'Magento\User\Model\Resource\User', + $this->model->saveExtra($this->userMock, [1, 2, 3]) + ); + } + + public function testSaveExtraFilledId() + { + $uid = 123; + $this->userMock->expects($this->atLeastOnce())->method('getId')->willReturn($uid); + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update'); + $this->assertInstanceOf( + 'Magento\User\Model\Resource\User', + $this->model->saveExtra($this->userMock, [1, 2, 3]) + ); + } + + public function testCountAll() + { + $returnData = 123; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchOne')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->countAll()); + } + + public function testUpdateRoleUsersAclWithUsers() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->roleMock->expects($this->once())->method('getRoleUsers')->willReturn(['user1', 'user2']); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn(1); + $this->assertTrue($this->model->updateRoleUsersAcl($this->roleMock)); + } + + public function testUpdateRoleUsersAclNoUsers() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->roleMock->expects($this->once())->method('getRoleUsers')->willReturn([]); + $this->dbAdapterMock->expects($this->never())->method('update'); + $this->assertFalse($this->model->updateRoleUsersAcl($this->roleMock)); + } + + public function testUpdateRoleUsersAclUpdateFail() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->roleMock->expects($this->once())->method('getRoleUsers')->willReturn(['user1', 'user2']); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn(0); + $this->assertFalse($this->model->updateRoleUsersAcl($this->roleMock)); + } + + public function testUnlock() + { + $inputData = [1, 2, 3]; + $returnData = 5; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->unlock($inputData)); + } + + public function testUnlockWithInteger() + { + $inputData = 123; + $returnData = 5; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->unlock($inputData)); + } + + public function testLock() + { + $inputData = [1, 2, 3]; + $returnData = 5; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->lock($inputData, 1, 1)); + } + + public function testLockWithInteger() + { + $inputData = 123; + $returnData = 5; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->lock($inputData, 1, 1)); + } + + public function testGetOldPassword() + { + $returnData = ['password1', 'password2']; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('order')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->atLeastOnce())->method('fetchCol')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->getOldPasswords($this->userMock)); + } + + public function testDeleteFromRole() + { + $methodUserMock = $this->getMockBuilder('\Magento\Framework\Model\AbstractModel') + ->disableOriginalConstructor() + ->setMethods(['getUserId', 'getRoleId']) + ->getMock(); + $uid = 1234; + $roleId = 44; + $methodUserMock->expects($this->once())->method('getUserId')->willReturn($uid); + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $methodUserMock->expects($this->atleastOnce())->method('getRoleId')->willReturn($roleId); + $this->dbAdapterMock->expects($this->once())->method('delete'); + + $this->assertInstanceOf('\Magento\User\Model\Resource\User', $this->model->deleteFromRole($methodUserMock)); + } + + public function testRoleUserExists() + { + $methodUserMock = $this->getMockBuilder('\Magento\Framework\Model\AbstractModel') + ->disableOriginalConstructor() + ->setMethods(['getUserId', 'getRoleId']) + ->getMock(); + $uid = 1234; + $roleId = 44; + $returnData = [1, 2, 3]; + $methodUserMock->expects($this->atLeastOnce())->method('getUserId')->willReturn($uid); + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $methodUserMock->expects($this->once())->method('getRoleId')->willReturn($roleId); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchCol')->willReturn($returnData); + + $this->assertEquals($returnData, $this->model->roleUserExists($methodUserMock)); + $this->assertEquals([], $this->model->roleUserExists($this->userMock)); + } + + public function testGetValidationBeforeSave() + { + $this->assertInstanceOf('\Zend_Validate_Callback', $this->model->getValidationRulesBeforeSave()); + } + + public function testUpdateFailure() + { + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('quoteInto')->willReturn($this->selectMock); + $this->model->updateFailure($this->userMock, 1, 1); + } + + public function testTrackPassword() + { + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('insert')->willReturn($this->selectMock); + $this->model->trackPassword($this->userMock, "myPas#w0rd", 1); + } + + public function testGetLatestPassword() + { + $uid = 123; + $returnData = ['password1', 'password2']; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('fetchRow')->willReturn($returnData); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('order')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('limit')->willReturn($this->selectMock); + $this->assertEquals($returnData, $this->model->getLatestPassword($uid)); + } + + public function testInitUniqueFields() + { + $this->assertInstanceOf( + '\Magento\User\Model\Resource\User', + $this->invokeMethod($this->model, '_initUniqueFields', []) + ); + } + + public function testBeforeSave() + { + $this->userMock->expects($this->once())->method('isObjectNew')->willReturn(true); + + $this->assertInstanceOf( + '\Magento\User\Model\Resource\User', + $this->invokeMethod($this->model, '_beforeSave', [$this->userMock]) + ); + } + + public function testAfterSave() + { + $roleId = 123; + $methodUserMock = $this->getMockBuilder('\Magento\User\Model\User') + ->disableOriginalConstructor() + ->setMethods(['hasRoleId', 'getRoleId']) + ->getMock(); + $methodUserMock->expects($this->once())->method('hasRoleId')->willReturn(true); + $methodUserMock->expects($this->once())->method('getRoleId')->willReturn($roleId); + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->roleFactoryMock->expects($this->once())->method('create')->willReturn($this->roleMock); + $this->roleMock->expects($this->once())->method('load')->willReturn($this->roleMock); + $this->roleMock->expects($this->atLeastOnce())->method('getId')->willReturn($roleId); + $this->dbAdapterMock->expects($this->once())->method('describeTable')->willReturn([1, 2, 3]); + + $this->assertInstanceOf( + '\Magento\User\Model\Resource\User', + $this->invokeMethod($this->model, '_afterSave', [$methodUserMock]) + ); + } + + /** + * Call protected/private method of a class. + * + * @param $object + * @param $methodName + * @param array $parameters + * @return mixed + */ + public function invokeMethod(&$object, $methodName, array $parameters = []) + { + $reflection = new \ReflectionClass(get_class($object)); + $method = $reflection->getMethod($methodName); + $method->setAccessible(true); + + return $method->invokeArgs($object, $parameters); + } +} diff --git a/app/code/Magento/Webapi/etc/di.xml b/app/code/Magento/Webapi/etc/di.xml index 28d00c467ea83ed0f8973860c67544efaef81294..593ef6427082d1d149c84a4d761567e28a7594e4 100644 --- a/app/code/Magento/Webapi/etc/di.xml +++ b/app/code/Magento/Webapi/etc/di.xml @@ -21,18 +21,6 @@ <type name="Magento\Framework\Xml\Generator" shared="false" /> <type name="Magento\Framework\Xml\Parser" shared="false" /> <type name="Magento\Framework\Code\Scanner\DirectoryScanner" shared="false" /> - <type name="Magento\Server\Reflection" shared="false" /> - <type name="Magento\Framework\Reflection\MethodsMap"> - <arguments> - <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Webapi</argument> - </arguments> - </type> - <type name="Magento\Framework\Reflection\DataObjectProcessor"> - <arguments> - <argument name="extensionAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy</argument> - <argument name="customAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\CustomAttributesProcessor\Proxy</argument> - </arguments> - </type> <type name="Magento\Integration\Model\ConfigBasedIntegrationManager"> <plugin name="webapiSetup" type="Magento\Webapi\Model\Plugin\Manager" /> </type> diff --git a/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less index 41f09cede4543914e6897aade0c0f088270c0537..cbc2b02bcb7c749a5a4ec1be568ef462101dd212 100644 --- a/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less @@ -4,120 +4,121 @@ // */ // -// Common -//-------------------------------------- +// Common +// _____________________________________________ & when (@media-common = true) { -.bundle-actions { - &:extend(.abs-box-tocart all); - .action.primary { - &:extend(.abs-button-l all); - } -} - -.bundle-options-container { - clear: both; - margin-bottom: @indent__xl; - - .legend.title { - .lib-heading(h2); + .bundle-actions { + &:extend(.abs-box-tocart all); + .action.primary { + &:extend(.abs-button-l all); + } } - .product-add-form { - display: none; - } + .bundle-options-container { + clear: both; + margin-bottom: @indent__xl; - .input-text.qty { - &:extend(.abs-input-qty all); - } + .legend.title { + .lib-heading(h2); + } - .product-options-wrapper { - margin-bottom: @indent__l; - } + .product-add-form { + display: none; + } - .action.back { - margin-bottom: @indent__l; - } + .input-text.qty { + &:extend(.abs-input-qty all); + } - .price-box { - .price { - font-weight: @font-weight__bold; - font-size: @font-size__l; + .product-options-wrapper { + margin-bottom: @indent__l; } - } - .price-notice { - &:extend(.abs-adjustment-incl-excl-tax all); - } + .action.back { + margin-bottom: @indent__l; + } - .block-bundle-summary { - &:extend(.abs-add-box-sizing all); - .lib-css(background, @secondary__color); - padding: @indent__s @indent__base; + .price-box { + .price { + font-size: @font-size__l; + font-weight: @font-weight__bold; + } + } - > .title > strong { - .lib-heading(h2); + .price-notice { + &:extend(.abs-adjustment-incl-excl-tax all); } - .bundle-summary { - margin-top: @indent__l; - &.empty { - display: none; + .block-bundle-summary { + &:extend(.abs-add-box-sizing all); + .lib-css(background, @secondary__color); + padding: @indent__s @indent__base; + + > .title > strong { + .lib-heading(h2); } - > .subtitle { - .lib-heading(h3); - display: block; + + .bundle-summary { + margin-top: @indent__l; + &.empty { + display: none; + } + > .subtitle { + .lib-heading(h3); + display: block; + } } - } - .bundle.items { - &:extend(.abs-reset-list all); - > li { - margin-bottom: @indent__s; + .bundle.items { + &:extend(.abs-reset-list all); + > li { + margin-bottom: @indent__s; + } } - } - .box-tocart { - .actions { - margin-bottom: @indent__s; - display: inline-block; + .box-tocart { + .actions { + display: inline-block; + margin-bottom: @indent__s; + } + .action.primary { + &:extend(.abs-button-l all); + } } - .action.primary { - &:extend(.abs-button-l all); + .product-addto-links { + > .action { + &:extend(.abs-action-addto-product all); + vertical-align: top; + } } } - .product-addto-links { - > .action { - &:extend(.abs-action-addto-product all); - vertical-align: top; + .nested { + .field.qty { + .label { + .lib-css(font-weight, @form-field-label__font-weight); + .lib-css(margin, 0 0 @indent__xs); + display: inline-block; + } + .lib-css(margin-top, @form-field__vertical-indent); } } - } - .nested { - .field.qty { - .label { - .lib-css(font-weight, @form-field-label__font-weight); - .lib-css(margin, 0 0 @indent__xs); - display: inline-block; - } - .lib-css(margin-top, @form-field__vertical-indent); + p.required { + .lib-css(color, @form-field-label-asterisk__color); } } - p.required { - .lib-css(color, @form-field-label-asterisk__color); - } -} } // -// Desktop -//-------------------------------------- +// Desktop +// _____________________________________________ + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .bundle-options-container { .legend.title { - &:extend(.abs-reset-left-margin all); + &:extend(.abs-reset-left-margin-desktop all); } .bundle-options-wrapper, .product-options-wrapper { @@ -126,8 +127,8 @@ } .block-bundle-summary { float: right; - width: 40%; position: relative; + width: 40%; } .bundle-options-wrapper, .block-bundle-summary { diff --git a/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less index 4f2e1f6e2f20acaf528afd647c3c78ad62b6fe69..1d595ccb3fe48229cf67a0053761c1718c82ac21 100644 --- a/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less @@ -4,168 +4,171 @@ // */ // -// Common -//-------------------------------------- +// Common +// _____________________________________________ & when (@media-common = true) { -.bundle-actions { - margin: 0 0 @indent__l; - .action.primary.customize { - &:extend(.abs-button-l all); - &:extend(.abs-button-responsive all); + .bundle-actions { + margin: 0 0 @indent__l; + .action.primary.customize { + &:extend(.abs-button-l all); + &:extend(.abs-button-responsive all); + } } -} - -.bundle-options-container { - clear: both; - margin-bottom: @indent__xl; - .legend.title { - .lib-heading(h1); - border: 0; - padding: 0; - } + .bundle-options-container { + clear: both; + margin-bottom: @indent__xl; - .product-add-form { - display: none; - } + .legend.title { + .lib-heading(h1); + border: 0; + padding: 0; + } - .input-text.qty { - &:extend(.abs-input-qty all); - } + .product-add-form { + display: none; + } - .product-options-wrapper { - margin-bottom: @indent__l; - .fieldset > .field { - padding-top: @form-field__vertical-indent; - border-top: 1px @color-gray-middle1 solid; - &:first-of-type { - border-top: 0; - padding-top: 0; - } + .input-text.qty { + &:extend(.abs-input-qty all); } - .field.choice { - input { - float: left; - } - .label { - margin-left: 24px; - display: block; - } - .product-name { - display: block; - } - .label { - &:extend(.abs-add-clearfix all); + + .product-options-wrapper { + margin-bottom: @indent__l; + .fieldset > .field { + border-top: 1px @color-gray-middle1 solid; + padding-top: @form-field__vertical-indent; + &:first-of-type { + border-top: 0; + padding-top: 0; + } } - .price-notice { - float: left; - &:extend(.abs-adjustment-incl-excl-tax all); + .fieldset-bundle-options { + .field.choice { + .price-notice { + float: left; + &:extend(.abs-adjustment-incl-excl-tax all); + } + } } - .price-excluding-tax { - display: inline-block; + .field.choice { + input { + float: left; + } + .label { + display: block; + margin-left: 24px; + } + .product-name { + display: block; + } + .label { + &:extend(.abs-add-clearfix all); + } + .price-excluding-tax { + display: inline-block; + } } } - } - - .action.back { - &:extend(.abs-action-button-as-link all); - margin-bottom: @indent__l; - } - .block-bundle-summary { - > .title { - margin-bottom: 15px; - > strong { - .lib-heading(h2); - } - } - > .title, - .bundle-summary .subtitle { - border-bottom: 1px @color-gray-middle1 solid; - padding-bottom: 16px; - margin-bottom: @indent__m; - } - .price-box { - margin-bottom: @indent__base; - .price-label { - display: block; - margin-bottom: @indent__xs; - } + .action.back { + &:extend(.abs-action-button-as-link all); + margin-bottom: @indent__l; } - .bundle-summary { - margin-top: @indent__l; - &.empty { - display: none; + .block-bundle-summary { + > .title { + margin-bottom: 15px; + > strong { + .lib-heading(h2); + } } - > .subtitle { - .lib-heading(h2); - display: block; + > .title, + .bundle-summary .subtitle { + border-bottom: 1px @color-gray-middle1 solid; + margin-bottom: @indent__m; + padding-bottom: 16px; } - } - - .bundle.items { - &:extend(.abs-reset-list all); - > li { + .price-box { margin-bottom: @indent__base; + .price-label { + display: block; + margin-bottom: @indent__xs; + } } - } - .box-tocart { - &:extend(.abs-box-tocart all); - .action.primary { - &:extend(.abs-button-l all); - &:extend(.abs-button-responsive all); + .bundle-summary { + margin-top: @indent__l; + &.empty { + display: none; + } + > .subtitle { + .lib-heading(h2); + display: block; + } } - } - .product-addto-links { - text-align: center; - > .action { - &:extend(.abs-actions-addto all); - margin-right: 5%; - &.tocompare { - .lib-icon-font-symbol( - @_icon-font-content: @icon-compare-full, - @_icon-font-position: before - ); + + .bundle.items { + &:extend(.abs-reset-list all); + > li { + margin-bottom: @indent__base; } + } + .box-tocart { + &:extend(.abs-box-tocart all); + .action.primary { + &:extend(.abs-button-l all); + &:extend(.abs-button-responsive all); + } + } + .product-addto-links { + text-align: center; + > .action { + &:extend(.abs-actions-addto all); + margin-right: 5%; + &.tocompare { + .lib-icon-font-symbol( + @_icon-font-content: @icon-compare-full, + @_icon-font-position: before + ); + } + } } + .product-image-container, + .product.name, + .stock { + &:extend(.abs-visually-hidden all); + } } - .product-image-container, - .product.name, - .stock { - &:extend(.abs-visually-hidden all); + p.required { + .lib-css(color, @form-field-label-asterisk__color); } - } - p.required { - .lib-css(color, @form-field-label-asterisk__color); - } - .nested { - .field.qty { - .lib-form-field-type(@_type: block); - .label { - font-weight: @form-field-label__font-weight; - } - &:last-child { - margin-bottom: 0; + .nested { + .field.qty { + .lib-form-field-type(@_type: block); + .label { + font-weight: @form-field-label__font-weight; + } + &:last-child { + margin-bottom: 0; + } + margin-top: @form-field__vertical-indent; } - margin-top: @form-field__vertical-indent; + } + .price { + font-weight: @font-weight__semibold; } } - .price { - font-weight: @font-weight__semibold; - } -} - } // -// Desktop -//-------------------------------------- +// Desktop +// _____________________________________________ + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .bundle-actions { .action.primary.customize { @@ -182,19 +185,19 @@ width: 57%; } .block-bundle-summary { - margin-top: 66px; - padding: @indent__s @indent__base; &:extend(.abs-add-box-sizing-desktop all); float: right; - width: 40%; + margin-top: 66px; + padding: @indent__s @indent__base; position: relative; + width: 40%; .price-box { .price-wrapper, .price-wrapper > .price { + .lib-css(color, @price-color); font-size: @price-size-desktop; - line-height: @price-size-desktop; font-weight: @font-weight__semibold; - .lib-css(color, @price-color); + line-height: @price-size-desktop; } } .price-container { @@ -214,8 +217,8 @@ } .box-tocart { .action.primary { - width: 49%; margin-right: 1%; + width: 49%; } } .product-addto-links { diff --git a/app/etc/di.xml b/app/etc/di.xml index fbb7c6946ce3cb006f2be5c1d76476b3e5f05f53..e26240c8b6c8cb6200191e0c245d5f371e1b90c9 100755 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -1048,6 +1048,13 @@ </argument> </arguments> </type> + <type name="Magento\Server\Reflection" shared="false" /> + <type name="Magento\Framework\Reflection\DataObjectProcessor"> + <arguments> + <argument name="extensionAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy</argument> + <argument name="customAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\CustomAttributesProcessor\Proxy</argument> + </arguments> + </type> <type name="Magento\Framework\Url\Decoder"> <arguments> <argument name="urlBuilder" xsi:type="object">Magento\Framework\UrlInterface</argument> diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php index 0f49b8bef0ae3f56dfff91db4c9ae8cc25f371c4..606c42e6b1269fa16cd5fc1c279fb7f561232425 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php @@ -90,7 +90,7 @@ class StockItemTest extends WebapiAbstract $arguments = ['productSku' => $productSku]; $apiResult = $this->_webApiCall($serviceInfo, $arguments); $result['item_id'] = $apiResult['item_id']; - $this->assertEquals($result, $apiResult, 'The stock data does not match.'); + $this->assertEquals($result, array_intersect_key($apiResult, $result), 'The stock data does not match.'); return $apiResult; } @@ -140,7 +140,7 @@ class StockItemTest extends WebapiAbstract $stockItemResource = $this->objectManager->get('Magento\CatalogInventory\Model\Resource\Stock\Item'); $stockItemResource->loadByProductId($stockItem, $stockItemOld['product_id'], $stockItemOld['website_id']); $expectedResult['item_id'] = $stockItem->getItemId(); - $this->assertEquals($expectedResult, $stockItem->getData()); + $this->assertEquals($expectedResult, array_intersect_key($stockItem->getData(), $expectedResult)); } /** @@ -234,7 +234,7 @@ class StockItemTest extends WebapiAbstract 'manage_stock' => 1, 'low_stock_date' => '', 'is_decimal_divided' => '', - 'stock_status_changed_auto' => 0 + 'stock_status_changed_auto' => 0, ], ], ]; diff --git a/dev/tests/functional/composer.json b/dev/tests/functional/composer.json index 1287f8a2f00f08d893cd3171baa9cb44eefa72bf..6514ced02709b700ad494d85a0b8dced6a798737 100644 --- a/dev/tests/functional/composer.json +++ b/dev/tests/functional/composer.json @@ -1,6 +1,6 @@ { "require": { - "magento/mtf": "1.0.0-rc32", + "magento/mtf": "1.0.0-rc33", "php": "~5.5.0|~5.6.0|~7.0.0", "phpunit/phpunit": "4.1.0", "phpunit/phpunit-selenium": ">=1.2" diff --git a/dev/tests/functional/phpunit.xml.dist b/dev/tests/functional/phpunit.xml.dist index ec1748e20b13556da45e875c29870dcdd70f72b1..f5f293ffa39f5099974a754655166834d26eb9a2 100644 --- a/dev/tests/functional/phpunit.xml.dist +++ b/dev/tests/functional/phpunit.xml.dist @@ -38,6 +38,7 @@ <env name="module_whitelist" value="Magento_Install" /> <env name="basedir" value="var/log" /> <env name="credentials_file_path" value="./credentials.xml.dist" /> + <env name="mage_mode" value="developer" /> </php> </phpunit> diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Cache/Additional.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Cache/Additional.php index 30f7194a98fe6ee74c2949c5adad9df2bf472160..605afd986421b6a62248c9c0719f59fd47d41402 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Cache/Additional.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Cache/Additional.php @@ -31,4 +31,16 @@ class Additional extends Block { $this->_rootElement->find(sprintf($this->flushButton, $flushButtonName), Locator::SELECTOR_XPATH)->click(); } + + /** + * Check if button is visible in 'Additional Cache Management'. + * + * @param string $flushButtonName + * @return bool + */ + public function isFlushCacheButtonVisible($flushButtonName) + { + return $this->_rootElement->find(sprintf($this->flushButton, $flushButtonName), Locator::SELECTOR_XPATH) + ->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheFlushStaticFilesInProductionMode.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheFlushStaticFilesInProductionMode.php new file mode 100644 index 0000000000000000000000000000000000000000..dce65ed1bc54ab6d74b46962809f9a40c85e7681 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheFlushStaticFilesInProductionMode.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\Constraint; + +use Magento\Backend\Test\Page\Adminhtml\AdminCache; +use Magento\Mtf\Constraint\AbstractConstraint; + +/** + * Assert Flush Static Files Cache button not visible in production mode. + */ +class AssertCacheFlushStaticFilesInProductionMode extends AbstractConstraint +{ + const FLUSH_STATIC_FILES_CACHE = 'Flush Static Files Cache'; + + /** + * Assert Flush Static Files Cache button not visible in production mode. + * + * @param AdminCache $adminCache + * @return void + */ + public function processAssert(AdminCache $adminCache) + { + \PHPUnit_Framework_Assert::assertFalse( + $adminCache->getAdditionalBlock()->isFlushCacheButtonVisible(self::FLUSH_STATIC_FILES_CACHE), + self::FLUSH_STATIC_FILES_CACHE . ' button should not be visible in production mode.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return self::FLUSH_STATIC_FILES_CACHE . ' button is not visible in production mode.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheManagementAction.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheManagementAction.php index 30e7a986ba8e8f361f0d7d75517053777a5156e5..5ca1e4e677bbf7f3fa1ecf19f25114a19e547a2e 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheManagementAction.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheManagementAction.php @@ -6,7 +6,6 @@ namespace Magento\Backend\Test\Constraint; -use Magento\Backend\Test\Fixture\GlobalSearch; use Magento\Backend\Test\Page\Adminhtml\AdminCache; use Magento\Mtf\Constraint\AbstractConstraint; @@ -16,7 +15,7 @@ use Magento\Mtf\Constraint\AbstractConstraint; class AssertCacheManagementAction extends AbstractConstraint { /** - * Assert that backend page has correct title and 404 Error is absent on the page. + * Assert success message for cache flush. * * @param AdminCache $adminCache * @param string $successMessage diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9777614e554e1c5eee2a6b6538a84ff00f62bfa7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\TestCase; + +use Magento\Mtf\TestCase\Injectable; +use Magento\Backend\Test\Page\Adminhtml\AdminCache; + +/** + * Steps: + * 1. Log in to backend. + * 2. Navigate through menu to cache management page. + * 3. Perform asserts. + * + * @ZephyrId MAGETWO-39934 + */ +class CacheFlushStaticFilesInProductionModeTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + const DOMAIN = 'PS'; + /* end tags */ + + /** + * Test only for 'Flush Static Files Cache' in production mode. + * + * @return void + */ + public function __prepare() + { + if ($_ENV['mage_mode'] !== 'production') { + $this->markTestSkipped('Skip "Flush Static Files Cache" button absence test when not in production mode.'); + } + } + + /** + * Check 'Flush Static Files Cache' not visible in production mode. + * + * + * @param AdminCache $adminCache + * @return void + */ + public function test(AdminCache $adminCache) + { + $adminCache->open(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..7417721c749fb1f6accd5cda5c98375500a4e15c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheFlushStaticFilesInProductionModeTest.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Backend\Test\TestCase\CacheFlushStaticFilesInProductionModeTest" summary="Flush Static Files Cache button not in production mode" ticketId="MAGETWO-39934"> + <variation name="FlushStaticFilesCacheInProductionTest"> + <constraint name="Magento\Backend\Test\Constraint\AssertCacheFlushStaticFilesInProductionMode" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.php index 6817abe742c6d4917f8b80963f67df4d06b75e50..c25b3d8922e9f6f2e6c265ad00650634a7fdb779 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.php @@ -12,11 +12,11 @@ use Magento\Backend\Test\Page\Adminhtml\AdminCache; /** * Steps: * 1. Log in to backend. - * 2. Navigate throught menu to cache management page. + * 2. Navigate through menu to cache management page. * 3. Click a button. * 4. Perform asserts. * - * @ZephyrId MAGETWO-34502, MAGETWO-34503, MAGETWO-39934 + * @ZephyrId MAGETWO-34052, MAGETWO-34053, MAGETWO-39934 */ class CacheManagementTest extends Injectable { @@ -26,7 +26,7 @@ class CacheManagementTest extends Injectable /* end tags */ /** - * Open admin cache management page. + * Open admin cache management page and click button to flush cache. * * @param AdminCache $adminCache * @param string $flushButtonName @@ -34,6 +34,12 @@ class CacheManagementTest extends Injectable */ public function test(AdminCache $adminCache, $flushButtonName) { + /** + * Skip test for 'Flush Static Files Cache' in production mode. + */ + if (($flushButtonName === 'Flush Static Files Cache') && $_ENV['mage_mode'] === 'production') { + $this->markTestSkipped('Skip flushing static files cache test when in production mode.'); + } $adminCache->open(); $adminCache->getAdditionalBlock()->clickFlushCache($flushButtonName); } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.xml index e970b3f71fa5484226e5c222e599bce7f4dd00f8..f575bedde68835011423a03a3e9ffa5af0683607 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.xml @@ -6,7 +6,7 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> - <testCase name="Magento\Backend\Test\TestCase\CacheManagementTest" summary="Configuration option on backend for singleQuery mode" ticketId="MAGETWO-34502"> + <testCase name="Magento\Backend\Test\TestCase\CacheManagementTest" summary="Additional Cache Management" ticketId="MAGETWO-34052"> <variation name="FlushCatalogImagesCacheTest"> <data name="flushButtonName" xsi:type="string">Flush Catalog Images Cache</data> <data name="successMessage" xsi:type="string">The image cache was cleaned.</data> diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php index 2e4509a1e66eab3cb43acfd0a9f0407c7bf50ffc..332f6e6dbb2ca40725b7d638445eda2f74bc4aae 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php @@ -12,7 +12,7 @@ use Magento\Backend\Test\Page\Adminhtml\Dashboard; /** * Steps: * 1. Log in to backend. - * 2. Navigate throught menu to the page. + * 2. Navigate through menu to the page. * 3. Perform asserts. * * @ZephyrId MAGETWO-34874 diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php index 696395534ddaa2f185490278de90689416efbe80..90e586768e40c27e697f32984fcf908b03730d97 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php @@ -243,7 +243,7 @@ class Bundle extends Block */ protected function parseOptionText($optionText) { - preg_match('`^(.*?)\+ ?\$(\d.*?)$`', $optionText, $match); + preg_match('`^(.*?)\+ ?\$(\d.*?)$`sim', $optionText, $match); $optionPrice = isset($match[2]) ? str_replace(',', '', $match[2]) : 0; $optionTitle = isset($match[1]) ? trim($match[1]) : $optionText; diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Links/CompareLink.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Links/CompareLink.php new file mode 100644 index 0000000000000000000000000000000000000000..6be91bbcecd43e037e2387a2029f2e8f26282e1a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Links/CompareLink.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\Block\Links; + +use Magento\Mtf\Block\Block; + +/** + * Products compare link block. + */ +class CompareLink extends Block +{ + /** + * Locator value for qty of Products in Compare list. + * + * @var string + */ + protected $qtyCompareProducts = '.compare .counter.qty'; + + /** + * Get qty of Products in Compare list. + * + * @return string + */ + public function getQtyInCompareList() + { + $this->waitForElementVisible($this->qtyCompareProducts); + $compareProductLink = $this->_rootElement->find($this->qtyCompareProducts); + preg_match_all('/^\d+/', $compareProductLink->getText(), $matches); + return $matches[0][0]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php index dd2265411c098a6e4998c25ffde26a82e069e61e..72b8853c3ad809dec0245ce6863d6d25e561c15f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php @@ -11,54 +11,47 @@ use Magento\Mtf\Client\Locator; /** * Class Search - * Block for search field + * Block for "Search" section */ class Search extends Block { /** - * Selector matches found - "Suggest Search" + * Locator value for matches found - "Suggest Search". * * @var string */ protected $searchAutocomplete = './/div[@id="search_autocomplete"]//li[span[text()[normalize-space()="%s"]]]'; /** - * Selector number of matches for a given row + * Locator value for given row matches amount. * * @var string */ protected $searchItemAmount = '/span[contains(@class,"amount") and text()="%d"]'; /** - * Search field + * Locator value for "Search" field. * * @var string */ protected $searchInput = '#search'; /** - * Search button + * Locator value for "Search" button. * * @var string */ private $searchButton = '[title="Search"]'; /** - * Search button + * Locator value for "Search" button placeholder. * * @var string */ protected $placeholder = '//input[@id="search" and contains(@placeholder, "%s")]'; /** - * Css selector advanced search button - * - * @var string - */ - protected $advancedSearchSelector = '.action.advanced'; - - /** - * Search products by a keyword + * Perform search by a keyword. * * @param string $keyword * @return void @@ -68,37 +61,34 @@ class Search extends Block public function search($keyword) { $this->fillSearch($keyword); - $this->_rootElement->find($this->searchButton, Locator::SELECTOR_CSS)->click(); + $this->_rootElement->find($this->searchButton)->click(); } /** - * Fills the search field + * Fill "Search" field with correspondent text. * * @param string $text * @return void */ public function fillSearch($text) { - $this->_rootElement->find($this->searchInput, Locator::SELECTOR_CSS)->setValue($text); + $this->_rootElement->find($this->searchInput)->setValue($text); } /** - * Check that placeholder contains text + * Check if placeholder contains correspondent text or not. * * @param string $placeholderText * @return bool */ public function isPlaceholderContains($placeholderText) { - $field = $this->_rootElement->find( - sprintf($this->placeholder, $placeholderText), - Locator::SELECTOR_XPATH - ); + $field = $this->_rootElement->find(sprintf($this->placeholder, $placeholderText), Locator::SELECTOR_XPATH); return $field->isVisible(); } /** - * Checking block visibility "Suggest Search" + * Check if "Suggest Search" block visible or not. * * @param string $text * @param int|null $amount @@ -118,14 +108,4 @@ class Search extends Block } ); } - - /** - * Click advanced search button - * - * @return void - */ - public function clickAdvancedSearchButton() - { - $this->_rootElement->find($this->advancedSearchSelector)->click(); - } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php index 1f355049a172ea7b076feb749db30b33bb33fa64..3314878854c52bcd8eeae25bc1b1b17e88656753 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php @@ -53,7 +53,7 @@ class AssertProductAttributeIsFilterable extends AbstractConstraint ? $attribute->getManageFrontendLabel() : $attribute->getFrontendLabel(); \PHPUnit_Framework_Assert::assertTrue( - in_array($label, $catalogCategoryView->getLayeredNavigationBlock()->getFilters()), + in_array(strtoupper($label), $catalogCategoryView->getLayeredNavigationBlock()->getFilters()), 'Attribute is absent in layered navigation on category page.' ); } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php index a19a5f881b4373848827007b190329c8eb58731f..8e3b69699f827127448d04610653bafb8dbf83b4 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php @@ -37,7 +37,7 @@ class AssertProductAttributeIsFilterableInSearch extends AbstractConstraint ? $attribute->getManageFrontendLabel() : $attribute->getFrontendLabel(); \PHPUnit_Framework_Assert::assertTrue( - in_array($label, $catalogCategoryView->getLayeredNavigationBlock()->getFilters()), + in_array(strtoupper($label), $catalogCategoryView->getLayeredNavigationBlock()->getFilters()), 'Attribute is absent in layered navigation on search page.' ); } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php index 9dd4d24c9df1570a95297dae6c03fe46d2e3ffd8..b511bcd8968fbe8fd8c45c05f51a4b6c9aa1bc9a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php @@ -24,7 +24,7 @@ class AssertProductCompareItemsLink extends AbstractConstraint public function processAssert(array $products, CmsIndex $cmsIndex) { $productQty = count($products); - $qtyOnPage = $cmsIndex->getLinksBlock()->getQtyInCompareList(); + $qtyOnPage = $cmsIndex->getCompareLinkBlock()->getQtyInCompareList(); \PHPUnit_Framework_Assert::assertEquals( $productQty, diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml new file mode 100644 index 0000000000000000000000000000000000000000..c820d9985e3210b6dd8f70bbaf49db0de3cc7625 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/pages.xsd"> + <page name="CmsIndex" mca="cms/index/index"> + <block name="compareProductsBlock" class="Magento\Catalog\Test\Block\Product\Compare\Sidebar" locator=".sidebar.sidebar-additional" strategy="css selector" /> + <block name="compareLinkBlock" class="Magento\Catalog\Test\Block\Links\CompareLink" locator="[data-role='compare-products-link']" strategy="css selector" /> + </page> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php index e3940285daa737f105639664a6c4498075dd75a2..5fadf342d10eab9dbf5c643c6e745c225d99e54c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php @@ -10,7 +10,6 @@ use Magento\Catalog\Test\Page\Product\CatalogProductCompare; use Magento\Catalog\Test\Page\Product\CatalogProductView; use Magento\Cms\Test\Page\CmsIndex; use Magento\Customer\Test\Fixture\Customer; -use Magento\Customer\Test\Page\CustomerAccountLogin; use Magento\Mtf\Client\BrowserInterface; use Magento\Mtf\Constraint\AbstractConstraint; use Magento\Mtf\Fixture\FixtureFactory; @@ -59,13 +58,6 @@ abstract class AbstractCompareProductsTest extends Injectable */ protected $catalogProductView; - /** - * Customer login page. - * - * @var CustomerAccountLogin - */ - protected $customerAccountLogin; - /** * Fixture factory. * @@ -100,18 +92,15 @@ abstract class AbstractCompareProductsTest extends Injectable * @param CmsIndex $cmsIndex * @param CatalogProductView $catalogProductView * @param BrowserInterface $browser - * @param CustomerAccountLogin $customerAccountLogin * @return void */ public function __inject( CmsIndex $cmsIndex, CatalogProductView $catalogProductView, - BrowserInterface $browser, - CustomerAccountLogin $customerAccountLogin + BrowserInterface $browser ) { $this->cmsIndex = $cmsIndex; $this->catalogProductView = $catalogProductView; - $this->customerAccountLogin = $customerAccountLogin; $this->browser = $browser; } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..dc239565c49d01471c82b5b1a62c17ae0244605e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.php @@ -0,0 +1,83 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\TestCase\Product; + +use Magento\Catalog\Test\Constraint\AssertProductCompareSuccessAddMessage; +use Magento\Catalog\Test\Page\Product\CatalogProductCompare; + +/** + * Preconditions: + * 1. All product types are created. + * 2. Customer created. + * + * Steps: + * 1. Navigate to front-end. + * 1.1 If present data for customer, login as test customer. + * 2. Open product page of test product(s) and click "Add to Compare" button. + * 3. Assert success message is present on page. + * 4. Navigate to compare page(click "compare product" link at the top of the page). + * 5. Perform all asserts. + * + * @group Compare_Products_(MX) + * @ZephyrId MAGETWO-25843 + */ +class AddCompareProductsTest extends AbstractCompareProductsTest +{ + /* tags */ + const MVP = 'yes'; + const DOMAIN = 'MX'; + /* end tags */ + + /** + * Catalog product compare page. + * + * @var CatalogProductCompare + */ + protected $catalogProductCompare; + + /** + * Test creation for adding compare products. + * + * @param string $products + * @param string $requireCustomerLogin + * @param AssertProductCompareSuccessAddMessage $assertProductCompareSuccessAddMessage + * @param CatalogProductCompare $catalogProductCompare + * @return array + */ + public function test( + $products, + $requireCustomerLogin, + AssertProductCompareSuccessAddMessage $assertProductCompareSuccessAddMessage, + CatalogProductCompare $catalogProductCompare + ) { + //Steps + $this->catalogProductCompare = $catalogProductCompare; + $this->cmsIndex->open(); + if ($requireCustomerLogin == 'Yes') { + $this->loginCustomer(); + } + $this->products = $this->createProducts($products); + $this->addProducts($this->products, $assertProductCompareSuccessAddMessage); + $this->cmsIndex->getLinksBlock()->openLink("Compare Products"); + + return ['products' => $this->products]; + } + + /** + * Clear data after test. + * + * @return void + */ + public function tearDown() + { + $this->cmsIndex->open(); + $this->cmsIndex->getLinksBlock()->openLink("Compare Products"); + for ($i = 1; $i <= count($this->products); $i++) { + $this->catalogProductCompare->getCompareProductsBlock()->removeProduct(); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..de2da8b34bbf2b06162b4a41f0ea30a95d571dbb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddCompareProductsTest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Catalog\Test\TestCase\Product\AddCompareProductsTest" summary="Add Products to Compare" ticketId="MAGETWO-25843"> + <variation name="AddCompareProductsTestVariation1"> + <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products</data> + <data name="requireCustomerLogin" xsi:type="string">No</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLink" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductComparePage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareBlockOnCmsPage" /> + </variation> + <variation name="AddCompareProductsTestVariation2"> + <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,bundleProduct::bundle_dynamic_product</data> + <data name="requireCustomerLogin" xsi:type="string">No</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLink" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductComparePage" /> + </variation> + <variation name="AddCompareProductsTestVariation3"> + <data name="products" xsi:type="string">configurableProduct::default</data> + <data name="requireCustomerLogin" xsi:type="string">Yes</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLink" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductComparePage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareBlockOnCmsPage" /> + </variation> + <variation name="AddCompareProductsTestVariation4"> + <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product</data> + <data name="requireCustomerLogin" xsi:type="string">Yes</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLink" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductComparePage" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3556fa00a838820d65e20d642037d4260e344bc3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\TestCase\Product; + +use Magento\Config\Test\Fixture\ConfigData; +use Magento\Customer\Test\Page\CustomerAccountIndex; + +/** + * Preconditions: + * 1. All product types are created. + * 2. Customer created. + * + * Steps: + * 1. Login to frontend. + * 2. Add to Compare Product $products. + * 3. Navigate to My Account page. + * 4. Click "Clear All" icon under the left menu tabs. + * 5. Perform assertions. + * + * @group Compare_Products_(MX) + * @ZephyrId MAGETWO-25961 + */ +class ClearAllCompareProductsTest extends AbstractCompareProductsTest +{ + /* tags */ + const MVP = 'yes'; + const DOMAIN = 'MX'; + /* end tags */ + + /** + * Test creation for clear all compare products. + * + * @param string $products + * @param ConfigData $config + * @param CustomerAccountIndex $customerAccountIndex + * @return void + */ + public function test($products, ConfigData $config, CustomerAccountIndex $customerAccountIndex) + { + // Preconditions + $config->persist(); + $products = $this->createProducts($products); + + //Steps + $this->cmsIndex->open(); + $this->loginCustomer(); + $this->addProducts($products); + $this->cmsIndex->getLinksBlock()->openLink("My Account"); + $customerAccountIndex->getCompareProductsBlock()->clickClearAll(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..e9fa3f36b002f74ec2d77bc1b2a0b53fc6e611bd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Catalog\Test\TestCase\Product\ClearAllCompareProductsTest" summary="Clear All Compare Products" ticketId="MAGETWO-25961"> + <variation name="ClearAllCompareProductsTestVariation1"> + <data name="config/dataset" xsi:type="string">compare_products</data> + <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareSuccessRemoveAllProductsMessage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLinkIsAbsent" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareRemoveLastProductMessage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInCompareBlock" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.xml index df25c659478dd74b2a51cf6310de409821728db5..eebe1b345306abff05d6cbf2be3babc694bc0a7c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.xml @@ -40,16 +40,14 @@ <data name="description" xsi:type="string">Create product with out of stock</data> <data name="product/data/url_key" xsi:type="string">virtual-product-%isolation%</data> <data name="product/data/name" xsi:type="string">VirtualProduct %isolation%</data> - <data name="product/data/sku" xsi:type="string">virtual_sku_%isolation%</data> <data name="product/data/price/value" xsi:type="string">10</data> <data name="product/data/tax_class_id/dataset" xsi:type="string">taxable_goods</data> <data name="product/data/quantity_and_stock_status/qty" xsi:type="string">999</data> + <data name="product/data/quantity_and_stock_status/is_in_stock" xsi:type="string">In Stock</data> <data name="product/data/is_virtual" xsi:type="string">Yes</data> <data name="product/data/price/dataset" xsi:type="string">MAGETWO-23030</data> - <data name="product/data/quantity_and_stock_status/is_in_stock" xsi:type="string">Out of Stock</data> <data name="product/data/visibility" xsi:type="string">Search</data> <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" /> - <constraint name="Magento\Catalog\Test\Constraint\AssertProductForm" /> <constraint name="Magento\Catalog\Test\Constraint\AssertProductSkuAutoGenerated" /> <constraint name="Magento\Catalog\Test\Constraint\AssertProductSearchableBySku" /> </variation> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c4771496cc0883bd64a33cce1f967517ae23babd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php @@ -0,0 +1,97 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\TestCase\Product; + +use Magento\Catalog\Test\Page\Product\CatalogProductCompare; +use Magento\Customer\Test\Fixture\Customer; +use Magento\Mtf\Fixture\FixtureFactory; + +/** + * Preconditions: + * 1. All product types are created. + * 2. Customer created. + * + * Steps: + * 1. Add to Compare Product $products. + * 2. Navigate to Compare Product page. + * 3. Click (X) icon near the $product from dataset. + * 4. Perform assertions. + * + * @group Compare_Products_(MX) + * @ZephyrId MAGETWO-26161 + */ +class DeleteCompareProductsTest extends AbstractCompareProductsTest +{ + /* tags */ + const MVP = 'yes'; + const DOMAIN = 'MX'; + /* end tags */ + + /** + * Catalog product compare page. + * + * @var CatalogProductCompare + */ + protected $catalogProductCompare; + + /** + * Prepare data. + * + * @param FixtureFactory $fixtureFactory + * @param Customer $customer + * @return void + */ + public function __prepare(FixtureFactory $fixtureFactory, Customer $customer) + { + parent::__prepare($fixtureFactory, $customer); + $config = $this->fixtureFactory->createByCode('configData', ['dataset' => 'compare_products']); + $config->persist(); + } + + /** + * Test creation for delete product from compare products list. + * + * @param string $products + * @param string $removeProductIndex + * @param string $requireCustomerLogin + * @param CatalogProductCompare $catalogProductCompare + * @return array + */ + public function test( + $products, + $removeProductIndex, + $requireCustomerLogin, + CatalogProductCompare $catalogProductCompare + ) { + //Steps + $this->catalogProductCompare = $catalogProductCompare; + $this->cmsIndex->open(); + if ($requireCustomerLogin == 'Yes') { + $this->loginCustomer(); + } + $this->products = $this->createProducts($products); + $this->addProducts($this->products); + $this->cmsIndex->getLinksBlock()->openLink("Compare Products"); + $this->catalogProductCompare->getCompareProductsBlock()->removeProduct($removeProductIndex); + + return ['product' => $this->products[$removeProductIndex - 1], 'countProducts' => count($this->products)]; + } + + /** + * Clear data after test. + * + * @return void + */ + public function tearDown() + { + if (count($this->products) > 1) { + $this->cmsIndex->open(); + $this->cmsIndex->getLinksBlock()->openLink("Compare Products"); + $this->catalogProductCompare->getCompareProductsBlock()->removeAllProducts(); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..78a9e6af18713cfeb28a365f8926257bbc8b002c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Catalog\Test\TestCase\Product\DeleteCompareProductsTest" summary="Delete Compare Products" ticketId="MAGETWO-26161"> + <variation name="DeleteCompareProductsTestVariation1"> + <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product</data> + <data name="removeProductIndex" xsi:type="string">1</data> + <data name="requireCustomerLogin" xsi:type="string">No</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareSuccessRemoveMessage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInComparePage" /> + </variation> + <variation name="DeleteCompareProductsTestVariation2"> + <data name="products" xsi:type="string">catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product</data> + <data name="removeProductIndex" xsi:type="string">6</data> + <data name="requireCustomerLogin" xsi:type="string">Yes</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareSuccessRemoveMessage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInComparePage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInCompareBlock" /> + </variation> + <variation name="DeleteCompareProductsTestVariation3"> + <data name="products" xsi:type="string">bundleProduct::bundle_dynamic_product</data> + <data name="removeProductIndex" xsi:type="string">1</data> + <data name="requireCustomerLogin" xsi:type="string">Yes</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareSuccessRemoveMessage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareRemoveLastProductMessage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductIsNotVisibleInCompareBlock" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductCompareItemsLinkIsAbsent" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php index 740497bffb148aea85ca2c32ffe264e9e33cc4e4..b2773dc7964231e523110427a6afac9a22920e1b 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php @@ -78,7 +78,7 @@ class AdvancedSearchEntityTest extends Injectable AdvancedSearch $searchPage ) { $cmsIndex->open(); - $cmsIndex->getSearchBlock()->clickAdvancedSearchButton(); + $cmsIndex->getFooterBlock()->openAdvancedSearch(); $searchForm = $searchPage->getForm(); $searchForm->fill($productSearch); $searchForm->submit(); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php index 5d12b4575d9adc26f53cb67398eb84941db42375..22256fed04b100e1cf8f89ccc6f3f6b2ac850194 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php @@ -16,13 +16,13 @@ use Magento\Mtf\Fixture\FixtureInterface; /** * Class Cart - * Shopping cart block + * Shopping Cart block */ class Cart extends Block { // @codingStandardsIgnoreStart /** - * Selector for cart item block + * Locator value for correspondent "Shopping Cart item" block. * * @var string */ @@ -30,42 +30,56 @@ class Cart extends Block // @codingStandardsIgnoreEnd /** - * Proceed to checkout block + * Locator value for "Proceed to One Page Checkout" block. * * @var string */ protected $onepageLinkBlock = '.action.primary.checkout'; /** - * 'Clear Shopping Cart' button + * Locator value for "Clear Shopping Cart" button. * * @var string */ protected $clearShoppingCart = '#empty_cart_button'; /** - * 'Update Shopping Cart' button + * Locator value for "Update Shopping Cart" button. * * @var string */ protected $updateShoppingCart = '.update[name="update_cart_action"]'; /** - * Cart empty block selector + * Locator value for "Check out with PayPal" button. + * + * @var string + */ + protected $paypalCheckoutButton = '[data-action=checkout-form-submit]'; + + /** + * Locator value for "empty Shopping Cart" block. * * @var string */ protected $cartEmpty = '.cart-empty'; /** - * Cart container selector + * Locator value for "Shopping Cart" container. * * @var string */ protected $cartContainer = '.cart-container'; /** - * Get cart item block + * Locator value for "Remove Product" button. + * + * @var string + */ + protected $deleteItemButton = '.action.action-delete'; + + /** + * Get Shopping Cart item. * * @param FixtureInterface $product * @return CartItem @@ -93,7 +107,7 @@ class Cart extends Block } /** - * Get proceed to checkout block + * Get "Proceed to One Page Checkout" block. * * @return Link */ @@ -105,17 +119,17 @@ class Cart extends Block } /** - * Press 'Check out with PayPal' button + * Click "Check out with PayPal" button. * * @return void */ public function paypalCheckout() { - $this->_rootElement->find('[data-action=checkout-form-submit]', Locator::SELECTOR_CSS)->click(); + $this->_rootElement->find($this->paypalCheckoutButton)->click(); } /** - * Returns the total discount price + * Get total discount Price value. * * @return string * @throws Exception @@ -135,20 +149,19 @@ class Cart extends Block } /** - * Clear shopping cart + * Clear Shopping Cart. * * @return void */ public function clearShoppingCart() { - $clearShoppingCart = $this->_rootElement->find($this->clearShoppingCart); - if ($clearShoppingCart->isVisible()) { - $clearShoppingCart->click(); + while (!$this->cartIsEmpty()) { + $this->_rootElement->find($this->deleteItemButton)->click(); } } /** - * Check if a product has been successfully added to the cart + * Check if Product is present in Shopping Cart or not. * * @param FixtureInterface $product * @return boolean @@ -159,27 +172,29 @@ class Cart extends Block } /** - * Update shopping cart + * Update Shopping Cart. * * @return void */ public function updateShoppingCart() { - $this->_rootElement->find($this->updateShoppingCart, Locator::SELECTOR_CSS)->click(); + $this->_rootElement->find($this->updateShoppingCart)->click(); } /** - * Check that cart is empty + * Check if Shopping Cart is empty or not. * * @return bool */ public function cartIsEmpty() { - return $this->_rootElement->find($this->cartEmpty, Locator::SELECTOR_CSS)->isVisible(); + return $this->_rootElement->find($this->cartEmpty)->isVisible(); } /** - * Wait while cart container is loaded + * Wait while Shopping Cart container is loaded. + * + * @return void */ public function waitCartContainerLoading() { diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php index f0d771fff09c7378b78e9e647f1313c4e22ffb5c..04f4d4569f94a3ab3b44d6f0015d6c92d9848167 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php @@ -58,18 +58,11 @@ class Sidebar extends Block protected $counterQty = '.minicart-wrapper .counter.qty'; /** - * Count product in cart block. + * Locator value for Mini Shopping Cart wrapper. * * @var string */ - protected $counterNumberBlock = '//*[@class="counter-number" and normalize-space(text()) != ""]'; - - /** - * Count product in cart wrapper. - * - * @var string - */ - protected $counterNumberWrapper = '/ancestor::*[@class="minicart-wrapper"]'; + protected $counterNumberWrapper = '.minicart-wrapper'; /** * Loading masc. @@ -157,10 +150,10 @@ class Sidebar extends Block public function waitInit() { $browser = $this->browser; - $selector = $this->counterNumberBlock . $this->counterNumberWrapper; + $selector = $this->counterNumberWrapper; $browser->waitUntil( function () use ($browser, $selector) { - $counterQty = $browser->find($selector, Locator::SELECTOR_XPATH); + $counterQty = $browser->find($selector); return $counterQty->isVisible() ? true : null; } ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml index 9e388b13f7aade6faf292d3dbd5ef0f26ca789f0..69ab253de55c0f0b4b797b3eaf5c61488a57cf4d 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml @@ -45,7 +45,7 @@ </variation> <variation name="AddProductsToShoppingCartEntityTestVariation5"> <data name="productsData" xsi:type="string">configurableProduct::default</data> - <data name="cart/data/grand_total" xsi:type="string">360</data> + <data name="cart/data/grand_total" xsi:type="string">120</data> <constraint name="Magento\Checkout\Test\Constraint\AssertPriceInShoppingCart" /> <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" /> <constraint name="Magento\Checkout\Test\Constraint\AssertSubtotalInShoppingCart" /> @@ -72,7 +72,7 @@ </variation> <variation name="AddProductsToShoppingCartEntityTestVariation8"> <data name="productsData" xsi:type="string">catalogProductSimple::with_two_custom_option, catalogProductVirtual::product_50_dollar, downloadableProduct::with_two_separately_links, groupedProduct::three_simple_products, configurableProduct::default, bundleProduct::bundle_dynamic_product, bundleProduct::bundle_dynamic_product</data> - <data name="cart/data/grand_total" xsi:type="string">3092.43</data> + <data name="cart/data/grand_total" xsi:type="string">2852.43</data> <constraint name="Magento\Checkout\Test\Constraint\AssertPriceInShoppingCart" /> <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" /> <constraint name="Magento\Checkout\Test\Constraint\AssertSubtotalInShoppingCart" /> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php index 39951aa818cde6da5d54b8735e6a16bf044357a7..57963c6e28ce6e3696e0472b1e945d42a2b67bc3 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php @@ -102,6 +102,7 @@ class UpdateShoppingCartTest extends Injectable { // Preconditions $product->persist(); + $this->checkoutCart->open(); $this->checkoutCart->getCartBlock()->clearShoppingCart(); // Steps diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml index f6d62c1f0ffc7d482cd135ad9c94b095ba407d30..94be490f81adc65a229701a7794ae5747679b139 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml @@ -14,7 +14,6 @@ <block name="linksBlock" class="Magento\Theme\Test\Block\Links" locator=".header .links" strategy="css selector" /> <block name="storeSwitcherBlock" class="Magento\Store\Test\Block\Switcher" locator="[data-ui-id='language-switcher']" strategy="css selector" /> <block name="cartSidebarBlock" class="Magento\Checkout\Test\Block\Cart\Sidebar" locator="[data-block='minicart']" strategy="css selector" /> - <block name="compareProductsBlock" class="Magento\Catalog\Test\Block\Product\Compare\Sidebar" locator=".sidebar.sidebar-additional" strategy="css selector" /> <block name="currencyBlock" class="Magento\Directory\Test\Block\Currency\Switcher" locator=".switcher.currency" strategy="css selector" /> <block name="cmsPageBlock" class="Magento\Cms\Test\Block\Page" locator=".page-main" strategy="css selector" /> <block name="widgetView" class="Magento\Widget\Test\Block\WidgetView" locator=".widget" strategy="css selector" /> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml index 6dc0342a5e44e5ab234c8ff2e5a3a7e2f2ab65b7..4f058ad0611c0f5eff12d181acb7607d920361a5 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml @@ -22,9 +22,9 @@ </field> <field name="qty" xsi:type="string">3</field> <field name="cartItem" xsi:type="array"> - <item name="price" xsi:type="string">120</item> + <item name="price" xsi:type="string">40</item> <item name="qty" xsi:type="string">3</item> - <item name="subtotal" xsi:type="string">360</item> + <item name="subtotal" xsi:type="string">120</item> </field> </dataset> diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php index fe690d7c18ca71cc0b370ae05952bbb7ae71a341..8d89091816aa5a217f385b50ce31bbd0fb205ac7 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php @@ -63,13 +63,13 @@ class RegisterCustomerFrontendEntityTest extends Injectable } /** - * Create Customer account on frontend + * Create Customer account on Storefront. * * @param Customer $customer */ public function test(Customer $customer) { - //Steps + // Steps $this->cmsIndex->open(); $this->cmsIndex->getLinksBlock()->openLink('Create an Account'); $this->customerAccountCreate->getRegisterForm()->registerCustomer($customer); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/LogoutCustomerOnFrontendStep.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/LogoutCustomerOnFrontendStep.php index 1ff30b1dcdf030fedef0e289d4b4d6c8076fc2f3..63399666bbc44a8ccd21371b6df5c5813bb2cf3e 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/LogoutCustomerOnFrontendStep.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/LogoutCustomerOnFrontendStep.php @@ -54,7 +54,7 @@ class LogoutCustomerOnFrontendStep implements TestStepInterface { $this->customerAccount->open(); $this->cmsIndex->getCmsPageBlock()->waitPageInit(); - if ($this->cmsIndex->getLinksBlock()->isLinkVisible('Sign Out')) { + if ($this->cmsIndex->getTitleBlock()->getTitle() != 'Customer Login') { $this->cmsIndex->getLinksBlock()->openLink('Sign Out'); $this->cmsIndex->getCmsPageBlock()->waitUntilTextIsVisible('Home Page'); $this->cmsIndex->getCmsPageBlock()->waitPageInit(); diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php index e6de2178a4eeb04931bdebd038cf099513be41dd..100e32be0b442bb783891793ab88d2eb7725cda9 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php @@ -25,7 +25,7 @@ class AssertLanguageSelected extends AbstractConstraint { $indexPage->open(); \PHPUnit_Framework_Assert::assertTrue( - $indexPage->getLinksBlock()->isLinkVisible($languageTemplate), + $indexPage->getFooterBlock()->isLinkVisible($languageTemplate), 'Selected language not displays on frontend.' ); } diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php index 4dfa6dd2122c10aa6a7344210cd47d10985551c0..602316510e825dda680c14eb39eaff5f18a04f45 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php @@ -15,63 +15,76 @@ use Magento\Mtf\Client\Locator; class Navigation extends Block { /** - * 'Clear All' link. + * Locator value for "Clear All" link. * * @var string */ protected $clearAll = '.action.clear'; /** - * Attribute option title selector. + * Locator value for correspondent Attribute filter option. * * @var string */ - protected $optionTitle = '.filter-options-title'; + protected $optionTitle = './/div[@class="filter-options-title" and contains(text(),"%s")]'; /** - * Filter link locator. + * Locator value for correspondent "Filter" link. * * @var string */ - protected $filterLink = './/dt[contains(text(),"%s")]/following-sibling::dd//a'; + protected $filterLink = './/div[@class="filter-options-title" and contains(text(),"%s")]/following-sibling::div//a'; /** - * Click on 'Clear All' link. + * Locator value for "Expand Filter" button. + * + * @var string + */ + protected $expandFilterButton = '[data]'; + + /** + * Remove all applied filters. * * @return void */ public function clearAll() { - $this->_rootElement->find($this->clearAll, locator::SELECTOR_CSS)->click(); + $this->_rootElement->find($this->clearAll)->click(); } /** - * Get array of available filters. + * Get all available filters. * * @return array */ public function getFilters() { - $options = $this->_rootElement->getElements($this->optionTitle); + $options = $this->_rootElement->getElements(sprintf($this->optionTitle, ''), Locator::SELECTOR_XPATH); $data = []; foreach ($options as $option) { - $data[] = $option->getText(); + $data[] = strtoupper($option->getText()); } return $data; } /** - * Click filter link. + * Apply Layerd Navigation filter. * * @param string $filter * @param string $linkPattern * @return void * @throws \Exception */ - public function clickFilterLink($filter, $linkPattern) + public function applyFilter($filter, $linkPattern) { - $links = $this->_rootElement->getElements(sprintf($this->filterLink, $filter), Locator::SELECTOR_XPATH); + $expandFilterButton = sprintf($this->optionTitle, $filter); + $links = sprintf($this->filterLink, $filter); + + if (!$this->_rootElement->find($links, Locator::SELECTOR_XPATH)->isVisible()) { + $this->_rootElement->find($expandFilterButton, Locator::SELECTOR_XPATH)->click(); + } + $links = $this->_rootElement->getElements($links, Locator::SELECTOR_XPATH); foreach ($links as $link) { if (preg_match($linkPattern, trim($link->getText()))) { $link->click(); diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php index e2b384a26611026f3c353fd7d8f7185ecab99143..9d840ff45dd61853c222e5b107f4ecc5febe5466 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php @@ -44,7 +44,7 @@ class AssertFilterProductList extends AbstractConstraint foreach ($layeredNavigation as $filters) { foreach ($filters as $filter) { - $catalogCategoryView->getLayeredNavigationBlock()->clickFilterLink( + $catalogCategoryView->getLayeredNavigationBlock()->applyFilter( $filter['title'], $filter['linkPattern'] ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php index 2ebb040791cdcecaa3a26ee06e26494ce04919ce..01a177c91ccad192574b772fd1ccda355d2ab285 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php @@ -10,20 +10,19 @@ use Magento\Backend\Test\Block\Widget\Tab; use Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\CreditMemos\Grid; /** - * Class CreditMemos - * CreditMemos tab + * CreditMemos tab. */ class CreditMemos extends Tab { /** - * Grid block css selector + * Grid block css selector. * * @var string */ protected $grid = '#sales_order_view_tabs_order_creditmemos_content'; /** - * Get grid block + * Get grid block. * * @return Grid */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php index 38b4e2344fd4b0701b29b9a519d8280090ca5155..9e5725bcf5c0582afbb0ec09fb460052d8cafcf6 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php @@ -10,20 +10,19 @@ use Magento\Backend\Test\Block\Widget\Tab; use Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Shipments\Grid; /** - * Class Shipments - * Shipments tab + * Shipments tab. */ class Shipments extends Tab { /** - * Grid block css selector + * Grid block css selector. * * @var string */ protected $grid = '#sales_order_view_tabs_order_shipments_content'; /** - * Get grid block + * Get grid block. * * @return Grid */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/PrintOrderOnFrontendStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/PrintOrderOnFrontendStep.php index a810a3ca608a2cd7927e12316d731b3b4ce47d4a..e520d538cc7570b669fe2d936fe783acc45d1e31 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/PrintOrderOnFrontendStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/PrintOrderOnFrontendStep.php @@ -47,7 +47,7 @@ class PrintOrderOnFrontendStep implements TestStepInterface */ public function run() { - $this->salesGuestView->getActionsToolbar()->clickLink('Print Order'); + $this->salesGuestView->getActionsToolbar()->clickLink('Print'); $this->browser->selectWindow(); } } diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Footer.php b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Footer.php index 4781f506ae0c8482e49c7aaf1ab5113acb5c54c6..6af2b23db6f578deadf9942fa1221008d02c5f70 100644 --- a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Footer.php +++ b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Footer.php @@ -12,47 +12,54 @@ use Magento\Store\Test\Fixture\Store; /** * Footer block - * CmsIndex page footer block + * CmsIndex page Footer block */ class Footer extends Block { /** - * Link selector + * Locator value for correspondent link. * * @var string */ protected $linkSelector = '//*[contains(@class, "links")]//a[contains(text(), "%s")]'; /** - * Variable selector + * Locator value for variable. * * @var string */ protected $variableSelector = './/ul[contains(@class, "links")]/*[text()="%s"]'; /** - * Store group dropdown selector + * Locator value for "Store group" dropdown. * * @var string */ protected $storeGroupDropdown = '.switcher.store'; /** - * Store Group switch selector + * Locator value for "Store group" switcher. * * @var string */ protected $storeGroupSwitch = '[data-toggle="dropdown"]'; /** - * Store group selector + * Locator value for correspondent Store group. * * @var string */ protected $storeGroupSelector = './/a[contains(.,"%s")]'; /** - * Click on link by name + * Locator value for "Advanced Search" link. + * + * @var string + */ + protected $advancedSearchSelector = '[data-action="advanced-search"]'; + + /** + * Click on link by its title. * * @param string $linkName * @return void @@ -68,7 +75,18 @@ class Footer extends Block } /** - * Check Variable visibility by html value + * Check is link is visible. + * + * @param string $linkName + * @return bool + */ + public function isLinkVisible($linkName) + { + return $this->_rootElement->find(sprintf($this->linkSelector, $linkName), Locator::SELECTOR_XPATH)->isVisible(); + } + + /** + * Check Variable visibility by html value. * * @param string $htmlValue * @return bool @@ -82,7 +100,7 @@ class Footer extends Block } /** - * Select store group + * Select Store group. * * @param Store $store * @return void @@ -102,7 +120,7 @@ class Footer extends Block } /** - * Check if store visible in dropdown + * Check if correspondent "Store" is present in "Store" swither or not. * * @param Store $store * @return bool @@ -118,7 +136,7 @@ class Footer extends Block } /** - * Check if store group switcher is visible + * Check if "Store" switcher is visible or not. * * @return bool */ @@ -126,4 +144,14 @@ class Footer extends Block { return $this->_rootElement->find($this->storeGroupSwitch)->isVisible(); } + + /** + * Open Advanced Search. + * + * @return void + */ + public function openAdvancedSearch() + { + $this->_rootElement->find($this->advancedSearchSelector)->click(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php index 027b1ca6ec7fff352865e5d0a001e059f4044372..3375541068cb1264e5054958cc449dc7871bc8b9 100644 --- a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php +++ b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php @@ -15,50 +15,72 @@ use Magento\Mtf\Client\Locator; class Links extends Block { /** - * Selector for qty products on compare. + * Locator value for correspondent link. * * @var string */ - protected $qtyCompareProducts = '.compare .counter.qty'; + protected $link = '//a[contains(text(), "%s")]'; /** - * Link selector. + * Locator value for welcome message. * * @var string */ - protected $link = '//a[contains(text(), "%s")]'; + protected $welcomeMessage = '.greet.welcome'; /** - * Welcome message on frontend. + * Locator value for "Expand/Collapse Customer Menu" button. * * @var string */ - protected $welcomeMessage = '.greet.welcome'; + protected $toggleButton = '[data-action="customer-menu-toggle"]'; + + /** + * Locator value for Customer Menu. + * + * @var string + */ + protected $customerMenu = '.customer-menu > ul'; /** - * Open Link by title. + * Expand Customer Menu (located in page Header) if it was collapsed. + * + * @return void + */ + protected function expandCustomerMenu() + { + $this->_rootElement->find($this->toggleButton)->click(); + } + + /** + * Open link by its title. * * @param string $linkTitle * @return void */ public function openLink($linkTitle) { - $this->_rootElement->find(sprintf($this->link, $linkTitle), Locator::SELECTOR_XPATH)->click(); + $link = $this->_rootElement->find(sprintf($this->link, $linkTitle), Locator::SELECTOR_XPATH); + if (!$link->isVisible()) { + $this->expandCustomerMenu(); + } + $link->click(); } /** - * Is visible Link by title. + * Verify if correspondent link is present or not. * * @param string $linkTitle * @return bool */ public function isLinkVisible($linkTitle) { + $this->expandCustomerMenu(); return $this->_rootElement->find(sprintf($this->link, $linkTitle), Locator::SELECTOR_XPATH)->isVisible(); } /** - * Wait for link is visible. + * Wait until correspondent link appears. * * @param string $linkTitle * @return void @@ -75,19 +97,6 @@ class Links extends Block ); } - /** - * Get the number of products added to compare list. - * - * @return string - */ - public function getQtyInCompareList() - { - $this->waitForElementVisible($this->qtyCompareProducts); - $compareProductLink = $this->_rootElement->find($this->qtyCompareProducts); - preg_match_all('/^\d+/', $compareProductLink->getText(), $matches); - return $matches[0][0]; - } - /** * Get url from link. * @@ -103,7 +112,7 @@ class Links extends Block } /** - * Waiter for welcome message. + * Wait until welcome message appears. * * @return void */ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php index e887766535ed3492f5838b291c96f8c8ce0f111a..a624d4f71de5f06a941703060b9d07e08e4a9885 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php @@ -59,7 +59,7 @@ class AssertWidgetCatalogCategoryLink extends AbstractConstraint 'Wrong category title.' ); - $cmsIndex->getSearchBlock()->clickAdvancedSearchButton(); + $cmsIndex->getFooterBlock()->openAdvancedSearch(); \PHPUnit_Framework_Assert::assertTrue( $cmsIndex->getWidgetView()->isWidgetVisible($widget, $widgetText), 'Widget with type catalog category link is absent on Advanced Search page.' diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php index 3cce4ea17193c0e3e17694a1f1062b8a4dfe0c4a..8d3170aebc9046cde9879841275c062b75b8f646 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php @@ -54,7 +54,7 @@ class AssertWidgetCmsPageLink extends AbstractConstraint 'Wrong page title on Cms page.' ); - $cmsIndex->getSearchBlock()->clickAdvancedSearchButton(); + $cmsIndex->getFooterBlock()->openAdvancedSearch(); \PHPUnit_Framework_Assert::assertTrue( $cmsIndex->getWidgetView()->isWidgetVisible($widget, $widgetText), 'Widget with type CmsPageLink is absent on Advanced Search page.' diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml index c7c75cfb643531869c405862af0b92733dca5b56..a43376e87102219babd18a568469a8c36bd3526a 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml @@ -10,7 +10,7 @@ <dataset name="default"> <field name="code" xsi:type="string">CMS Page Link</field> <field name="title" xsi:type="string">Cms Page Link %isolation%</field> - <field name="theme_id" xsi:type="string">Magento Blank</field> + <field name="theme_id" xsi:type="string">Magento Luma</field> <field name="store_ids" xsi:type="array"> <item name="dataset" xsi:type="string">all_store_views</item> </field> diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml index fdebafbc3af35b95f6dfacff69338fd25d56b4d0..c46bc78fda62b210b168c22b4d9c1b02dee53779 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml @@ -9,7 +9,7 @@ <testCase name="Magento\Widget\Test\TestCase\CreateWidgetEntityTest" summary="Create Widget (Frontend Apps)" ticketId="MAGETWO-27916"> <variation name="CreateWidgetEntityTestVariation1"> <data name="widget/data/code" xsi:type="string">CMS Static Block</data> - <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data> + <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data> <data name="widget/data/title" xsi:type="string">Title_%isolation%</data> <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data> <data name="widget/data/widget_instance/dataset" xsi:type="string">on_category</data> @@ -20,7 +20,7 @@ </variation> <variation name="CreateWidgetEntityTestVariation2"> <data name="widget/data/code" xsi:type="string">CMS Page Link</data> - <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data> + <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data> <data name="widget/data/title" xsi:type="string">Title_%isolation%</data> <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data> <data name="widget/data/widget_instance/dataset" xsi:type="string">for_cms_page_link</data> @@ -31,7 +31,7 @@ </variation> <variation name="CreateWidgetEntityTestVariation3"> <data name="widget/data/code" xsi:type="string">Recently Viewed Products</data> - <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data> + <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data> <data name="widget/data/title" xsi:type="string">Title_%isolation%</data> <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data> <data name="widget/data/widget_instance/dataset" xsi:type="string">for_viewed_products</data> @@ -42,7 +42,7 @@ </variation> <variation name="CreateWidgetEntityTestVariation4"> <data name="widget/data/code" xsi:type="string">Recently Compared Products</data> - <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data> + <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data> <data name="widget/data/title" xsi:type="string">Title_%isolation%</data> <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data> <data name="widget/data/widget_instance/dataset" xsi:type="string">for_compared_products</data> @@ -53,7 +53,7 @@ </variation> <variation name="CreateWidgetEntityTestVariation5"> <data name="widget/data/code" xsi:type="string">Catalog Category Link</data> - <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data> + <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data> <data name="widget/data/title" xsi:type="string">Title_%isolation%</data> <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data> <data name="widget/data/widget_instance/dataset" xsi:type="string">for_category_link</data> @@ -64,7 +64,7 @@ </variation> <variation name="CreateWidgetEntityTestVariation6"> <data name="widget/data/code" xsi:type="string">Catalog Product Link</data> - <data name="widget/data/theme_id" xsi:type="string">Magento Blank</data> + <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data> <data name="widget/data/title" xsi:type="string">Title_%isolation%</data> <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data> <data name="widget/data/widget_instance/dataset" xsi:type="string">on_product_link</data> diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.php index df69f321c511977efb61b47e81358b03ec6888d7..0bc0507d993637ffe221abafbe2c508964fdfee6 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.php @@ -11,19 +11,19 @@ use Magento\Mtf\Client\Locator; /** * Class Product - * Wishlist item product form + * Wish List item Product form */ class Product extends Form { /** - * Selector for 'Add to Cart' button + * Locator value for "Add to Cart" button. * * @var string */ protected $addToCart = '.action.tocart'; /** - * Selector for 'Remove item' button + * Locator value for "Remove item" button. * * @var string */ @@ -37,74 +37,84 @@ class Product extends Form protected $viewDetails = '.details.tooltip'; /** - * Selector for 'Details block' element + * Locator value for "Details" block. * * @var string */ protected $detailsBlock = '.product-item-tooltip'; /** - * Edit button css selector + * Locator value for "Edit" button. * * @var string */ protected $edit = '.action.edit'; /** - * Selector for option's label + * Locator value for option's label. * * @var string */ protected $optionLabel = '.tooltip.content .label'; /** - * Selector for option's value + * Locator value for option's value. * * @var string */ protected $optionValue = '.tooltip.content .values'; /** - * Selector for click on footer block + * Locator value for Footer block. * * @var string */ protected $footer = './ancestor::body//footer'; /** - * Fill item product details + * Locator value for item Price. + * + * @var string + */ + protected $price = '.price'; + + /** + * Fill item with details. * * @param array $fields * @return void */ public function fillProduct(array $fields) { + $this->hoverProductBlock(); $mapping = $this->dataMapping($fields); $this->_fill($mapping); } /** - * Click button 'Add To Cart' + * Click "Add to Cart" button. * * @return void */ public function clickAddToCart() { + $this->hoverProductBlock(); $this->_rootElement->find($this->addToCart)->click(); } /** - * Remove product from wish list + * Remove item from Wish List. * * @return void */ public function remove() { + $this->hoverProductBlock(); $this->_rootElement->find($this->remove)->click(); } /** - * Get product options + * Get Product options. * * @return array|null */ @@ -134,17 +144,28 @@ class Product extends Form } /** - * Click edit button + * Click "Edit" button. * * @return void */ public function clickEdit() { + $this->hoverProductBlock(); $this->_rootElement->find($this->edit)->click(); } /** - * Get wishlist data for the product. + * Hover Product block so that possible actions appear. + * + * @return void + */ + public function hoverProductBlock() + { + $this->_rootElement->find($this->price)->click(); + } + + /** + * Get Wish List data for the Product. * * @param mixed $qty * @return array diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php index 1f31bde19a817f5c4888d8fe3faee5edbf6d67be..172ba1389b391a03d3d0da01d79f83e321eb5c29 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php @@ -11,7 +11,31 @@ $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( 'Magento\Catalog\Model\Resource\Eav\Attribute' ); -$attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'attribute_with_option'); +$attribute->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'attribute_with_option'); + +/* Delete simple products per each option */ +/** @var $options \Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection */ +$options = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection' +); +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry'); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +$options->setAttributeFilter($attribute->getId()); + +foreach ($options as $option) { + /** @var $product \Magento\Catalog\Model\Product */ + $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product'); + $product = $product->loadByAttribute('sku', 'simple_product_' . $option->getId()); + if ($product->getId()) { + $product->delete(); + } +} + if ($attribute->getId()) { $attribute->delete(); } + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php index d719463f60ad96888d041073905bc7092420ed74..01b7f93ad982137e8d62277d45d8eb86919275cf 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php @@ -99,7 +99,7 @@ class CartTest extends \PHPUnit_Framework_TestCase $html = $this->_block->toHtml(); $this->assertContains("<div id=\"customer_cart_grid\"", $html); $this->assertContains("<div class=\"admin__data-grid-header admin__data-grid-toolbar\"", $html); - $this->assertContains("customer_cart_gridJsObject = new varienGrid('customer_cart_grid',", $html); + $this->assertContains("customer_cart_gridJsObject = new varienGrid(\"customer_cart_grid\",", $html); $this->assertContains( "backend/customer/cart_product_composite_cart/configure/customer_id/" . self::CUSTOMER_ID_VALUE, $html diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php index 5bbdca87782a224ea4e59558e12e1231b5c26ddd..5e7361b26cfda79f70348f48503466e9d9f0b390 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php @@ -61,7 +61,7 @@ class CartsTest extends \PHPUnit_Framework_TestCase '/<div class=".*admin__data-grid-toolbar"/', $html ); - $this->assertContains("customer_cart_grid1JsObject = new varienGrid('customer_cart_grid1',", $html); + $this->assertContains("customer_cart_grid1JsObject = new varienGrid(\"customer_cart_grid1\",", $html); $this->assertContains("backend/customer/cart_product_composite_cart/configure/website_id/1", $html); } @@ -84,7 +84,7 @@ class CartsTest extends \PHPUnit_Framework_TestCase '/<div class=".*admin__data-grid-toolbar"/', $html ); - $this->assertContains("customer_cart_gridJsObject = new varienGrid('customer_cart_grid',", $html); + $this->assertContains("customer_cart_gridJsObject = new varienGrid(\"customer_cart_grid\",", $html); $this->assertContains("backend/customer/cart_product_composite_cart/configure/key/", $html); } } diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php b/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php index ad3393695ad1babf0698758d786422f9613f73a7..d66a3ebcc0a64a6c134987f2bc8ea6f751671b26 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php @@ -123,7 +123,7 @@ class TemplateTest extends \PHPUnit_Framework_TestCase ->load(); $this->setNotDefaultThemeForFixtureStore(); - $expectedViewUrl = 'static/frontend/Magento/luma/en_US/Magento_Theme/favicon.ico'; + $expectedViewUrl = 'static/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico'; $this->model->setTemplateText('{{view url="Magento_Theme::favicon.ico"}}'); $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplate()); $this->model->setDesignConfig([ @@ -513,15 +513,18 @@ class TemplateTest extends \PHPUnit_Framework_TestCase */ protected function setNotDefaultThemeForFixtureStore() { - $theme = $this->objectManager->create('Magento\Framework\View\Design\ThemeInterface'); - $theme->load('Magento/luma', 'theme_path'); - $this->objectManager->get('Magento\Framework\App\Config\MutableScopeConfigInterface') - ->setValue( - DesignInterface::XML_PATH_THEME_ID, - $theme->getId(), - ScopeInterface::SCOPE_STORE, - 'fixturestore' - ); + $theme = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Framework\View\Design\ThemeInterface' + ); + $theme->load('Magento/blank', 'theme_path'); + \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + 'Magento\Framework\App\Config\MutableScopeConfigInterface' + )->setValue( + \Magento\Framework\View\DesignInterface::XML_PATH_THEME_ID, + $theme->getId(), + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + 'fixturestore' + ); } /** @@ -536,7 +539,7 @@ class TemplateTest extends \PHPUnit_Framework_TestCase ->load(); $this->setNotDefaultThemeForFixtureStore(); - $expectedViewUrl = 'static/frontend/Magento/luma/en_US/Magento_Theme/favicon.ico'; + $expectedViewUrl = 'static/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico'; $this->model->setTemplateSubject('{{view url="Magento_Theme::favicon.ico"}}'); $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplateSubject([])); $this->model->setDesignConfig([ @@ -560,7 +563,7 @@ class TemplateTest extends \PHPUnit_Framework_TestCase ->load(); $this->assertStringEndsWith( - 'static/frontend/Magento/blank/en_US/Magento_Email/logo_email.png', + 'static/frontend/Magento/luma/en_US/Magento_Email/logo_email.png', $this->model->getDefaultEmailLogo() ); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php index 04a82aafb8219f3114aa0266fe6ef2ec24f147bb..24cf533ddf5ca4517b325491545b4a0026bb9561 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php @@ -14,7 +14,27 @@ $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( 'Magento\Catalog\Model\Resource\Eav\Attribute' ); -$attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'select_attribute'); +$attribute->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'select_attribute'); + +/** @var $selectOptions \Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection */ +$selectOptions = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection' +); +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry'); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$selectOptions->setAttributeFilter($attribute->getId()); +/* Delete simple products per each select(dropdown) option */ +foreach ($selectOptions as $option) { + /** @var $product \Magento\Catalog\Model\Product */ + $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product'); + $product = $product->loadByAttribute('sku', 'simple_product_' . $option->getId()); + if ($product->getId()) { + $product->delete(); + } +} if ($attribute->getId()) { $attribute->delete(); } @@ -23,3 +43,6 @@ $attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'multisel if ($attribute->getId()) { $attribute->delete(); } + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php index 416e72ed185bd35179b80ab8699a8c343899bd7d..bee5e691d76d85b59bedb2c0e8df0b5b8c62368d 100644 --- a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php @@ -10,6 +10,7 @@ class AssociatedProductsCollectionTest extends \PHPUnit_Framework_TestCase /** * @magentoDataFixture Magento/GroupedProduct/_files/product_grouped.php * @magentoAppIsolation enabled + * @magentoDbIsolation disabled */ public function testGetColumnValues() { diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Model/TemplateTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Model/TemplateTest.php index d501af84c4c26266dff6331a627d6ab1aad6dd30..20a8c4fb5599d23ac409d513d1d2269f86ac1a80 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Model/TemplateTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Model/TemplateTest.php @@ -24,8 +24,8 @@ class TemplateTest extends \PHPUnit_Framework_TestCase /** * This test expects next themes for areas: - * current_store design/theme/full_name Magento/blank - * fixturestore_store design/theme/full_name Magento/luma + * current_store design/theme/full_name Magento/luma + * fixturestore_store design/theme/full_name Magento/blank * * @magentoAppIsolation enabled * @magentoAppArea adminhtml @@ -62,8 +62,8 @@ class TemplateTest extends \PHPUnit_Framework_TestCase public function getProcessedTemplateFrontendDataProvider() { return [ - 'frontend' => ['default', 'Magento/blank'], - 'frontend store' => ['fixturestore', 'Magento/luma'] + 'frontend' => ['default', 'Magento/luma'], + 'frontend store' => ['fixturestore', 'Magento/blank'] ]; } diff --git a/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php b/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php index 163b4ab3cd019ec4410edaebf94492a10e38e05b..99cb701eec3f576499260a2fce7ab75acdcc3797 100644 --- a/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php +++ b/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php @@ -7,8 +7,25 @@ */ namespace Magento\TestFramework\Dependency; -class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface +use Magento\Framework\App\Utility\Files; +use Magento\TestFramework\Dependency\RuleInterface; + +class PhpRule implements RuleInterface { + /** + * List of filepaths for DI files + * + * @var array + */ + private $diFiles; + + /** + * Map from plugin classes to the subjects they modify + * + * @var array + */ + private $pluginMap; + /** * List of routers * @@ -47,12 +64,14 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface * * @param array $mapRouters * @param array $mapLayoutBlocks + * @param array $pluginMap */ - public function __construct(array $mapRouters, array $mapLayoutBlocks) + public function __construct(array $mapRouters, array $mapLayoutBlocks, array $pluginMap = []) { $this->_mapRouters = $mapRouters; $this->_mapLayoutBlocks = $mapLayoutBlocks; $this->_namespaces = implode('|', \Magento\Framework\App\Utility\Files::init()->getNamespaces()); + $this->pluginMap = $pluginMap ?: null; } /** @@ -72,7 +91,7 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface $pattern = '~\b(?<class>(?<module>(' . implode( '_|', - \Magento\Framework\App\Utility\Files::init()->getNamespaces() + Files::init()->getNamespaces() ) . '[_\\\\])[a-zA-Z0-9]+)[a-zA-Z0-9_\\\\]*)\b~'; $dependenciesInfo = []; @@ -83,10 +102,16 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface if ($currentModule == $referenceModule) { continue; } + $dependencyClass = trim($matches['class'][$i]); + $currentClass = $this->getClassFromFilepath($file, $currentModule); + $dependencyType = $this->isPluginDependency($currentClass, $dependencyClass) + ? RuleInterface::TYPE_SOFT + : RuleInterface::TYPE_HARD; + $dependenciesInfo[] = [ 'module' => $referenceModule, - 'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_HARD, - 'source' => trim($matches['class'][$i]), + 'type' => $dependencyType, + 'source' => $dependencyClass, ]; } } @@ -102,6 +127,84 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface return $dependenciesInfo; } + /** + * Get class name from filename based on class/file naming conventions + * + * @param string $filepath + * @param string $module + * @return string + */ + private function getClassFromFilepath($filepath, $module) + { + $class = strstr($filepath, str_replace(['_', '\\', '/'], DIRECTORY_SEPARATOR, $module)); + $class = str_replace(DIRECTORY_SEPARATOR, '\\', strstr($class, '.php', true)); + return $class; + } + + /** + * @return array + * @throws \Exception + */ + private function loadDiFiles() + { + if (!$this->diFiles) { + $this->diFiles = Files::init()->getDiConfigs(); + } + return $this->diFiles; + } + + /** + * Generate an array of plugin info + * + * @return array + */ + private function loadPluginMap() + { + if (!$this->pluginMap) { + foreach ($this->loadDiFiles() as $filepath) { + $dom = new \DOMDocument(); + $dom->loadXML(file_get_contents($filepath)); + $typeNodes = $dom->getElementsByTagName('type'); + /** @var \DOMElement $type */ + foreach ($typeNodes as $type) { + /** @var \DOMElement $plugin */ + foreach ($type->getElementsByTagName('plugin') as $plugin) { + $subject = $type->getAttribute('name'); + $pluginType = $plugin->getAttribute('type'); + $this->pluginMap[$pluginType] = $subject; + } + } + } + } + return $this->pluginMap; + } + + /** + * Determine whether a the dependency relation is because of a plugin + * + * True IFF the dependent is a plugin for some class in the same module as the dependency. + * + * @param string $dependent + * @param string $dependency + * @return bool + */ + private function isPluginDependency($dependent, $dependency) + { + $pluginMap = $this->loadPluginMap(); + $subject = isset($pluginMap[$dependent]) + ? $pluginMap[$dependent] + : null; + if ($subject === $dependency) { + return true; + } else if ($subject) { + $subjectModule = substr($subject, 0, strpos($subject, '\\', 9)); // (strlen('Magento\\') + 1) === 9 + return strpos($dependency, $subjectModule) === 0; + } else { + return false; + } + } + + /** * Check get URL method * @@ -128,7 +231,7 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface foreach ($modules as $module) { $dependencies[] = [ 'module' => $module, - 'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_HARD, + 'type' => RuleInterface::TYPE_HARD, 'source' => $item['source'], ]; } @@ -166,7 +269,7 @@ class PhpRule implements \Magento\TestFramework\Dependency\RuleInterface $module = isset($check['module']) ? $check['module'] : null; if ($module) { $result[$module] = [ - 'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_HARD, + 'type' => RuleInterface::TYPE_HARD, 'source' => $match['source'], ]; } diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/PhpRuleTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/PhpRuleTest.php index ed8660694377b51f79320972d79b3f50d4662adc..aa92d6ba72e0097ba2476ca0bbde8a9c2421d61a 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/PhpRuleTest.php +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/PhpRuleTest.php @@ -16,7 +16,11 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase { $mapRoutes = ['someModule' => ['Magento\SomeModule'], 'anotherModule' => ['Magento\OneModule']]; $mapLayoutBlocks = ['area' => ['block.name' => ['Magento\SomeModule' => 'Magento\SomeModule']]]; - $this->model = new PhpRule($mapRoutes, $mapLayoutBlocks); + $pluginMap = [ + 'Magento\Module1\Plugin1' => 'Magento\Module1\Subject', + 'Magento\Module1\Plugin2' => 'Magento\Module2\Subject', + ]; + $this->model = new PhpRule($mapRoutes, $mapLayoutBlocks, $pluginMap); } public function testNonPhpGetDependencyInfo() @@ -26,22 +30,31 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase } /** - * @param string $module + * @param string $class * @param string $content * @param array $expected * @dataProvider getDependencyInfoDataProvider */ - public function testGetDependencyInfo($module, $content, array $expected) + public function testGetDependencyInfo($class, $content, array $expected) { - $this->assertEquals($expected, $this->model->getDependencyInfo($module, 'php', 'any', $content)); + $file = $this->makeMockFilepath($class); + $module = $this->getModuleFromClass($class); + $this->assertEquals($expected, $this->model->getDependencyInfo($module, 'php', $file, $content)); } + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ public function getDependencyInfoDataProvider() { return [ - ['Magento\SomeModule', 'something extends \Magento\SomeModule\Any\ClassName {', []], //1 - [ - 'Magento\AnotherModule', + 'Extend class in same module' => [ + 'Magento\SomeModule\SomeClass', + 'something extends \Magento\SomeModule\Any\ClassName {', + [] + ], + 'Extend class in different module' => [ + 'Magento\AnotherModule\SomeClass', 'something extends \Magento\SomeModule\Any\ClassName {', [ [ @@ -50,14 +63,14 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase 'source' => 'Magento\SomeModule\Any\ClassName', ] ] - ], // 2 - [ - 'Magento\SomeModule', + ], + 'getViewFileUrl in same module' => [ + 'Magento\SomeModule\SomeClass', '$this->getViewFileUrl("Magento_SomeModule::js/order-by-sku-failure.js")', [] - ], // 3 - [ - 'Magento\AnotherModule', + ], + 'getViewFileUrl in different module' => [ + 'Magento\AnotherModule\SomeClass', '$this->getViewFileUrl("Magento_SomeModule::js/order-by-sku-failure.js")', [ [ @@ -66,10 +79,14 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase 'source' => 'Magento_SomeModule', ] ] - ], //4 - ['Magento\SomeModule', '$this->helper("Magento\SomeModule\Any\ClassName")', []], //5 - [ - 'Magento\AnotherModule', + ], + 'Helper class from same module' => [ + 'Magento\SomeModule\SomeClass', + '$this->helper("Magento\SomeModule\Any\ClassName")', + [] + ], + 'Helper class from another module' => [ + 'Magento\AnotherModule\SomeClass', '$this->helper("Magento\SomeModule\Any\ClassName")', [ [ @@ -78,10 +95,14 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase 'source' => 'Magento\SomeModule\Any\ClassName', ] ] - ], //6 - ['Magento\SomeModule', '$this->getUrl("someModule")', []], // 7 - [ - 'Magento\AnotherModule', + ], + 'getUrl from same module' => [ + 'Magento\SomeModule\SomeClass', + '$this->getUrl("someModule")', + [] + ], + 'getUrl from another module' => [ + 'Magento\SomeModule\SomeClass', '$this->getUrl("anotherModule")', [ [ @@ -90,10 +111,13 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase 'source' => 'getUrl("anotherModule"', ] ] - ], //8 - ['Magento\SomeModule', '$this->getLayout()->getBlock(\'block.name\');', []], // 9 - [ - 'Magento\AnotherModule', + ], + 'getBlock from same module' => [ + 'Magento\SomeModule\SomeClass', + '$this->getLayout()->getBlock(\'block.name\');', [] + ], + 'getBlock from another module' => [ + 'Magento\AnotherModule\SomeClass', '$this->getLayout()->getBlock(\'block.name\');', [ [ @@ -102,7 +126,50 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase 'source' => 'getBlock(\'block.name\')', ] ] - ] // 10 + ], + 'Plugin on class in same module' => [ + 'Magento\Module1\Plugin1', + ', \Magento\Module1\Subject $variable', + [] + ], + 'Plugin depends on arbitrary class in same module' => [ + 'Magento\Module1\Plugin1', + ', \Magento\Module1\NotSubject $variable', + [] + ], + 'Plugin on class in different module' => [ + 'Magento\Module1\Plugin2', + 'Magento\Module2\Subject', + [ + [ + 'module' => 'Magento\Module2', + 'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_SOFT, + 'source' => 'Magento\Module2\Subject', + ] + ], + ], + 'Plugin depends on arbitrary class in same module as subject' => [ + 'Magento\Module1\Plugin2', + 'Magento\Module2\NotSubject', + [ + [ + 'module' => 'Magento\Module2', + 'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_SOFT, + 'source' => 'Magento\Module2\NotSubject', + ] + ] + ], + 'Plugin depends on arbitrary class in arbitrary module' => [ + 'Magento\Module1\Plugin2', + 'Magento\OtherModule\NotSubject', + [ + [ + 'module' => 'Magento\OtherModule', + 'type' => \Magento\TestFramework\Dependency\RuleInterface::TYPE_HARD, + 'source' => 'Magento\OtherModule\NotSubject', + ] + ] + ], ]; } @@ -141,4 +208,28 @@ class PhpRuleTest extends \PHPUnit_Framework_TestCase ] ]; } + + + /** + * Make some fake filepath to correspond to the class name + * + * @param string $class + * @return string + */ + private function makeMockFilepath($class) + { + return 'ClassRoot' . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'; + } + + /** + * Get the module name like Magento\Module out of a classname, assuming for test purpose that + * all modules are from "Magento" vendor + * + * @param string $class + * @return string + */ + private function getModuleFromClass($class) + { + return substr($class, 0, strpos($class, '\\', 9)); // (strlen('Magento\\') + 1) === 9 + } } diff --git a/lib/internal/Magento/Framework/App/Cache/Type/Reflection.php b/lib/internal/Magento/Framework/App/Cache/Type/Reflection.php new file mode 100644 index 0000000000000000000000000000000000000000..5ad5d1e30a8cc7e9a2b4543199db7570ec50e30c --- /dev/null +++ b/lib/internal/Magento/Framework/App/Cache/Type/Reflection.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\App\Cache\Type; + +/** + * System / Cache Management / Cache type "Reflection Data" + */ +class Reflection extends \Magento\Framework\Cache\Frontend\Decorator\TagScope +{ + /** + * Cache type code unique among all cache types + */ + const TYPE_IDENTIFIER = 'reflection'; + + /** + * Cache tag used to distinguish the cache type from all other cache + */ + const CACHE_TAG = 'REFLECTION'; + + /** + * @param \Magento\Framework\App\Cache\Type\FrontendPool $cacheFrontendPool + */ + public function __construct(\Magento\Framework\App\Cache\Type\FrontendPool $cacheFrontendPool) + { + parent::__construct($cacheFrontendPool->get(self::TYPE_IDENTIFIER), self::CACHE_TAG); + } +} diff --git a/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php b/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php index 7c971eaf437f13a4b301b4b210affbea20ce35d8..f1daf86f782395e831a804a55369554acd28e29f 100644 --- a/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php +++ b/lib/internal/Magento/Framework/View/Element/Html/Link/Current.php @@ -12,6 +12,7 @@ namespace Magento\Framework\View\Element\Html\Link; * @method string getLabel() * @method string getPath() * @method string getTitle() + * @method null|array getAttributes() * @method null|bool getCurrent() * @method \Magento\Framework\View\Element\Html\Link\Current setCurrent(bool $value) */ @@ -110,7 +111,7 @@ class Current extends \Magento\Framework\View\Element\Template $html .= $this->getTitle() ? ' title="' . $this->escapeHtml((string)new \Magento\Framework\Phrase($this->getTitle())) . '"' : ''; - $html .= '>'; + $html .= $this->getAttributesHtml() . '>'; if ($this->getIsHighlighted()) { $html .= '<strong>'; @@ -127,4 +128,22 @@ class Current extends \Magento\Framework\View\Element\Template return $html; } + + /** + * Generate attributes' HTML code + * + * @return string + */ + private function getAttributesHtml() + { + $attributesHtml = ''; + $attributes = $this->getAttributes(); + if ($attributes) { + foreach ($attributes as $attribute => $value) { + $attributesHtml .= ' ' . $attribute . '="' . $this->escapeHtml($value) . '"'; + } + } + + return $attributesHtml; + } } diff --git a/nginx.conf.sample b/nginx.conf.sample index cab0b839ffe10f8c87a46dc97baccafa50f93a64..01b163498156956cb37f9ea99a5f5f9c9817981c 100644 --- a/nginx.conf.sample +++ b/nginx.conf.sample @@ -26,13 +26,32 @@ charset off; location /setup { root $MAGE_ROOT; - location ~ ^/setup/index.php { fastcgi_pass fastcgi_backend; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } + + location ~ /setup/(?!pub/). { + deny all; + } +} + +location /update { + root $MAGE_ROOT; + + location ~ /update/index.php { + fastcgi_pass fastcgi_backend; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + } + + # deny everything but index.php + location ~ /update/(?!pub/). { + deny all; + } } location / { @@ -40,6 +59,9 @@ location / { } location /pub { + location ~ ^/pub/media/(downloadable|customer|import|theme_customization/.*\.xml) { + deny all; + } alias $MAGE_ROOT/pub; } @@ -70,6 +92,11 @@ location /static/ { location /media/ { try_files $uri $uri/ /get.php?$args; + + location ~ ^/media/theme_customization/.*\.xml { + deny all; + } + location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ { add_header Cache-Control "public"; expires +1y; @@ -90,15 +117,7 @@ location /media/downloadable/ { deny all; } -location ~ /media/theme_customization/.*\.xml$ { - deny all; -} - -location /errors/ { - try_files $uri =404; -} - -location ~ ^/errors/.*\.(xml|phtml)$ { +location /media/import/ { deny all; } diff --git a/pub/errors/.htaccess b/pub/errors/.htaccess index 5a3f0a15d124ed9f66b3fd0e97ad4d6ae7cce0f7..3692dd439e2ff90b141f4e2c362518e359e7079e 100644 --- a/pub/errors/.htaccess +++ b/pub/errors/.htaccess @@ -2,6 +2,3 @@ Options None <IfModule mod_rewrite.c> RewriteEngine Off </IfModule> -<FilesMatch "\.(xml|phtml)$"> - Deny from all -</FilesMatch> \ No newline at end of file diff --git a/setup/config/.htaccess b/setup/config/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..281d5c33db37cd1cc887dbb2d36897b897835071 --- /dev/null +++ b/setup/config/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/setup/performance-toolkit/.htaccess b/setup/performance-toolkit/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..281d5c33db37cd1cc887dbb2d36897b897835071 --- /dev/null +++ b/setup/performance-toolkit/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/setup/src/.htaccess b/setup/src/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..281d5c33db37cd1cc887dbb2d36897b897835071 --- /dev/null +++ b/setup/src/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php index 707c8ee9dae3296836b2a16a000298fded1c9359..05a46aac47dade5b0a8f9b40ad7eeb16ea175388 100644 --- a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php +++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php @@ -8,6 +8,7 @@ namespace Magento\Setup\Console\Command; use Magento\Framework\Filesystem; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Filesystem\DriverInterface; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\App\DeploymentConfig; use Magento\Setup\Model\ObjectManagerProvider; @@ -44,6 +45,9 @@ class DiCompileCommand extends Command /** @var array */ private $excludedPathsList; + /** @var DriverInterface */ + private $fileDriver; + /** * Constructor * @@ -52,19 +56,22 @@ class DiCompileCommand extends Command * @param Manager $taskManager * @param ObjectManagerProvider $objectManagerProvider * @param Filesystem $filesystem + * @param DriverInterface $fileDriver */ public function __construct( DeploymentConfig $deploymentConfig, DirectoryList $directoryList, Manager $taskManager, ObjectManagerProvider $objectManagerProvider, - Filesystem $filesystem + Filesystem $filesystem, + DriverInterface $fileDriver ) { $this->deploymentConfig = $deploymentConfig; $this->directoryList = $directoryList; $this->objectManager = $objectManagerProvider->get(); $this->taskManager = $taskManager; $this->filesystem = $filesystem; + $this->fileDriver = $fileDriver; parent::__construct(); } @@ -80,18 +87,50 @@ class DiCompileCommand extends Command parent::configure(); } + /** + * Checks that application is installed and DI resources are cleared + * + * @return string[] + */ + private function checkEnvironment() + { + $messages = []; + if (!$this->deploymentConfig->isAvailable()) { + $messages[] = 'You cannot run this command because the Magento application is not installed.'; + } + + /** + * By the time the command is able to execute, the Object Management configuration is already contaminated + * by old config info, and it's too late to just clear the files in code. + * + * TODO: reconfigure OM in runtime so DI resources can be cleared after command launches + * + */ + $path = $this->directoryList->getPath(DirectoryList::DI); + if ($this->fileDriver->isExists($path)) { + $messages[] = "DI configuration must be cleared before running compiler. Please delete '$path'."; + } + + return $messages; + } + /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { + $errors = $this->checkEnvironment(); + if ($errors) { + foreach ($errors as $line) { + $output->writeln($line); + } + return; + } + $appCodePath = $this->directoryList->getPath(DirectoryList::MODULES); $libraryPath = $this->directoryList->getPath(DirectoryList::LIB_INTERNAL); $generationPath = $this->directoryList->getPath(DirectoryList::GENERATION); - if (!$this->deploymentConfig->isAvailable()) { - $output->writeln('You cannot run this command because the Magento application is not installed.'); - return; - } + $this->objectManager->get('Magento\Framework\App\Cache')->clean(); $compiledPathsList = [ 'application' => $appCodePath, diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php index 2b9381b4783a495e0a179e6221734c0ac34e5895..205e0799436bb77e81fcda0bfed630df89874c55 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php @@ -28,6 +28,12 @@ class DiCompileCommandTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject */ private $filesystem; + /** @var \Magento\Framework\Filesystem\Driver\File | \PHPUnit_Framework_MockObject_MockObject*/ + private $fileDriver; + + /** @var \Magento\Framework\App\Filesystem\DirectoryList | \PHPUnit_Framework_MockObject_MockObject*/ + private $directoryList; + public function setUp() { $this->deploymentConfig = $this->getMock('Magento\Framework\App\DeploymentConfig', [], [], '', false); @@ -52,23 +58,39 @@ class DiCompileCommandTest extends \PHPUnit_Framework_TestCase ->method('get') ->willReturn($this->objectManager); $this->manager = $this->getMock('Magento\Setup\Module\Di\App\Task\Manager', [], [], '', false); - $directoryList = $this->getMock('Magento\Framework\App\Filesystem\DirectoryList', [], [], '', false); + $this->directoryList = $this->getMock('Magento\Framework\App\Filesystem\DirectoryList', [], [], '', false); $this->filesystem = $this->getMockBuilder('Magento\Framework\Filesystem') ->disableOriginalConstructor() ->getMock(); - $directoryList->expects($this->exactly(3))->method('getPath'); + $this->fileDriver = $this->getMockBuilder('Magento\Framework\Filesystem\Driver\File') + ->disableOriginalConstructor() + ->getMock(); + $this->command = new DiCompileCommand( $this->deploymentConfig, - $directoryList, + $this->directoryList, $this->manager, $objectManagerProvider, - $this->filesystem + $this->filesystem, + $this->fileDriver ); } + public function testExecuteDiExists() + { + $diPath = '/root/magento/var/di'; + $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(true); + $this->fileDriver->expects($this->atLeastOnce())->method('isExists')->with($diPath)->willReturn(true); + $this->directoryList->expects($this->atLeastOnce())->method('getPath')->willReturn($diPath); + $tester = new CommandTester($this->command); + $tester->execute([]); + $this->assertContains("delete '/root/magento/var/di'", $tester->getDisplay()); + } + public function testExecuteNotInstalled() { + $this->directoryList->expects($this->atLeastOnce())->method('getPath')->willReturn(null); $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(false); $tester = new CommandTester($this->command); $tester->execute([]); @@ -80,6 +102,7 @@ class DiCompileCommandTest extends \PHPUnit_Framework_TestCase public function testExecute() { + $this->directoryList->expects($this->atLeastOnce())->method('getPath')->willReturn(null); $this->objectManager->expects($this->once()) ->method('get') ->with('Magento\Framework\App\Cache') diff --git a/setup/view/.htaccess b/setup/view/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..281d5c33db37cd1cc887dbb2d36897b897835071 --- /dev/null +++ b/setup/view/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/vendor/.htaccess b/vendor/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..cb24fd7fc0b3a0e46f6cad19e834117476bd0341 --- /dev/null +++ b/vendor/.htaccess @@ -0,0 +1,2 @@ +Order allow,deny +Deny from all