diff --git a/.php_cs b/.php_cs index 8381e44cf08ffb15328333db20f5d3a9b69386dc..7f5e43f9d4f01ec44cadc22650a8bd5b3c19c154 100644 --- a/.php_cs +++ b/.php_cs @@ -17,7 +17,6 @@ $finder = Symfony\CS\Finder\DefaultFinder::create() ->exclude('dev/tests/integration/var') ->exclude('lib/internal/Cm') ->exclude('lib/internal/Credis') - ->exclude('lib/internal/JSMin') ->exclude('lib/internal/Less') ->exclude('lib/internal/LinLibertineFont') ->exclude('lib/internal/phpseclib') diff --git a/Gruntfile.js b/Gruntfile.js index 8dcee340ef46cdd59a9631a3d77b2155c0802e6c..5f401a8c6fe4a47dd835531195a94fbb201cf597 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -15,6 +15,9 @@ module.exports = function (grunt) { [ taskDir + '/mage-minify', taskDir + '/deploy', + taskDir + '/black-list-generator', + taskDir + '/clean-black-list', + taskDir + '/static', 'time-grunt' ].forEach(function (task) { require(task)(grunt); diff --git a/app/code/Magento/Authorizenet/Helper/Backend/Data.php b/app/code/Magento/Authorizenet/Helper/Backend/Data.php index 1adfc4a25d95a72f07d5ccd7f2342357d98dad09..7489262c0dcd6b504cd054760182203510302df6 100644 --- a/app/code/Magento/Authorizenet/Helper/Backend/Data.php +++ b/app/code/Magento/Authorizenet/Helper/Backend/Data.php @@ -28,8 +28,8 @@ class Data extends FrontendDataHelper OrderFactory $orderFactory, UrlInterface $backendUrl ) { - $this->_urlBuilder = $backendUrl; parent::__construct($context, $storeManager, $orderFactory); + $this->_urlBuilder = $backendUrl; } /** @@ -85,6 +85,8 @@ class Data extends FrontendDataHelper * * @param null|int|string $storeId * @return string + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getRelayUrl($storeId = null) { diff --git a/app/code/Magento/Authorizenet/view/adminhtml/web/js/direct-post.js b/app/code/Magento/Authorizenet/view/adminhtml/web/js/direct-post.js index d6423db943e1eb5ad55bae6d7a3c61a8d27a6987..79c2a13c8451c8380f2096c79b1374bfe8b651d0 100644 --- a/app/code/Magento/Authorizenet/view/adminhtml/web/js/direct-post.js +++ b/app/code/Magento/Authorizenet/view/adminhtml/web/js/direct-post.js @@ -32,13 +32,11 @@ directPost.prototype = { this.headers = []; this.isValid = true; this.paymentRequestSent = false; - this.isResponse = false; this.orderIncrementId = false; this.successUrl = false; this.hasError = false; this.tmpForm = false; - this.onSaveOnepageOrderSuccess = this.saveOnepageOrderSuccess.bindAsEventListener(this); this.onLoadIframe = this.loadIframe.bindAsEventListener(this); this.onLoadOrderIframe = this.loadOrderIframe.bindAsEventListener(this); this.onSubmitAdminOrder = this.submitAdminOrder.bindAsEventListener(this); @@ -80,63 +78,30 @@ directPost.prototype = { .off('submitOrder') .on('submitOrder', this.submitAdminOrder.bind(this)); if ($(this.iframeId)) { - switch (this.controller) { - case 'onepage': - this.headers = $$('#' + checkout.accordion.container.readAttribute('id') + ' .section'); - var button = $('review-buttons-container').down('button'); - button.writeAttribute('onclick', ''); - button.stopObserving('click'); - button.observe('click', function() { - if ($(this.iframeId)) { - if (this.validate()) { - this.saveOnepageOrder(); - } - } else { - review.save(); - } - }.bind(this)); - break; - case 'order_create': - case 'order_edit': - // Temporary solution will be removed after refactoring Authorize.Net (sales) functionality - jQuery('.scalable.save:not(disabled)').removeAttr('onclick'); - jQuery(document).off('click.directPost'); - jQuery(document).on( - 'click.directPost', - '.scalable.save:not(disabled)', - jQuery.proxy(this.onSubmitAdminOrder, this) - ); - - $('order-' + this.iframeId).observe('load', this.onLoadOrderIframe); - break; - } - + // Temporary solution will be removed after refactoring Authorize.Net (sales) functionality + jQuery('.scalable.save:not(disabled)').removeAttr('onclick'); + jQuery(document).off('click.directPost'); + jQuery(document).on( + 'click.directPost', + '.scalable.save:not(disabled)', + jQuery.proxy(this.onSubmitAdminOrder, this) + ); + $('order-' + this.iframeId).observe('load', this.onLoadOrderIframe); $(this.iframeId).observe('load', this.onLoadIframe); } }, loadIframe : function() { if (this.paymentRequestSent) { - switch (this.controller) { - case 'onepage': - this.paymentRequestSent = false; - if (!this.hasError) { - this.returnQuote(); - } - break; - case 'order_edit': - case 'order_create': - if (!this.orderRequestSent) { - this.paymentRequestSent = false; - if (!this.hasError) { - this.returnQuote(); - } else { - this.changeInputOptions('disabled', false); - jQuery('body').trigger('processStop'); - enableElements('save'); - } - } - break; + if (!this.orderRequestSent) { + this.paymentRequestSent = false; + if (!this.hasError) { + this.returnQuote(); + } else { + this.changeInputOptions('disabled', false); + jQuery('body').trigger('processStop'); + enableElements('save'); + } } if (this.tmpForm) { document.body.removeChild(this.tmpForm); @@ -167,7 +132,7 @@ directPost.prototype = { new Ajax.Request(url, { onSuccess : function(transport) { try { - response = eval('(' + transport.responseText + ')'); + response = transport.responseText.evalJSON(true); } catch (e) { response = {}; } @@ -175,17 +140,9 @@ directPost.prototype = { alert(response.error_message); } $(this.iframeId).show(); - switch (this.controller) { - case 'onepage': - this.resetLoadWaiting(); - break; - case 'order_edit': - case 'order_create': - this.changeInputOptions('disabled', false); - jQuery('body').trigger('processStop'); - enableElements('save'); - break; - } + this.changeInputOptions('disabled', false); + jQuery('body').trigger('processStop'); + enableElements('save'); }.bind(this) }); }, @@ -204,66 +161,6 @@ directPost.prototype = { checkout.setLoadWaiting(false); }, - saveOnepageOrder : function() { - this.hasError = false; - this.setLoadWaiting(); - var params = Form.serialize(payment.form); - if (review.agreementsForm) { - params += '&' + Form.serialize(review.agreementsForm); - } - params += '&controller=' + this.controller; - new Ajax.Request(this.orderSaveUrl, { - method : 'post', - parameters : params, - onComplete : this.onSaveOnepageOrderSuccess, - onFailure : function(transport) { - this.resetLoadWaiting(); - if (transport.status == 403) { - checkout.ajaxFailure(); - } - } - }); - }, - - saveOnepageOrderSuccess : function(transport) { - if (transport.status == 403) { - checkout.ajaxFailure(); - } - try { - response = eval('(' + transport.responseText + ')'); - } catch (e) { - response = {}; - } - - if (response.success && response.directpost) { - this.orderIncrementId = response.directpost.fields.x_invoice_num; - var paymentData = {}; - for ( var key in response.directpost.fields) { - paymentData[key] = response.directpost.fields[key]; - } - var preparedData = this.preparePaymentRequest(paymentData); - this.sendPaymentRequest(preparedData); - } else { - var msg = response.error_messages; - if (typeof (msg) == 'object') { - msg = msg.join("\n"); - } - if (msg) { - alert(msg); - } - - if (response.update_section) { - $('checkout-' + response.update_section.name + '-load').replace(response.update_section.html); - response.update_section.html.evalScripts(); - } - - if (response.goto_section) { - checkout.gotoSection(response.goto_section); - checkout.reloadProgressBlock(); - } - } - }, - submitAdminOrder : function() { // Temporary solution will be removed after refactoring Authorize.Net (sales) functionality var editForm = jQuery('#edit_form'); @@ -324,7 +221,7 @@ directPost.prototype = { saveAdminOrderSuccess : function(data) { try { - response = eval('(' + data + ')'); + response = data.evalJSON(true); } catch (e) { response = {}; } @@ -423,4 +320,4 @@ directPost.prototype = { } } }; -})); \ No newline at end of file +})); diff --git a/app/code/Magento/Backend/Block/Cache/Additional.php b/app/code/Magento/Backend/Block/Cache/Additional.php index f1aed57660825553a4259fa6eef6f550245c58f5..99574ad958397d53228d7c37f6b40dcfacf85df8 100644 --- a/app/code/Magento/Backend/Block/Cache/Additional.php +++ b/app/code/Magento/Backend/Block/Cache/Additional.php @@ -7,6 +7,16 @@ namespace Magento\Backend\Block\Cache; class Additional extends \Magento\Backend\Block\Template { + /** + * Check if application is in production mode + * + * @return bool + */ + public function isInProductionMode() + { + return $this->_appState->getMode() === \Magento\Framework\App\State::MODE_PRODUCTION; + } + /** * @return string */ @@ -22,4 +32,12 @@ class Additional extends \Magento\Backend\Block\Template { return $this->getUrl('*/*/cleanMedia'); } + + /** + * @return string + */ + public function getCleanStaticFilesUrl() + { + return $this->getUrl('*/*/cleanStaticFiles'); + } } diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFiles.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFiles.php new file mode 100644 index 0000000000000000000000000000000000000000..4ca025b3ec57fabc68dfa4814de74f68afc38608 --- /dev/null +++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFiles.php @@ -0,0 +1,28 @@ +<?php +/** + * + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Backend\Controller\Adminhtml\Cache; + +use Magento\Framework\Controller\ResultFactory; + +class CleanStaticFiles extends \Magento\Backend\Controller\Adminhtml\Cache +{ + /** + * Clean static files cache + * + * @return \Magento\Backend\Model\View\Result\Redirect + */ + public function execute() + { + $this->_objectManager->get('Magento\Framework\App\State\CleanupFiles')->clearMaterializedViewFiles(); + $this->_eventManager->dispatch('clean_static_files_cache_after'); + $this->messageManager->addSuccess(__('The static files cache has been cleaned.')); + + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + return $resultRedirect->setPath('adminhtml/*'); + } +} diff --git a/app/code/Magento/Backend/Setup/ConfigOptionsList.php b/app/code/Magento/Backend/Setup/ConfigOptionsList.php index 2a6a39f88af73d7b2680d985971310ebe5115e9d..78ec4523435fd1e57b2e7e01d4baeb2f24fc64a8 100644 --- a/app/code/Magento/Backend/Setup/ConfigOptionsList.php +++ b/app/code/Magento/Backend/Setup/ConfigOptionsList.php @@ -10,6 +10,7 @@ use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Setup\ConfigOptionsListInterface; use Magento\Framework\Setup\Option\TextConfigOption; use Magento\Framework\App\DeploymentConfig; +use \Magento\Framework\Setup\BackendFrontnameGenerator; /* * Deployment configuration options needed for Backend module @@ -36,8 +37,7 @@ class ConfigOptionsList implements ConfigOptionsListInterface self::INPUT_KEY_BACKEND_FRONTNAME, TextConfigOption::FRONTEND_WIZARD_TEXT, self::CONFIG_PATH_BACKEND_FRONTNAME, - 'Backend frontname', - 'admin' + 'Backend frontname (will be autogenerated if missing)' ) ]; } @@ -50,6 +50,10 @@ class ConfigOptionsList implements ConfigOptionsListInterface { $configData = new ConfigData(ConfigFilePool::APP_ENV); + if (!$deploymentConfig->get(self::CONFIG_PATH_BACKEND_FRONTNAME) + && !isset($options[self::INPUT_KEY_BACKEND_FRONTNAME])) { + $options[self::INPUT_KEY_BACKEND_FRONTNAME] = BackendFrontnameGenerator::generate(); + } if (isset($options[self::INPUT_KEY_BACKEND_FRONTNAME])) { $configData->set(self::CONFIG_PATH_BACKEND_FRONTNAME, $options[self::INPUT_KEY_BACKEND_FRONTNAME]); } diff --git a/app/code/Magento/Backend/Test/Unit/Block/Cache/AdditionalTest.php b/app/code/Magento/Backend/Test/Unit/Block/Cache/AdditionalTest.php new file mode 100644 index 0000000000000000000000000000000000000000..db0e91b0dd8f3adeedd8eb6f535e02ae6aec1736 --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Block/Cache/AdditionalTest.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\Unit\Block\Cache; + +class AdditionalTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Backend\Block\Cache\Additional + */ + private $additonalBlock; + + /** + * @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $urlBuilderMock; + + /** + * @var \Magento\Framework\App\State | \PHPUnit_Framework_MockObject_MockObject + */ + protected $appStateMock; + + protected function setUp() + { + $this->urlBuilderMock = $this->getMock('Magento\Framework\UrlInterface'); + $this->appStateMock = $this->getMockBuilder('Magento\Framework\App\State') + ->disableOriginalConstructor() + ->getMock(); + + $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $context = $objectHelper->getObject( + 'Magento\Backend\Block\Template\Context', + [ + 'urlBuilder' => $this->urlBuilderMock, + 'appState' => $this->appStateMock, + ] + ); + + $this->additonalBlock = $objectHelper->getObject( + 'Magento\Backend\Block\Cache\Additional', + ['context' => $context] + ); + } + + public function testGetCleanImagesUrl() + { + $expectedUrl = 'cleanImagesUrl'; + $this->urlBuilderMock->expects($this->once()) + ->method('getUrl') + ->with('*/*/cleanImages') + ->will($this->returnValue($expectedUrl)); + $this->assertEquals($expectedUrl, $this->additonalBlock->getCleanImagesUrl()); + } + + public function testGetCleanMediaUrl() + { + $expectedUrl = 'cleanMediaUrl'; + $this->urlBuilderMock->expects($this->once()) + ->method('getUrl') + ->with('*/*/cleanMedia') + ->will($this->returnValue($expectedUrl)); + $this->assertEquals($expectedUrl, $this->additonalBlock->getCleanMediaUrl()); + } + + public function testGetCleanStaticFiles() + { + $expectedUrl = 'cleanStaticFilesUrl'; + $this->urlBuilderMock->expects($this->once()) + ->method('getUrl') + ->with('*/*/cleanStaticFiles') + ->will($this->returnValue($expectedUrl)); + $this->assertEquals($expectedUrl, $this->additonalBlock->getCleanStaticFilesUrl()); + } + + /** + * @param string $mode + * @param bool $expected + * @dataProvider isInProductionModeDataProvider + */ + public function testIsInProductionMode($mode, $expected) + { + $this->appStateMock->expects($this->once()) + ->method('getMode') + ->willReturn($mode); + $this->assertEquals($expected, $this->additonalBlock->isInProductionMode()); + } + + public function isInProductionModeDataProvider() + { + return [ + [\Magento\Framework\App\State::MODE_DEFAULT, false], + [\Magento\Framework\App\State::MODE_DEVELOPER, false], + [\Magento\Framework\App\State::MODE_PRODUCTION, true], + ]; + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanStaticFilesTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanStaticFilesTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0e78f533c85256eb48534c6ac877a4c31fd7e967 --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanStaticFilesTest.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +// @codingStandardsIgnoreFile + +namespace Magento\Backend\Test\Unit\Controller\Adminhtml\Cache; + +class CleanStaticFilesTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface | \PHPUnit_Framework_MockObject_MockObject + */ + private $objectManagerMock; + + /** + * @var \Magento\Framework\Event\ManagerInterface | \PHPUnit_Framework_MockObject_MockObject + */ + private $eventManagerMock; + + /** + * @var \Magento\Framework\Message\ManagerInterface | \PHPUnit_Framework_MockObject_MockObject + */ + private $messageManagerMock; + + /** + * @var \Magento\Framework\Controller\ResultFactory | \PHPUnit_Framework_MockObject_MockObject + */ + private $resultFactoryMock; + + /** + * @var \Magento\Backend\Controller\Adminhtml\Cache\CleanStaticFiles + */ + private $controller; + + protected function setUp() + { + $this->objectManagerMock = $this->getMock('Magento\Framework\ObjectManagerInterface'); + $this->eventManagerMock = $this->getMockBuilder('Magento\Framework\Event\ManagerInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->messageManagerMock = $this->getMockBuilder('Magento\Framework\Message\ManagerInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->resultFactoryMock = $this->getMockBuilder('Magento\Framework\Controller\ResultFactory') + ->disableOriginalConstructor() + ->getMock(); + $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $context = $objectHelper->getObject( + '\Magento\Backend\App\Action\Context', + [ + 'objectManager' => $this->objectManagerMock, + 'eventManager' => $this->eventManagerMock, + 'messageManager' => $this->messageManagerMock, + 'resultFactory' => $this->resultFactoryMock, + ] + ); + + $this->controller = $objectHelper->getObject( + 'Magento\Backend\Controller\Adminhtml\Cache\CleanStaticFiles', + ['context' => $context,] + ); + } + + public function testExecute() + { + $cleanupFilesMock = $this->getMockBuilder('Magento\Framework\App\State\CleanupFiles') + ->disableOriginalConstructor() + ->getMock(); + $cleanupFilesMock->expects($this->once()) + ->method('clearMaterializedViewFiles'); + $this->objectManagerMock->expects($this->once())->method('get')->will($this->returnValue($cleanupFilesMock)); + + $this->eventManagerMock->expects($this->once()) + ->method('dispatch') + ->with('clean_static_files_cache_after'); + + $this->messageManagerMock->expects($this->once()) + ->method('addSuccess') + ->with('The static files cache has been cleaned.'); + + $resultRedirect = $this->getMockBuilder('Magento\Backend\Model\View\Result\Redirect') + ->disableOriginalConstructor() + ->getMock(); + $this->resultFactoryMock->expects($this->atLeastOnce()) + ->method('create') + ->with(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) + ->willReturn($resultRedirect); + $resultRedirect->expects($this->once()) + ->method('setPath') + ->with('adminhtml/*') + ->willReturnSelf(); + + // Run + $this->controller->execute(); + } +} diff --git a/app/code/Magento/Backend/i18n/de_DE.csv b/app/code/Magento/Backend/i18n/de_DE.csv index fddd1a2eba777c7ab248f5fd11993536cf260914..8bd82b41c2050a73b6cefcad5a4a53a280627769 100644 --- a/app/code/Magento/Backend/i18n/de_DE.csv +++ b/app/code/Magento/Backend/i18n/de_DE.csv @@ -412,6 +412,8 @@ Scope:,Scope: "Pregenerated product images files","Pregenerated product images files" "Flush JavaScript/CSS Cache","Flush JavaScript/CSS Cache" "Themes JavaScript and CSS files combined to one file.","Themes JavaScript and CSS files combined to one file." +"Flush Static Files Cache", "Flush Static Files Cache" +"Preprocessed view files and static files", "Preprocessed view files and static files" Catalog,Catalog JavaScript/CSS,JavaScript/CSS "JavaScript/CSS Cache","JavaScript/CSS Cache" diff --git a/app/code/Magento/Backend/i18n/en_US.csv b/app/code/Magento/Backend/i18n/en_US.csv index fddd1a2eba777c7ab248f5fd11993536cf260914..8bd82b41c2050a73b6cefcad5a4a53a280627769 100644 --- a/app/code/Magento/Backend/i18n/en_US.csv +++ b/app/code/Magento/Backend/i18n/en_US.csv @@ -412,6 +412,8 @@ Scope:,Scope: "Pregenerated product images files","Pregenerated product images files" "Flush JavaScript/CSS Cache","Flush JavaScript/CSS Cache" "Themes JavaScript and CSS files combined to one file.","Themes JavaScript and CSS files combined to one file." +"Flush Static Files Cache", "Flush Static Files Cache" +"Preprocessed view files and static files", "Preprocessed view files and static files" Catalog,Catalog JavaScript/CSS,JavaScript/CSS "JavaScript/CSS Cache","JavaScript/CSS Cache" diff --git a/app/code/Magento/Backend/i18n/es_ES.csv b/app/code/Magento/Backend/i18n/es_ES.csv index fddd1a2eba777c7ab248f5fd11993536cf260914..8bd82b41c2050a73b6cefcad5a4a53a280627769 100644 --- a/app/code/Magento/Backend/i18n/es_ES.csv +++ b/app/code/Magento/Backend/i18n/es_ES.csv @@ -412,6 +412,8 @@ Scope:,Scope: "Pregenerated product images files","Pregenerated product images files" "Flush JavaScript/CSS Cache","Flush JavaScript/CSS Cache" "Themes JavaScript and CSS files combined to one file.","Themes JavaScript and CSS files combined to one file." +"Flush Static Files Cache", "Flush Static Files Cache" +"Preprocessed view files and static files", "Preprocessed view files and static files" Catalog,Catalog JavaScript/CSS,JavaScript/CSS "JavaScript/CSS Cache","JavaScript/CSS Cache" diff --git a/app/code/Magento/Backend/i18n/fr_FR.csv b/app/code/Magento/Backend/i18n/fr_FR.csv index fddd1a2eba777c7ab248f5fd11993536cf260914..8bd82b41c2050a73b6cefcad5a4a53a280627769 100644 --- a/app/code/Magento/Backend/i18n/fr_FR.csv +++ b/app/code/Magento/Backend/i18n/fr_FR.csv @@ -412,6 +412,8 @@ Scope:,Scope: "Pregenerated product images files","Pregenerated product images files" "Flush JavaScript/CSS Cache","Flush JavaScript/CSS Cache" "Themes JavaScript and CSS files combined to one file.","Themes JavaScript and CSS files combined to one file." +"Flush Static Files Cache", "Flush Static Files Cache" +"Preprocessed view files and static files", "Preprocessed view files and static files" Catalog,Catalog JavaScript/CSS,JavaScript/CSS "JavaScript/CSS Cache","JavaScript/CSS Cache" diff --git a/app/code/Magento/Backend/i18n/nl_NL.csv b/app/code/Magento/Backend/i18n/nl_NL.csv index fddd1a2eba777c7ab248f5fd11993536cf260914..8bd82b41c2050a73b6cefcad5a4a53a280627769 100644 --- a/app/code/Magento/Backend/i18n/nl_NL.csv +++ b/app/code/Magento/Backend/i18n/nl_NL.csv @@ -412,6 +412,8 @@ Scope:,Scope: "Pregenerated product images files","Pregenerated product images files" "Flush JavaScript/CSS Cache","Flush JavaScript/CSS Cache" "Themes JavaScript and CSS files combined to one file.","Themes JavaScript and CSS files combined to one file." +"Flush Static Files Cache", "Flush Static Files Cache" +"Preprocessed view files and static files", "Preprocessed view files and static files" Catalog,Catalog JavaScript/CSS,JavaScript/CSS "JavaScript/CSS Cache","JavaScript/CSS Cache" diff --git a/app/code/Magento/Backend/i18n/pt_BR.csv b/app/code/Magento/Backend/i18n/pt_BR.csv index fddd1a2eba777c7ab248f5fd11993536cf260914..8bd82b41c2050a73b6cefcad5a4a53a280627769 100644 --- a/app/code/Magento/Backend/i18n/pt_BR.csv +++ b/app/code/Magento/Backend/i18n/pt_BR.csv @@ -412,6 +412,8 @@ Scope:,Scope: "Pregenerated product images files","Pregenerated product images files" "Flush JavaScript/CSS Cache","Flush JavaScript/CSS Cache" "Themes JavaScript and CSS files combined to one file.","Themes JavaScript and CSS files combined to one file." +"Flush Static Files Cache", "Flush Static Files Cache" +"Preprocessed view files and static files", "Preprocessed view files and static files" Catalog,Catalog JavaScript/CSS,JavaScript/CSS "JavaScript/CSS Cache","JavaScript/CSS Cache" diff --git a/app/code/Magento/Backend/i18n/zh_CN.csv b/app/code/Magento/Backend/i18n/zh_CN.csv index fddd1a2eba777c7ab248f5fd11993536cf260914..8bd82b41c2050a73b6cefcad5a4a53a280627769 100644 --- a/app/code/Magento/Backend/i18n/zh_CN.csv +++ b/app/code/Magento/Backend/i18n/zh_CN.csv @@ -412,6 +412,8 @@ Scope:,Scope: "Pregenerated product images files","Pregenerated product images files" "Flush JavaScript/CSS Cache","Flush JavaScript/CSS Cache" "Themes JavaScript and CSS files combined to one file.","Themes JavaScript and CSS files combined to one file." +"Flush Static Files Cache", "Flush Static Files Cache" +"Preprocessed view files and static files", "Preprocessed view files and static files" Catalog,Catalog JavaScript/CSS,JavaScript/CSS "JavaScript/CSS Cache","JavaScript/CSS Cache" diff --git a/app/code/Magento/Backend/view/adminhtml/templates/system/cache/additional.phtml b/app/code/Magento/Backend/view/adminhtml/templates/system/cache/additional.phtml index aa96f3db654c6b51e47cab7e548863de89be76d0..06eeedd275a76a1488c107d444d54287f1ed5f17 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/system/cache/additional.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/system/cache/additional.phtml @@ -9,16 +9,28 @@ <span><?php echo __('Additional Cache Management') ?></span> </div> <div class="field"> - <button onclick="setLocation('<?php echo $block->getCleanImagesUrl()?>')" type="button"> + <button onclick="setLocation('<?php echo $block->getCleanImagesUrl() ?>')" type="button"> <?php echo __('Flush Catalog Images Cache') ?> </button> - <label class="label"><?php echo __('Pregenerated product images files')?></label> + <label class="label"><?php echo __('Pregenerated product images files') ?></label> </div> <div class="field"> - <button onclick="setLocation('<?php echo $block->getCleanMediaUrl()?>')" type="button"> + <button onclick="setLocation('<?php echo $block->getCleanMediaUrl() ?>')" type="button"> <?php echo __('Flush JavaScript/CSS Cache') ?> </button> - <label class="label"><?php echo __('Themes JavaScript and CSS files combined to one file.')?></label> + <label class="label"><?php echo __('Themes JavaScript and CSS files combined to one file.') ?></label> </div> + <?php + if (!$block->isInProductionMode()): + ?> + <div class="field"> + <button onclick="setLocation('<?php echo $block->getCleanStaticFilesUrl() ?>')" type="button"> + <?php echo __('Flush Static Files Cache') ?> + </button> + <label class="label"><?php echo __('Preprocessed view files and static files') ?></label> + </div> + <?php + endif; + ?> <?php echo $block->getChildHtml(); ?> </div> diff --git a/app/code/Magento/Checkout/Block/Onepage/Success.php b/app/code/Magento/Checkout/Block/Onepage/Success.php index 46f85df2019ef53debf6b5583bffb9c7c264e6b0..5884c8f945a8bf12c68000fa10a195db1283a3f7 100644 --- a/app/code/Magento/Checkout/Block/Onepage/Success.php +++ b/app/code/Magento/Checkout/Block/Onepage/Success.php @@ -6,6 +6,7 @@ namespace Magento\Checkout\Block\Onepage; use Magento\Customer\Model\Context; +use Magento\Sales\Model\Order; /** * One page checkout success page @@ -17,16 +18,6 @@ class Success extends \Magento\Framework\View\Element\Template */ protected $_checkoutSession; - /** - * @var \Magento\Customer\Model\Session - */ - protected $_customerSession; - - /** - * @var \Magento\Sales\Model\OrderFactory - */ - protected $_orderFactory; - /** * @var \Magento\Sales\Model\Order\Config */ @@ -40,8 +31,6 @@ class Success extends \Magento\Framework\View\Element\Template /** * @param \Magento\Framework\View\Element\Template\Context $context * @param \Magento\Checkout\Model\Session $checkoutSession - * @param \Magento\Customer\Model\Session $customerSession - * @param \Magento\Sales\Model\OrderFactory $orderFactory * @param \Magento\Sales\Model\Order\Config $orderConfig * @param \Magento\Framework\App\Http\Context $httpContext * @param array $data @@ -49,31 +38,17 @@ class Success extends \Magento\Framework\View\Element\Template public function __construct( \Magento\Framework\View\Element\Template\Context $context, \Magento\Checkout\Model\Session $checkoutSession, - \Magento\Customer\Model\Session $customerSession, - \Magento\Sales\Model\OrderFactory $orderFactory, \Magento\Sales\Model\Order\Config $orderConfig, \Magento\Framework\App\Http\Context $httpContext, array $data = [] ) { parent::__construct($context, $data); $this->_checkoutSession = $checkoutSession; - $this->_customerSession = $customerSession; - $this->_orderFactory = $orderFactory; $this->_orderConfig = $orderConfig; $this->_isScopePrivate = true; $this->httpContext = $httpContext; } - /** - * See if the order has state, visible on frontend - * - * @return bool - */ - public function isOrderVisible() - { - return (bool)$this->_getData('is_order_visible'); - } - /** * Render additional order information lines and return result html * @@ -91,35 +66,60 @@ class Success extends \Magento\Framework\View\Element\Template */ protected function _beforeToHtml() { - $this->_prepareLastOrder(); + $this->prepareBlockData(); return parent::_beforeToHtml(); } /** - * Get last order ID from session, fetch it and check whether it can be viewed, printed etc + * Prepares block data * * @return void */ - protected function _prepareLastOrder() + protected function prepareBlockData() + { + $order = $this->_checkoutSession->getLastRealOrder(); + + $this->addData( + [ + 'is_order_visible' => $this->isVisible($order), + 'view_order_url' => $this->getUrl( + 'sales/order/view/', + ['order_id' => $order->getEntityId()] + ), + 'print_url' => $this->getUrl( + 'sales/order/print', + ['order_id' => $order->getEntityId()] + ), + 'can_print_order' => $this->isVisible($order), + 'can_view_order' => $this->canViewOrder($order), + 'order_id' => $order->getIncrementId() + ] + ); + } + + /** + * Is order visible + * + * @param Order $order + * @return bool + */ + protected function isVisible(Order $order) + { + return !in_array( + $order->getStatus(), + $this->_orderConfig->getInvisibleOnFrontStatuses() + ); + } + + /** + * Can view order + * + * @param Order $order + * @return bool + */ + protected function canViewOrder(Order $order) { - $orderId = $this->_checkoutSession->getLastOrderId(); - if ($orderId) { - $incrementId = $this->_checkoutSession->getLastRealOrderId(); - $status = $this->_checkoutSession->getLastOrderStatus(); - if ($status && $incrementId) { - $isVisible = !in_array($status, $this->_orderConfig->getInvisibleOnFrontStatuses()); - $canView = $this->httpContext->getValue(Context::CONTEXT_AUTH) && $isVisible; - $this->addData( - [ - 'is_order_visible' => $isVisible, - 'view_order_url' => $this->getUrl('sales/order/view/', ['order_id' => $orderId]), - 'print_url' => $this->getUrl('sales/order/print', ['order_id' => $orderId]), - 'can_print_order' => $isVisible, - 'can_view_order' => $canView, - 'order_id' => $incrementId, - ] - ); - } - } + return $this->httpContext->getValue(Context::CONTEXT_AUTH) + && $this->isVisible($order); } } diff --git a/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php b/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php index 54c8fee91f2c411fd470716906dc89087d403914..5d0c643d450d6cf7d64f566f4317ad35a1ec1a36 100644 --- a/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php @@ -5,6 +5,8 @@ */ namespace Magento\Checkout\Test\Unit\Block\Onepage; +use Magento\Sales\Model\Order; + /** * Class SuccessTest * @package Magento\Checkout\Block\Onepage @@ -32,13 +34,11 @@ class SuccessTest extends \PHPUnit_Framework_TestCase $this->orderConfig = $this->getMock('Magento\Sales\Model\Order\Config', [], [], '', false); - $this->checkoutSession = $this->getMock( - 'Magento\Checkout\Model\Session', - ['getLastOrderId', 'getLastRealOrderId', 'getLastOrderStatus'], - [], - '', - false - ); + $this->checkoutSession = $this->getMockBuilder( + 'Magento\Checkout\Model\Session' + ) + ->disableOriginalConstructor() + ->getMock(); $this->block = $objectManager->getObject( 'Magento\Checkout\Block\Onepage\Success', @@ -67,28 +67,36 @@ class SuccessTest extends \PHPUnit_Framework_TestCase /** * @dataProvider invisibleStatusesProvider + * * @param array $invisibleStatuses - * @param string $orderStatus * @param bool $expectedResult */ - public function testToHtmlOrderVisibleOnFront(array $invisibleStatuses, $orderStatus, $expectedResult) + public function testToHtmlOrderVisibleOnFront(array $invisibleStatuses, $expectedResult) { $orderId = 5; $realOrderId = 100003332; + $status = Order::STATE_PENDING_PAYMENT; + + $order = $this->getMockBuilder('Magento\Sales\Model\Order') + ->disableOriginalConstructor() + ->getMock(); $this->checkoutSession->expects($this->once()) - ->method('getLastOrderId') - ->will($this->returnValue($orderId)); - $this->checkoutSession->expects($this->once()) - ->method('getLastRealOrderId') - ->will($this->returnValue($realOrderId)); - $this->checkoutSession->expects($this->once()) - ->method('getLastOrderStatus') - ->will($this->returnValue($orderStatus)); + ->method('getLastRealOrder') + ->willReturn($order); + $order->expects($this->atLeastOnce()) + ->method('getEntityId') + ->willReturn($orderId); + $order->expects($this->atLeastOnce()) + ->method('getIncrementId') + ->willReturn($realOrderId); + $order->expects($this->atLeastOnce()) + ->method('getStatus') + ->willReturn($status); $this->orderConfig->expects($this->any()) ->method('getInvisibleOnFrontStatuses') - ->will($this->returnValue($invisibleStatuses)); + ->willReturn($invisibleStatuses); $this->block->toHtml(); @@ -98,8 +106,8 @@ class SuccessTest extends \PHPUnit_Framework_TestCase public function invisibleStatusesProvider() { return [ - [['status1', 'status2'], 'status1', false], - [['status1', 'status2'], 'status3', true] + [[Order::STATE_PENDING_PAYMENT, 'status2'], false], + [['status1', 'status2'], true] ]; } } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js index 7b679f3799b38a47b07585c1e46d16323f580948..d5de7247ff4d56027db27c20cd8ce1b628c7d854 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js @@ -209,6 +209,10 @@ define( emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid()); } + if (!emailValidationResult) { + $(loginFormSelector + ' input[name=username]').focus(); + } + if (this.isFormInline) { this.source.set('params.invalid', false); this.source.trigger('shippingAddress.data.validate'); diff --git a/app/code/Magento/Config/Block/System/Config/Form/Field/Datetime.php b/app/code/Magento/Config/Block/System/Config/Form/Field/Datetime.php index f6339dd68cd3149f38822875e82c25bcc15988e8..342a7307d4b647724745ca9d37ccae30bfb2432c 100644 --- a/app/code/Magento/Config/Block/System/Config/Form/Field/Datetime.php +++ b/app/code/Magento/Config/Block/System/Config/Form/Field/Datetime.php @@ -15,6 +15,7 @@ class Datetime extends \Magento\Config\Block\System\Config\Form\Field /** * @param AbstractElement $element * @return string + * @codeCoverageIgnore */ protected function _getElementHtml(AbstractElement $element) { diff --git a/app/code/Magento/Developer/Model/View/Asset/PreProcessor/DeveloperChain.php b/app/code/Magento/Developer/Model/View/Asset/PreProcessor/DeveloperChain.php index 7ef5b31ba966c8f5b59bf5133e5e4dddbcb16d15..37d5976ea46c4b9c3a27eaff452bfaa4d1279918 100644 --- a/app/code/Magento/Developer/Model/View/Asset/PreProcessor/DeveloperChain.php +++ b/app/code/Magento/Developer/Model/View/Asset/PreProcessor/DeveloperChain.php @@ -14,19 +14,20 @@ class DeveloperChain extends Chain * @param LocalInterface $asset * @param string $origContent * @param string $origContentType - * @param null $origAssetPath + * @param string $origAssetPath * @codeCoverageIgnore */ public function __construct( LocalInterface $asset, $origContent, $origContentType, - $origAssetPath = null + $origAssetPath ) { parent::__construct( $asset, $origContent, - $origContentType + $origContentType, + $origAssetPath ); $this->targetContentType = $this->origContentType; diff --git a/app/code/Magento/Developer/Model/View/Page/Config/ClientSideLessCompilation/Renderer.php b/app/code/Magento/Developer/Model/View/Page/Config/ClientSideLessCompilation/Renderer.php index eaf588a27cc671b76d66a0d74169fe4043b14317..edfbdcb5f638db8fa730eec738b068f20251a04d 100644 --- a/app/code/Magento/Developer/Model/View/Page/Config/ClientSideLessCompilation/Renderer.php +++ b/app/code/Magento/Developer/Model/View/Page/Config/ClientSideLessCompilation/Renderer.php @@ -19,7 +19,6 @@ class Renderer extends Config\Renderer /** * @param Config $pageConfig - * @param \Magento\Framework\View\Asset\MinifyService $assetMinifyService * @param \Magento\Framework\View\Asset\MergeService $assetMergeService * @param \Magento\Framework\UrlInterface $urlBuilder * @param \Magento\Framework\Escaper $escaper @@ -29,7 +28,6 @@ class Renderer extends Config\Renderer */ public function __construct( Config $pageConfig, - \Magento\Framework\View\Asset\MinifyService $assetMinifyService, \Magento\Framework\View\Asset\MergeService $assetMergeService, \Magento\Framework\UrlInterface $urlBuilder, \Magento\Framework\Escaper $escaper, @@ -41,7 +39,6 @@ class Renderer extends Config\Renderer parent::__construct( $pageConfig, - $assetMinifyService, $assetMergeService, $urlBuilder, $escaper, diff --git a/app/code/Magento/Dhl/Model/Carrier.php b/app/code/Magento/Dhl/Model/Carrier.php index 4e28283eae0edeef9c1ce24e695ab02b198227d7..498842814bd892478ebeffadf3b4b654d8d3499d 100644 --- a/app/code/Magento/Dhl/Model/Carrier.php +++ b/app/code/Magento/Dhl/Model/Carrier.php @@ -15,6 +15,7 @@ use Magento\Quote\Model\Quote\Address\RateRequest; use Magento\Quote\Model\Quote\Address\RateResult\Error; use Magento\Shipping\Model\Carrier\AbstractCarrier; use Magento\Shipping\Model\Rate\Result; +use Magento\Framework\Xml\Security; /** * DHL International (API v1.4) @@ -192,6 +193,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory * @param \Psr\Log\LoggerInterface $logger + * @param Security $xmlSecurity * @param \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory * @param \Magento\Shipping\Model\Rate\ResultFactory $rateFactory * @param \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory @@ -202,6 +204,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin * @param \Magento\Directory\Model\CountryFactory $countryFactory * @param \Magento\Directory\Model\CurrencyFactory $currencyFactory * @param \Magento\Directory\Helper\Data $directoryData + * @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry * @param \Magento\Shipping\Helper\Carrier $carrierHelper * @param \Magento\Framework\Stdlib\DateTime\DateTime $coreDate * @param \Magento\Framework\Module\Dir\Reader $configReader @@ -211,7 +214,6 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin * @param \Magento\Framework\Filesystem $filesystem * @param \Magento\Framework\Stdlib\DateTime $dateTime * @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory - * @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry * @param array $data * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -219,6 +221,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory, \Psr\Log\LoggerInterface $logger, + Security $xmlSecurity, \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory, \Magento\Shipping\Model\Rate\ResultFactory $rateFactory, \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory, @@ -254,6 +257,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin $scopeConfig, $rateErrorFactory, $logger, + $xmlSecurity, $xmlElFactory, $rateFactory, $rateMethodFactory, diff --git a/app/code/Magento/Dhl/Test/Unit/Model/CarrierTest.php b/app/code/Magento/Dhl/Test/Unit/Model/CarrierTest.php index 3170777d18318f1e8a3bfdeb15b8050ce3188f18..d6cb174acf25016970118222111a8656b5e7fe78 100644 --- a/app/code/Magento/Dhl/Test/Unit/Model/CarrierTest.php +++ b/app/code/Magento/Dhl/Test/Unit/Model/CarrierTest.php @@ -5,6 +5,8 @@ */ namespace Magento\Dhl\Test\Unit\Model; +use Magento\Framework\Xml\Security; + class CarrierTest extends \PHPUnit_Framework_TestCase { /** @@ -145,6 +147,7 @@ class CarrierTest extends \PHPUnit_Framework_TestCase 'Magento\Dhl\Model\Carrier', [ 'scopeConfig' => $scopeConfig, + 'xmlSecurity' => new Security(), 'xmlElFactory' => $xmlElFactory, 'rateFactory' => $rateFactory, 'rateMethodFactory' => $rateMethodFactory, diff --git a/app/code/Magento/Downloadable/Block/Checkout/Success.php b/app/code/Magento/Downloadable/Block/Checkout/Success.php index 644ecc9688535b31ac5d42420568a0099677b319..65c8b92484168792700f39895e6b71a2e8e1c284 100644 --- a/app/code/Magento/Downloadable/Block/Checkout/Success.php +++ b/app/code/Magento/Downloadable/Block/Checkout/Success.php @@ -23,8 +23,6 @@ class Success extends \Magento\Checkout\Block\Onepage\Success /** * @param Template\Context $context * @param \Magento\Checkout\Model\Session $checkoutSession - * @param \Magento\Customer\Model\Session $customerSession - * @param \Magento\Sales\Model\OrderFactory $orderFactory * @param \Magento\Sales\Model\Order\Config $orderConfig * @param \Magento\Framework\App\Http\Context $httpContext * @param \Magento\Customer\Helper\Session\CurrentCustomer $currentCustomer @@ -33,8 +31,6 @@ class Success extends \Magento\Checkout\Block\Onepage\Success public function __construct( \Magento\Framework\View\Element\Template\Context $context, \Magento\Checkout\Model\Session $checkoutSession, - \Magento\Customer\Model\Session $customerSession, - \Magento\Sales\Model\OrderFactory $orderFactory, \Magento\Sales\Model\Order\Config $orderConfig, \Magento\Framework\App\Http\Context $httpContext, \Magento\Customer\Helper\Session\CurrentCustomer $currentCustomer, @@ -43,8 +39,6 @@ class Success extends \Magento\Checkout\Block\Onepage\Success parent::__construct( $context, $checkoutSession, - $customerSession, - $orderFactory, $orderConfig, $httpContext, $data @@ -56,21 +50,29 @@ class Success extends \Magento\Checkout\Block\Onepage\Success * Return true if order(s) has one or more downloadable products * * @return bool - * @SuppressWarnings(PHPMD.BooleanGetMethodName) */ - public function getOrderHasDownloadable() + private function orderHasDownloadableProducts() { - $hasDownloadableFlag = $this->_checkoutSession->getHasDownloadableProducts(true); - if (!$this->isOrderVisible()) { - return false; - } - /** - * if use guest checkout - */ - if (!$this->currentCustomer->getCustomerId()) { - return false; - } - return $hasDownloadableFlag; + return $this->isVisible($this->_checkoutSession->getLastRealOrder()) + && $this->currentCustomer->getCustomerId() + ? $this->_checkoutSession->getHasDownloadableProducts(true) + : false; + } + + /** + * Prepares block data + * + * @return void + */ + protected function prepareBlockData() + { + parent::prepareBlockData(); + + $this->addData( + [ + 'order_has_downloadable' => $this->orderHasDownloadableProducts() + ] + ); } /** diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index db802c1912e2c9ca34d2ba5a1c89d989d11b79fd..69d52fead5bb266011b23c30efaef43086384d05 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -11,6 +11,7 @@ namespace Magento\Fedex\Model; use Magento\Quote\Model\Quote\Address\RateRequest; use Magento\Shipping\Model\Carrier\AbstractCarrierOnline; use Magento\Shipping\Model\Rate\Result; +use Magento\Framework\Xml\Security; /** * Fedex shipping implementation @@ -121,6 +122,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory * @param \Psr\Log\LoggerInterface $logger + * @param Security $xmlSecurity * @param \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory * @param \Magento\Shipping\Model\Rate\ResultFactory $rateFactory * @param \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory @@ -143,6 +145,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory, \Psr\Log\LoggerInterface $logger, + Security $xmlSecurity, \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory, \Magento\Shipping\Model\Rate\ResultFactory $rateFactory, \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory, @@ -165,6 +168,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C $scopeConfig, $rateErrorFactory, $logger, + $xmlSecurity, $xmlElFactory, $rateFactory, $rateMethodFactory, diff --git a/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php b/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php index c9100c8f451830eb20f8a01cfc4b00eec9013f92..37717163a595f11076fa23e0095c40774b121f7b 100644 --- a/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php +++ b/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php @@ -6,6 +6,7 @@ namespace Magento\Fedex\Test\Unit\Model; use Magento\Framework\Object; +use Magento\Framework\Xml\Security; /** * Class CarrierTest @@ -79,6 +80,7 @@ class CarrierTest extends \PHPUnit_Framework_TestCase 'rateErrorFactory' => $this->getMock('Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory', [], [], '', false), 'logger' => $this->getMock('Psr\Log\LoggerInterface'), + 'xmlSecurity' => new Security(), 'xmlElFactory' => $this->getMock('Magento\Shipping\Model\Simplexml\ElementFactory', [], [], '', false), 'rateFactory' => $rateFactory, 'rateMethodFactory' => $rateMethodFactory, diff --git a/app/code/Magento/Paypal/Model/Payflow/Service/Response/Handler/FraudHandler.php b/app/code/Magento/Paypal/Model/Payflow/Service/Response/Handler/FraudHandler.php index 4553ff54e53d8cfb5c18d261358fd0eb24062bdb..63003f7f15c0e55469ea474b02ae0ac0f7db2ed6 100644 --- a/app/code/Magento/Paypal/Model/Payflow/Service/Response/Handler/FraudHandler.php +++ b/app/code/Magento/Paypal/Model/Payflow/Service/Response/Handler/FraudHandler.php @@ -9,7 +9,12 @@ use Magento\Framework\Object; use Magento\Payment\Model\InfoInterface; use Magento\Paypal\Model\Info; use Magento\Paypal\Model\Payflowpro; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Xml\Security; +/** + * Class FraudHandler + */ class FraudHandler implements HandlerInterface { /** @@ -28,11 +33,22 @@ class FraudHandler implements HandlerInterface private $paypalInfoManager; /** + * The security scanner XML document + * + * @var Security + */ + private $xmlSecurity; + + /** + * Constructor + * * @param Info $paypalInfoManager + * @param Security $xmlSecurity */ - public function __construct(Info $paypalInfoManager) + public function __construct(Info $paypalInfoManager, Security $xmlSecurity) { $this->paypalInfoManager = $paypalInfoManager; + $this->xmlSecurity = $xmlSecurity; } /** @@ -76,11 +92,16 @@ class FraudHandler implements HandlerInterface * * @param string $rulesString * @return array + * @throws LocalizedException */ private function getFraudRulesDictionary($rulesString) { - libxml_use_internal_errors(true); $rules = []; + + if (!$this->xmlSecurity->scan($rulesString)) { + return $rules; + } + try { $rulesXml = new \SimpleXMLElement($rulesString); foreach ($rulesXml->{'rule'} as $rule) { diff --git a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/FraudHandlerTest.php b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/FraudHandlerTest.php index 71ed0ff7bff3c7281ca8e2f125f4106d8d6e58b2..dee2f88f42f440f73456c46283a3ce9b7404b650 100644 --- a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/FraudHandlerTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/FraudHandlerTest.php @@ -44,7 +44,10 @@ class FraudHandlerTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); - $this->fraudHandler = new FraudHandler($this->paypalInfoManagerMock); + $this->fraudHandler = new FraudHandler( + $this->paypalInfoManagerMock, + new \Magento\Framework\Xml\Security() + ); } public function testHandleApprovedTransaction() @@ -124,11 +127,12 @@ class FraudHandlerTest extends \PHPUnit_Framework_TestCase /** * Returns rules xml list as string * + * @param string $fileName * @return string */ - private function getRulesXmlString() + private function getRulesXmlString($fileName = 'fps_prexmldata.xml') { - return file_get_contents(__DIR__ .'/_files/fps_prexmldata.xml'); + return file_get_contents(__DIR__ . '/_files/' . $fileName); } /** @@ -153,4 +157,45 @@ class FraudHandlerTest extends \PHPUnit_Framework_TestCase 'The billing address is not a valid USAddress' ]; } + + /** + * Check attempting to read invalid XML file (XXE XML) + */ + public function testHandleXXEXml() + { + $file = __DIR__ . '/_files/xxe-xml.txt'; + $rulesString = str_replace('{file}', $file, $this->getRulesXmlString('xxe_fps_prexmldata.xml')); + + $this->responseMock->expects($this->atLeastOnce()) + ->method('getData') + ->willReturnMap( + [ + [FraudHandler::RESPONSE_MESSAGE, null, 'New fraud message'], + [FraudHandler::FRAUD_RULES_XML, null, $rulesString], + ['result', null, Payflowpro::RESPONSE_CODE_FRAUDSERVICE_FILTER] + ] + ); + $this->paymentMock->expects($this->once()) + ->method('getAdditionalInformation') + ->with(Info::FRAUD_FILTERS) + ->willReturn( + [ + 'Total Purchase Price Ceiling' => 'Existing fraud message', + 'RESPMSG' => 'Existing fraud message' + ] + ); + + $this->paypalInfoManagerMock->expects($this->once()) + ->method('importToPayment') + ->with( + [ + Info::FRAUD_FILTERS => [ + 'RESPMSG' => 'Existing fraud message', + 'Total Purchase Price Ceiling' => 'Existing fraud message' + ] + ] + ); + + $this->fraudHandler->handle($this->paymentMock, $this->responseMock); + } } diff --git a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/_files/xxe-xml.txt b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/_files/xxe-xml.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6099913174aa4149bdc5f07a17ca1a13a5e6978 --- /dev/null +++ b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/_files/xxe-xml.txt @@ -0,0 +1 @@ +the private content \ No newline at end of file diff --git a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/_files/xxe_fps_prexmldata.xml b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/_files/xxe_fps_prexmldata.xml new file mode 100644 index 0000000000000000000000000000000000000000..02c3724a1caf1a982b654d55ebae2161efbc5825 --- /dev/null +++ b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/Response/Handler/_files/xxe_fps_prexmldata.xml @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!DOCTYPE scan [<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource={file}">]> +<triggeredRules> + <scan>&test;</scan> + <rule num="1"> + <ruleId>2</ruleId> + <ruleAlias>CeilingAmount</ruleAlias> + <ruleDescription>Total Purchase Price Ceiling</ruleDescription> + <action>R</action> + <triggeredMessage>The purchase amount of 7501 is greater than the ceiling value set of 7500</triggeredMessage> + <rulevendorparms> + <ruleParameter num="1"> + <name>CeilingValue</name> + <value type="USD">75.00</value> + </ruleParameter> + </rulevendorparms> + </rule> + <rule num="2"> + <ruleId>6</ruleId> + <ruleAlias>HighOrderNumber</ruleAlias> + <ruleDescription>Total ItemCeiling</ruleDescription> + <action>R</action> + <triggeredMessage>16 items were ordered, which is overthe maximum allowed quantity of 15</triggeredMessage> + <rulevendorparms> + <ruleParameter num="1"> + <name>Value</name> + <value type="Integer">15</value> + </ruleParameter> + </rulevendorparms> + </rule> + <rule num="3"> + <ruleId>7</ruleId> + <ruleAlias>BillShipMismatch</ruleAlias> + <ruleDescription>Shipping/BillingMismatch</ruleDescription> + <action>R</action> + <triggeredMessage>Thebilling and shipping addresses did not match</triggeredMessage> + </rule> + <rule num="4"> + <ruleId>13</ruleId> + <ruleAlias>HighRiskBinCheck</ruleAlias> + <ruleDescription>BIN Risk List Match</ruleDescription> + <action>R</action> + <triggeredMessage>The card number is in a high risk bin list</triggeredMessage> + </rule> + <rule num="5"> + <ruleId>37</ruleId> + <ruleAlias>HighRiskZIPCheck</ruleAlias> + <ruleDescription>Zip Risk List Match</ruleDescription> + <action>R</action> + <triggeredMessage>High risk shipping zip</triggeredMessage> + </rule> + <rule num="6"> + <ruleId>16</ruleId> + <ruleAlias>BillUSPostalAddressCheck</ruleAlias> + <ruleDescription>USPS Address Validation Failure</ruleDescription> + <action>R</action> + <triggeredMessage>The billing address is not a valid USAddress</triggeredMessage> + <rulevendorparms> + <ruleParameter num="1"> + <name>AddressToVerify</name> + <value type="String">bill</value> + </ruleParameter> + </rulevendorparms> + </rule> +</triggeredRules> \ No newline at end of file diff --git a/app/code/Magento/RequireJs/Block/Html/Head/Config.php b/app/code/Magento/RequireJs/Block/Html/Head/Config.php index bf525dbf4034a748f4f1ea0709a71bb2778688b4..8eec827a91fdbb6c979544ec7920d853dd922b2b 100644 --- a/app/code/Magento/RequireJs/Block/Html/Head/Config.php +++ b/app/code/Magento/RequireJs/Block/Html/Head/Config.php @@ -7,6 +7,7 @@ namespace Magento\RequireJs\Block\Html\Head; use Magento\Framework\RequireJs\Config as RequireJsConfig; +use Magento\Framework\View\Asset\Minification; /** * Block responsible for including RequireJs config on the page @@ -28,12 +29,18 @@ class Config extends \Magento\Framework\View\Element\AbstractBlock */ protected $pageConfig; + /** + * @var Minification + */ + protected $minification; + /** * @param \Magento\Framework\View\Element\Context $context * @param RequireJsConfig $config * @param \Magento\RequireJs\Model\FileManager $fileManager * @param \Magento\Framework\View\Page\Config $pageConfig * @param \Magento\Framework\View\Asset\ConfigInterface $bundleConfig + * @param Minification $minification * @param array $data */ public function __construct( @@ -42,6 +49,7 @@ class Config extends \Magento\Framework\View\Element\AbstractBlock \Magento\RequireJs\Model\FileManager $fileManager, \Magento\Framework\View\Page\Config $pageConfig, \Magento\Framework\View\Asset\ConfigInterface $bundleConfig, + Minification $minification, array $data = [] ) { parent::__construct($context, $data); @@ -49,6 +57,7 @@ class Config extends \Magento\Framework\View\Element\AbstractBlock $this->fileManager = $fileManager; $this->pageConfig = $pageConfig; $this->bundleConfig = $bundleConfig; + $this->minification = $minification; } /** @@ -58,11 +67,21 @@ class Config extends \Magento\Framework\View\Element\AbstractBlock */ protected function _prepareLayout() { - $after = RequireJsConfig::REQUIRE_JS_FILE_NAME; $requireJsConfig = $this->fileManager->createRequireJsConfigAsset(); $requireJsMixinsConfig = $this->fileManager->createRequireJsMixinsAsset(); $assetCollection = $this->pageConfig->getAssetCollection(); + $after = RequireJsConfig::REQUIRE_JS_FILE_NAME; + if ($this->minification->isEnabled('js')) { + $minResolver = $this->fileManager->createMinResolverAsset(); + $assetCollection->insert( + $minResolver->getFilePath(), + $minResolver, + $after + ); + $after = $minResolver->getFilePath(); + } + if ($this->bundleConfig->isBundlingJsFiles()) { $bundleAssets = $this->fileManager->createBundleJsPool(); $staticAsset = $this->fileManager->createStaticJsAsset(); @@ -74,7 +93,7 @@ class Config extends \Magento\Framework\View\Element\AbstractBlock $assetCollection->insert( $bundleAsset->getFilePath(), $bundleAsset, - RequireJsConfig::REQUIRE_JS_FILE_NAME + $after ); } $assetCollection->insert( diff --git a/app/code/Magento/RequireJs/Model/FileManager.php b/app/code/Magento/RequireJs/Model/FileManager.php index 6ee4aae67fa381cd89127997ec3634e73901f734..7c9dee16935ef74bf780cf13109b4b23ed70c023 100644 --- a/app/code/Magento/RequireJs/Model/FileManager.php +++ b/app/code/Magento/RequireJs/Model/FileManager.php @@ -6,6 +6,8 @@ namespace Magento\RequireJs\Model; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\State as AppState; +use Magento\Framework\RequireJs\Config; /** * A service for handling RequireJS files in the application @@ -13,7 +15,7 @@ use Magento\Framework\App\Filesystem\DirectoryList; class FileManager { /** - * @var \Magento\Framework\RequireJs\Config + * @var Config */ private $config; @@ -23,7 +25,7 @@ class FileManager private $filesystem; /** - * @var \Magento\Framework\App\State + * @var AppState */ private $appState; @@ -33,15 +35,15 @@ class FileManager private $assetRepo; /** - * @param \Magento\Framework\RequireJs\Config $config + * @param Config $config * @param \Magento\Framework\Filesystem $appFilesystem - * @param \Magento\Framework\App\State $appState + * @param AppState $appState * @param \Magento\Framework\View\Asset\Repository $assetRepo */ public function __construct( - \Magento\Framework\RequireJs\Config $config, + Config $config, \Magento\Framework\Filesystem $appFilesystem, - \Magento\Framework\App\State $appState, + AppState $appState, \Magento\Framework\View\Asset\Repository $assetRepo ) { $this->config = $config; @@ -62,6 +64,18 @@ class FileManager return $this->assetRepo->createArbitrary($relPath, ''); } + /** + * Create '.min' files resolver asset + * + * @return \Magento\Framework\View\Asset\File + */ + public function createMinResolverAsset() + { + $relPath = $this->config->getMinResolverRelativePath(); + $this->ensureMinResolverFile($relPath); + return $this->assetRepo->createArbitrary($relPath, ''); + } + /** * Create a view asset representing the aggregated configuration file * @@ -95,11 +109,25 @@ class FileManager private function ensureSourceFile($relPath) { $dir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); - if ($this->appState->getMode() == \Magento\Framework\App\State::MODE_DEVELOPER || !$dir->isExist($relPath)) { + if ($this->appState->getMode() == AppState::MODE_DEVELOPER || !$dir->isExist($relPath)) { $dir->writeFile($relPath, $this->config->getConfig()); } } + /** + * Make sure the '.min' assets resolver is materialized + * + * @param string $relPath + * @return void + */ + private function ensureMinResolverFile($relPath) + { + $dir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); + if ($this->appState->getMode() == AppState::MODE_DEVELOPER || !$dir->isExist($relPath)) { + $dir->writeFile($relPath, $this->config->getMinResolverCode()); + } + } + /** * Create a view asset representing the static js functionality * @@ -107,11 +135,11 @@ class FileManager */ public function createStaticJsAsset() { - if ($this->appState->getMode() != \Magento\Framework\App\State::MODE_PRODUCTION) { + if ($this->appState->getMode() != AppState::MODE_PRODUCTION) { return false; } $libDir = $this->filesystem->getDirectoryRead(DirectoryList::STATIC_VIEW); - $relPath = $libDir->getRelativePath(\Magento\Framework\RequireJs\Config::STATIC_FILE_NAME); + $relPath = $libDir->getRelativePath(Config::STATIC_FILE_NAME); /** @var $context \Magento\Framework\View\Asset\File\FallbackContext */ $context = $this->assetRepo->getStaticViewFileContext(); @@ -126,12 +154,12 @@ class FileManager public function createBundleJsPool() { $bundles = []; - if ($this->appState->getMode() == \Magento\Framework\App\State::MODE_PRODUCTION) { + if ($this->appState->getMode() == AppState::MODE_PRODUCTION) { $libDir = $this->filesystem->getDirectoryRead(DirectoryList::STATIC_VIEW); /** @var $context \Magento\Framework\View\Asset\File\FallbackContext */ $context = $this->assetRepo->getStaticViewFileContext(); - $bundleDir = $context->getPath() . '/' .\Magento\Framework\RequireJs\Config::BUNDLE_JS_DIR; + $bundleDir = $context->getPath() . '/' . Config::BUNDLE_JS_DIR; if (!$libDir->isExist($bundleDir)) { return []; diff --git a/app/code/Magento/RequireJs/Test/Unit/Block/Html/Head/ConfigTest.php b/app/code/Magento/RequireJs/Test/Unit/Block/Html/Head/ConfigTest.php index 66cf3ce50736e74c89ca2edc60593323c4ec315f..e976f7563a84539744a186bb9b2b08653e607bd1 100644 --- a/app/code/Magento/RequireJs/Test/Unit/Block/Html/Head/ConfigTest.php +++ b/app/code/Magento/RequireJs/Test/Unit/Block/Html/Head/ConfigTest.php @@ -36,10 +36,15 @@ class ConfigTest extends \PHPUnit_Framework_TestCase protected $blockConfig; /** - * @var \Magento\Framework\View\Page\Config|\Magento\Framework\View\Asset\ConfigInterface + * @var \Magento\Framework\View\Asset\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $bundleConfig; + /** + * @var \Magento\Framework\View\Asset\Minification|\PHPUnit_Framework_MockObject_MockObject + */ + private $minificationMock; + protected function setUp() { $this->context = $this->getMock('\Magento\Framework\View\Element\Context', [], [], '', false); @@ -65,6 +70,11 @@ class ConfigTest extends \PHPUnit_Framework_TestCase ->expects($this->atLeastOnce()) ->method('getFilePath') ->willReturn('/path/to/require/require.js'); + $minResolverAsset = $this->getMockForAbstractClass('\Magento\Framework\View\Asset\LocalInterface'); + $minResolverAsset + ->expects($this->atLeastOnce()) + ->method('getFilePath') + ->willReturn('/path/to/require/require-min-resolver.js'); $this->fileManager ->expects($this->once()) @@ -82,6 +92,10 @@ class ConfigTest extends \PHPUnit_Framework_TestCase ->expects($this->once()) ->method('createBundleJsPool') ->will($this->returnValue([$asset])); + $this->fileManager + ->expects($this->once()) + ->method('createMinResolverAsset') + ->will($this->returnValue($minResolverAsset)); $layout = $this->getMock('Magento\Framework\View\LayoutInterface'); @@ -97,7 +111,24 @@ class ConfigTest extends \PHPUnit_Framework_TestCase ->method('insert') ->willReturn(true); - $object = new Config($this->context, $this->config, $this->fileManager, $this->pageConfig, $this->bundleConfig); + $this->minificationMock = $this->getMockBuilder('Magento\Framework\View\Asset\Minification') + ->disableOriginalConstructor() + ->getMock(); + $this->minificationMock + ->expects($this->any()) + ->method('isEnabled') + ->with('js') + ->willReturn(true); + + + $object = new Config( + $this->context, + $this->config, + $this->fileManager, + $this->pageConfig, + $this->bundleConfig, + $this->minificationMock + ); $object->setLayout($layout); } @@ -112,7 +143,18 @@ class ConfigTest extends \PHPUnit_Framework_TestCase $this->getMockForAbstractClass('\Magento\Framework\App\Config\ScopeConfigInterface') )); $this->config->expects($this->once())->method('getBaseConfig')->will($this->returnValue('the config data')); - $object = new Config($this->context, $this->config, $this->fileManager, $this->pageConfig, $this->bundleConfig); + $this->minificationMock = $this->getMockBuilder('Magento\Framework\View\Asset\Minification') + ->disableOriginalConstructor() + ->getMock(); + + $object = new Config( + $this->context, + $this->config, + $this->fileManager, + $this->pageConfig, + $this->bundleConfig, + $this->minificationMock + ); $html = $object->toHtml(); $expectedFormat = <<<expected <script type="text/javascript"> diff --git a/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php b/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php index 7905f9457db66c92c71520315c00d89c55247d4b..626db1149f1e5027c6ae75b7c7ca07174516b81c 100644 --- a/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php +++ b/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php @@ -14,7 +14,7 @@ class FileManagerTest extends \PHPUnit_Framework_TestCase /** * @var \Magento\Framework\RequireJs\Config|\PHPUnit_Framework_MockObject_MockObject */ - private $config; + private $configMock; /** * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject @@ -44,15 +44,15 @@ class FileManagerTest extends \PHPUnit_Framework_TestCase /** * @var \Magento\Framework\View\Asset\Repository|\PHPUnit_Framework_MockObject_MockObject */ - private $assetRepo; + private $assetRepoMock; protected function setUp() { - $this->config = $this->getMock('\Magento\Framework\RequireJs\Config', [], [], '', false); + $this->configMock = $this->getMock('\Magento\Framework\RequireJs\Config', [], [], '', false); $this->fileSystem = $this->getMock('\Magento\Framework\Filesystem', [], [], '', false); $this->appState = $this->getMock('\Magento\Framework\App\State', [], [], '', false); - $this->assetRepo = $this->getMock('\Magento\Framework\View\Asset\Repository', [], [], '', false); - $this->object = new FileManager($this->config, $this->fileSystem, $this->appState, $this->assetRepo); + $this->assetRepoMock = $this->getMock('\Magento\Framework\View\Asset\Repository', [], [], '', false); + $this->object = new FileManager($this->configMock, $this->fileSystem, $this->appState, $this->assetRepoMock); $this->dir = $this->getMockForAbstractClass('\Magento\Framework\Filesystem\Directory\WriteInterface'); $this->asset = $this->getMock('\Magento\Framework\View\Asset\File', [], [], '', false); } @@ -63,14 +63,14 @@ class FileManagerTest extends \PHPUnit_Framework_TestCase */ public function testCreateRequireJsConfigAsset($exists) { - $this->config->expects($this->once()) + $this->configMock->expects($this->once()) ->method('getConfigFileRelativePath') ->will($this->returnValue('requirejs/file.js')); $this->fileSystem->expects($this->once()) ->method('getDirectoryWrite') ->with(DirectoryList::STATIC_VIEW) ->will($this->returnValue($this->dir)); - $this->assetRepo->expects($this->once()) + $this->assetRepoMock->expects($this->once()) ->method('createArbitrary') ->with('requirejs/file.js', '') ->will($this->returnValue($this->asset)); @@ -81,11 +81,11 @@ class FileManagerTest extends \PHPUnit_Framework_TestCase ->with('requirejs/file.js') ->will($this->returnValue($exists)); if ($exists) { - $this->config->expects($this->never())->method('getConfig'); + $this->configMock->expects($this->never())->method('getConfig'); $this->dir->expects($this->never())->method('writeFile'); } else { $data = 'requirejs config data'; - $this->config->expects($this->once())->method('getConfig')->will($this->returnValue($data)); + $this->configMock->expects($this->once())->method('getConfig')->will($this->returnValue($data)); $this->dir->expects($this->once())->method('writeFile')->with('requirejs/file.js', $data); } $this->assertSame($this->asset, $this->object->createRequireJsConfigAsset()); @@ -101,14 +101,14 @@ class FileManagerTest extends \PHPUnit_Framework_TestCase public function testCreateRequireJsAssetDevMode() { - $this->config->expects($this->once()) + $this->configMock->expects($this->once()) ->method('getConfigFileRelativePath') ->will($this->returnValue('requirejs/file.js')); $this->fileSystem->expects($this->once()) ->method('getDirectoryWrite') ->with(DirectoryList::STATIC_VIEW) ->will($this->returnValue($this->dir)); - $this->assetRepo->expects($this->once()) + $this->assetRepoMock->expects($this->once()) ->method('createArbitrary') ->with('requirejs/file.js', '') ->will($this->returnValue($this->asset)); @@ -118,14 +118,14 @@ class FileManagerTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue(\Magento\Framework\App\State::MODE_DEVELOPER)); $this->dir->expects($this->never())->method('isExist'); $data = 'requirejs config data'; - $this->config->expects($this->once())->method('getConfig')->will($this->returnValue($data)); + $this->configMock->expects($this->once())->method('getConfig')->will($this->returnValue($data)); $this->dir->expects($this->once())->method('writeFile')->with('requirejs/file.js', $data); $this->assertSame($this->asset, $this->object->createRequireJsConfigAsset()); } public function testCreateBundleJsPool() { - unset($this->config); + unset($this->configMock); $dirRead = $this->getMock('Magento\Framework\Filesystem\Directory\Read', [], [], 'libDir', false); $context = $this->getMock('Magento\Framework\View\Asset\File\FallbackContext', [], [], '', false); $assetRepo = $this->getMock('Magento\Framework\View\Asset\Repository', [], [], '', false); @@ -189,4 +189,22 @@ class FileManagerTest extends \PHPUnit_Framework_TestCase $this->assertArrayHasKey('0', $result); $this->assertArrayHasKey('1', $result); } + + public function testCreateMinResolverAsset() + { + $this->configMock + ->expects($this->any()) + ->method('getMinResolverRelativePath') + ->willReturn('relative path'); + $this->assetRepoMock + ->expects($this->once()) + ->method('createArbitrary') + ->with('relative path'); + $this->fileSystem->expects($this->once()) + ->method('getDirectoryWrite') + ->with(DirectoryList::STATIC_VIEW) + ->will($this->returnValue($this->dir)); + + $this->object->createMinResolverAsset(); + } } diff --git a/app/code/Magento/RequireJs/etc/di.xml b/app/code/Magento/RequireJs/etc/di.xml index 457a8c49f0c7bf8a9a0860a90e8d4e79318a9e82..305fa59d47e1840a5ee3cc1c60751d35f86ba781 100644 --- a/app/code/Magento/RequireJs/etc/di.xml +++ b/app/code/Magento/RequireJs/etc/di.xml @@ -33,4 +33,9 @@ <argument name="themeFiles" xsi:type="object">Magento\Framework\View\File\Collector\Theme</argument> </arguments> </type> + <type name="Magento\Framework\RequireJs\Config"> + <arguments> + <argument name="minifyAdapter" xsi:type="object">jsMinificationAdapter</argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php index 99e544593f16bc73c2b191233afa2ffe99184657..047130de3eccc973abbc7708cf24e031bfcd1e19 100644 --- a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php +++ b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php @@ -9,6 +9,7 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Quote\Model\Quote\Address\RateRequest; use Magento\Quote\Model\Quote\Address\RateResult\Error; use Magento\Shipping\Model\Shipment\Request; +use Magento\Framework\Xml\Security; /** * Abstract online shipping carrier model @@ -102,10 +103,18 @@ abstract class AbstractCarrierOnline extends AbstractCarrier */ protected $_rawRequest = null; + /** + * The security scanner XML document + * + * @var Security + */ + protected $xmlSecurity; + /** * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory * @param \Psr\Log\LoggerInterface $logger + * @param Security $xmlSecurity * @param \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory * @param \Magento\Shipping\Model\Rate\ResultFactory $rateFactory * @param \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory @@ -125,6 +134,7 @@ abstract class AbstractCarrierOnline extends AbstractCarrier \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory, \Psr\Log\LoggerInterface $logger, + Security $xmlSecurity, \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory, \Magento\Shipping\Model\Rate\ResultFactory $rateFactory, \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory, @@ -150,6 +160,7 @@ abstract class AbstractCarrierOnline extends AbstractCarrier $this->_directoryData = $directoryData; $this->stockRegistry = $stockRegistry; parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data); + $this->xmlSecurity = $xmlSecurity; } /** @@ -620,12 +631,19 @@ abstract class AbstractCarrierOnline extends AbstractCarrier * * @param string $xmlContent * @param string $customSimplexml - * * @return \SimpleXMLElement|bool + * @throws LocalizedException + * * @api */ public function parseXml($xmlContent, $customSimplexml = 'SimpleXMLElement') { - return simplexml_load_string($xmlContent, $customSimplexml); + if (!$this->xmlSecurity->scan($xmlContent)) { + throw new LocalizedException(__('Security validation of XML document has been failed.')); + } + + $xmlElement = simplexml_load_string($xmlContent, $customSimplexml); + + return $xmlElement; } } diff --git a/app/code/Magento/Shipping/Test/Unit/Model/Carrier/AbstractCarrierOnline/xxe-xml.txt b/app/code/Magento/Shipping/Test/Unit/Model/Carrier/AbstractCarrierOnline/xxe-xml.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6099913174aa4149bdc5f07a17ca1a13a5e6978 --- /dev/null +++ b/app/code/Magento/Shipping/Test/Unit/Model/Carrier/AbstractCarrierOnline/xxe-xml.txt @@ -0,0 +1 @@ +the private content \ No newline at end of file diff --git a/app/code/Magento/Shipping/Test/Unit/Model/Carrier/AbstractCarrierOnlineTest.php b/app/code/Magento/Shipping/Test/Unit/Model/Carrier/AbstractCarrierOnlineTest.php index d6f5bd813bcb526b736e417ee8ebd6d71cc528d2..1de311ef47aaff7cbf05be0ebb8eb29ee7853402 100644 --- a/app/code/Magento/Shipping/Test/Unit/Model/Carrier/AbstractCarrierOnlineTest.php +++ b/app/code/Magento/Shipping/Test/Unit/Model/Carrier/AbstractCarrierOnlineTest.php @@ -52,7 +52,10 @@ class AbstractCarrierOnlineTest extends \PHPUnit_Framework_TestCase $objectManagerHelper = new ObjectManagerHelper($this); $carrierArgs = $objectManagerHelper->getConstructArguments( 'Magento\Shipping\Model\Carrier\AbstractCarrierOnline', - ['stockRegistry' => $this->stockRegistry] + [ + 'stockRegistry' => $this->stockRegistry, + 'xmlSecurity' => new \Magento\Framework\Xml\Security(), + ] ); $this->carrier = $this->getMockBuilder('Magento\Shipping\Model\Carrier\AbstractCarrierOnline') ->setConstructorArgs($carrierArgs) @@ -115,4 +118,36 @@ class AbstractCarrierOnlineTest extends \PHPUnit_Framework_TestCase $customSimpleXmlElement = $this->carrier->parseXml($xmlString, 'Magento\Shipping\Model\Simplexml\Element'); $this->assertInstanceOf('Magento\Shipping\Model\Simplexml\Element', $customSimpleXmlElement); } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Security validation of XML document has been failed. + */ + public function testParseXmlXXEXml() + { + $xmlString = '<!DOCTYPE scan [ + <!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=' + . __DIR__ . '/AbstractCarrierOnline/xxe-xml.txt">]><scan>&test;</scan>'; + + $xmlElement = $this->carrier->parseXml($xmlString); + + echo $xmlElement->asXML(); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Security validation of XML document has been failed. + */ + public function testParseXmlXQBXml() + { + $xmlString = '<?xml version="1.0"?> + <!DOCTYPE test [ + <!ENTITY value "value"> + <!ENTITY value1 "&value;&value;&value;&value;&value;&value;&value;&value;&value;&value;"> + <!ENTITY value2 "&value1;&value1;&value1;&value1;&value1;&value1;&value1;&value1;&value1;&value1;"> + ]> + <test>&value2;</test>'; + + $this->carrier->parseXml($xmlString); + } } diff --git a/app/code/Magento/Store/etc/cache.xml b/app/code/Magento/Store/etc/cache.xml index 45c887b58506313e06cd9a6e24b221b2bdfa9fdb..6dae6b683b09121e6bc3820d0d797fda2d7877bc 100644 --- a/app/code/Magento/Store/etc/cache.xml +++ b/app/code/Magento/Store/etc/cache.xml @@ -18,14 +18,6 @@ <label>Blocks HTML output</label> <description>Page blocks HTML.</description> </type> - <type name="view_files_fallback" translate="label,description" instance="Magento\Framework\View\Design\FileResolution\Fallback\Cache"> - <label>View files fallback</label> - <description>Paths to view files (e.g., PHTML templates, images, CSS, JS files).</description> - </type> - <type name="view_files_preprocessing" translate="label,description" instance="Magento\Framework\View\Asset\PreProcessor\Cache"> - <label>View files pre-processing</label> - <description>Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files).</description> - </type> <type name="collections" translate="label,description" instance="Magento\Framework\App\Cache\Type\Collection"> <label>Collections Data</label> <description>Collection data files.</description> diff --git a/app/code/Magento/Store/etc/config.xml b/app/code/Magento/Store/etc/config.xml index 0bf0f4cdb889d4590773e402854cdeb4c1ee015c..131a73e7abba3a4b2f9423a92f0a56313e93a4e2 100644 --- a/app/code/Magento/Store/etc/config.xml +++ b/app/code/Magento/Store/etc/config.xml @@ -20,11 +20,15 @@ <js> <merge_files>0</merge_files> <minify_files>0</minify_files> - <minify_adapter>Magento\Framework\Code\Minifier\Adapter\Js\Jsmin</minify_adapter> + <minify_exclude> + /tiny_mce/ + </minify_exclude> </js> <css> <minify_files>0</minify_files> - <minify_adapter>Magento\Framework\Code\Minifier\Adapter\Css\CssMinifier</minify_adapter> + <minify_exclude> + /tiny_mce/ + </minify_exclude> </css> <image> <default_adapter>GD2</default_adapter> diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml index ecda7a87e6b85889b034ead1340c2426ddc1931c..1f5efd97f8bf527bd417d68a8b5ce07f00eb9fb4 100644 --- a/app/code/Magento/Store/etc/di.xml +++ b/app/code/Magento/Store/etc/di.xml @@ -288,6 +288,18 @@ <argument name="modulePrefix" xsi:type="string">store</argument> </arguments> </type> + <virtualType name="cssMinificationAdapter" type="Magento\Framework\Code\Minifier\Adapter\Css\CSSmin" /> + <virtualType name="jsMinificationAdapter" type="Magento\Framework\Code\Minifier\Adapter\Js\JShrink" /> + <virtualType name="cssMinificationProcessor" type="Magento\Framework\View\Asset\PreProcessor\Minify"> + <arguments> + <argument name="adapter" xsi:type="object">cssMinificationAdapter</argument> + </arguments> + </virtualType> + <virtualType name="jsMinificationProcessor" type="Magento\Framework\View\Asset\PreProcessor\Minify"> + <arguments> + <argument name="adapter" xsi:type="object">jsMinificationAdapter</argument> + </arguments> + </virtualType> <type name="Magento\Framework\View\Asset\PreProcessor\Pool"> <arguments> <argument name="preProcessors" xsi:type="array"> @@ -296,6 +308,7 @@ <item name="less_css" xsi:type="string">Magento\Framework\Css\PreProcessor\Less</item> <item name="variable_notation" xsi:type="string">Magento\Framework\View\Asset\PreProcessor\VariableNotation</item> <item name="module_notation" xsi:type="string">Magento\Framework\View\Asset\PreProcessor\ModuleNotation</item> + <item name="css_min" xsi:type="string">cssMinificationProcessor</item> </item> <item name="less" xsi:type="array"> <item name="magento_import" xsi:type="string">Magento\Framework\Less\PreProcessor\Instruction\MagentoImport</item> @@ -306,6 +319,12 @@ <item name="css" xsi:type="array"> <item name="variable_notation" xsi:type="string">Magento\Framework\View\Asset\PreProcessor\VariableNotation</item> <item name="module_notation" xsi:type="string">Magento\Framework\View\Asset\PreProcessor\ModuleNotation</item> + <item name="css_min" xsi:type="string">cssMinificationProcessor</item> + </item> + </item> + <item name="js" xsi:type="array"> + <item name="js" xsi:type="array"> + <item name="js_min" xsi:type="string">jsMinificationProcessor</item> </item> </item> </argument> diff --git a/app/code/Magento/Store/i18n/de_DE.csv b/app/code/Magento/Store/i18n/de_DE.csv index f376d05a2c634af120f2e31c26caa9af4e97949d..e498731b13b2ca4ef3655fbedbdd1abce242bdd7 100644 --- a/app/code/Magento/Store/i18n/de_DE.csv +++ b/app/code/Magento/Store/i18n/de_DE.csv @@ -17,9 +17,7 @@ Layouts,Layouts "Layout building instructions.","Layout building instructions." "Blocks HTML output","Blocks HTML output" "Page blocks HTML.","Page blocks HTML." -"View files fallback","View files fallback" "Paths to view files (e.g., PHTML templates, images, CSS, JS files).","Paths to view files (e.g., PHTML templates, images, CSS, JS files)." -"View files pre-processing","View files pre-processing" "Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files).","Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files)." "Collections Data","Collections Data" "Collection data files.","Collection data files." diff --git a/app/code/Magento/Store/i18n/en_US.csv b/app/code/Magento/Store/i18n/en_US.csv index f376d05a2c634af120f2e31c26caa9af4e97949d..e498731b13b2ca4ef3655fbedbdd1abce242bdd7 100644 --- a/app/code/Magento/Store/i18n/en_US.csv +++ b/app/code/Magento/Store/i18n/en_US.csv @@ -17,9 +17,7 @@ Layouts,Layouts "Layout building instructions.","Layout building instructions." "Blocks HTML output","Blocks HTML output" "Page blocks HTML.","Page blocks HTML." -"View files fallback","View files fallback" "Paths to view files (e.g., PHTML templates, images, CSS, JS files).","Paths to view files (e.g., PHTML templates, images, CSS, JS files)." -"View files pre-processing","View files pre-processing" "Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files).","Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files)." "Collections Data","Collections Data" "Collection data files.","Collection data files." diff --git a/app/code/Magento/Store/i18n/es_ES.csv b/app/code/Magento/Store/i18n/es_ES.csv index f376d05a2c634af120f2e31c26caa9af4e97949d..e498731b13b2ca4ef3655fbedbdd1abce242bdd7 100644 --- a/app/code/Magento/Store/i18n/es_ES.csv +++ b/app/code/Magento/Store/i18n/es_ES.csv @@ -17,9 +17,7 @@ Layouts,Layouts "Layout building instructions.","Layout building instructions." "Blocks HTML output","Blocks HTML output" "Page blocks HTML.","Page blocks HTML." -"View files fallback","View files fallback" "Paths to view files (e.g., PHTML templates, images, CSS, JS files).","Paths to view files (e.g., PHTML templates, images, CSS, JS files)." -"View files pre-processing","View files pre-processing" "Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files).","Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files)." "Collections Data","Collections Data" "Collection data files.","Collection data files." diff --git a/app/code/Magento/Store/i18n/fr_FR.csv b/app/code/Magento/Store/i18n/fr_FR.csv index f376d05a2c634af120f2e31c26caa9af4e97949d..e498731b13b2ca4ef3655fbedbdd1abce242bdd7 100644 --- a/app/code/Magento/Store/i18n/fr_FR.csv +++ b/app/code/Magento/Store/i18n/fr_FR.csv @@ -17,9 +17,7 @@ Layouts,Layouts "Layout building instructions.","Layout building instructions." "Blocks HTML output","Blocks HTML output" "Page blocks HTML.","Page blocks HTML." -"View files fallback","View files fallback" "Paths to view files (e.g., PHTML templates, images, CSS, JS files).","Paths to view files (e.g., PHTML templates, images, CSS, JS files)." -"View files pre-processing","View files pre-processing" "Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files).","Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files)." "Collections Data","Collections Data" "Collection data files.","Collection data files." diff --git a/app/code/Magento/Store/i18n/nl_NL.csv b/app/code/Magento/Store/i18n/nl_NL.csv index f376d05a2c634af120f2e31c26caa9af4e97949d..e498731b13b2ca4ef3655fbedbdd1abce242bdd7 100644 --- a/app/code/Magento/Store/i18n/nl_NL.csv +++ b/app/code/Magento/Store/i18n/nl_NL.csv @@ -17,9 +17,7 @@ Layouts,Layouts "Layout building instructions.","Layout building instructions." "Blocks HTML output","Blocks HTML output" "Page blocks HTML.","Page blocks HTML." -"View files fallback","View files fallback" "Paths to view files (e.g., PHTML templates, images, CSS, JS files).","Paths to view files (e.g., PHTML templates, images, CSS, JS files)." -"View files pre-processing","View files pre-processing" "Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files).","Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files)." "Collections Data","Collections Data" "Collection data files.","Collection data files." diff --git a/app/code/Magento/Store/i18n/pt_BR.csv b/app/code/Magento/Store/i18n/pt_BR.csv index f376d05a2c634af120f2e31c26caa9af4e97949d..e498731b13b2ca4ef3655fbedbdd1abce242bdd7 100644 --- a/app/code/Magento/Store/i18n/pt_BR.csv +++ b/app/code/Magento/Store/i18n/pt_BR.csv @@ -17,9 +17,7 @@ Layouts,Layouts "Layout building instructions.","Layout building instructions." "Blocks HTML output","Blocks HTML output" "Page blocks HTML.","Page blocks HTML." -"View files fallback","View files fallback" "Paths to view files (e.g., PHTML templates, images, CSS, JS files).","Paths to view files (e.g., PHTML templates, images, CSS, JS files)." -"View files pre-processing","View files pre-processing" "Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files).","Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files)." "Collections Data","Collections Data" "Collection data files.","Collection data files." diff --git a/app/code/Magento/Store/i18n/zh_CN.csv b/app/code/Magento/Store/i18n/zh_CN.csv index f376d05a2c634af120f2e31c26caa9af4e97949d..e498731b13b2ca4ef3655fbedbdd1abce242bdd7 100644 --- a/app/code/Magento/Store/i18n/zh_CN.csv +++ b/app/code/Magento/Store/i18n/zh_CN.csv @@ -17,9 +17,7 @@ Layouts,Layouts "Layout building instructions.","Layout building instructions." "Blocks HTML output","Blocks HTML output" "Page blocks HTML.","Page blocks HTML." -"View files fallback","View files fallback" "Paths to view files (e.g., PHTML templates, images, CSS, JS files).","Paths to view files (e.g., PHTML templates, images, CSS, JS files)." -"View files pre-processing","View files pre-processing" "Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files).","Paths to pre-processed view files (e.g, CSS files with fixed paths or generated from LESS files)." "Collections Data","Collections Data" "Collection data files.","Collection data files." diff --git a/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml b/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml index 4861e4b3bdc539fe555e6eefa3eaad39a489ecdb..ec05691741ff4da2899ef2a1b5161eaee18c9d5f 100644 --- a/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml +++ b/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml @@ -216,11 +216,16 @@ require([ of: 'body' }, open: function () { - $(this).closest('.ui-dialog').addClass('ui-dialog-active'); + var topMargin; - var topMargin = $(this).closest('.ui-dialog').children('.ui-dialog-titlebar').outerHeight() + 30; + $(this).closest('.ui-dialog').addClass('ui-dialog-active'); + topMargin = $(this).closest('.ui-dialog').children('.ui-dialog-titlebar').outerHeight() + 80; + $(this).closest('.ui-dialog').css({ + top: '1%', + position: 'absolute', + left: '10%' + }); $(this).closest('.ui-dialog').css('margin-top', topMargin); - $(this).addClass('admin__scope-old'); // ToDo UI: remove with old styles removal }, close: function() { diff --git a/app/code/Magento/Ui/view/base/web/js/modal/modal.js b/app/code/Magento/Ui/view/base/web/js/modal/modal.js index aa415e7aeacebaf5d9ffed007bdc3cbe5a59e9fa..84074ebf9800e689fd6a900afe986c8242664ac9 100644 --- a/app/code/Magento/Ui/view/base/web/js/modal/modal.js +++ b/app/code/Magento/Ui/view/base/web/js/modal/modal.js @@ -2,17 +2,39 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ + define([ - "jquery", - "underscore", - "mage/template", - "text!ui/template/modal/modal-popup.html", - "text!ui/template/modal/modal-slide.html", - "text!ui/template/modal/modal-custom.html", - "jquery/ui", - "mage/translate" -], function($, _, template, popupTpl, slideTpl, customTpl){ - "use strict"; + 'jquery', + 'underscore', + 'mage/template', + 'text!ui/template/modal/modal-popup.html', + 'text!ui/template/modal/modal-slide.html', + 'text!ui/template/modal/modal-custom.html', + 'jquery/ui', + 'mage/translate' +], function ($, _, template, popupTpl, slideTpl, customTpl) { + 'use strict'; + + /** + * Detect browser transition end event. + * @return {String|undefined} - transition event. + */ + var transitionEvent = (function () { + var transition, + elementStyle = document.body.style, + transitions = { + 'transition': 'transitionend', + 'OTransition': 'oTransitionEnd', + 'MozTransition': 'transitionend', + 'WebkitTransition': 'webkitTransitionEnd' + }; + + for (transition in transitions) { + if (elementStyle[transition] !== undefined && transitions.hasOwnProperty(transition)) { + return transitions[transition]; + } + } + })(); /** * Modal Window Widget @@ -44,132 +66,167 @@ define([ buttons: [{ text: $.mage.__('Ok'), class: '', - click: function(){ + + /** + * Default action on button click + */ + click: function () { this.closeModal(); } }] }, + /** * Creates modal widget. */ - _create: function() { - this.options.transitionEvent = this.whichTransitionEvent(); + _create: function () { + this.options.transitionEvent = transitionEvent; this._createWrapper(); this._renderModal(); this._createButtons(); - this.modal.find(this.options.modalCloseBtn).on('click', _.bind(this.closeModal, this)); $(this.options.trigger).on('click', _.bind(this.toggleModal, this)); - this.element.on('openModal', _.bind(this.openModal, this)); - this.element.on('closeModal', _.bind(this.closeModal, this)); + this._on(this.modal.find(this.options.modalCloseBtn), { + 'click': this.closeModal + }); + this._on(this.element, { + 'openModal': this.openModal, + 'closeModal': this.closeModal + }); }, + /** * Returns element from modal node. * @return {Object} - element. */ - _getElem: function(elem) { + _getElem: function (elem) { return this.modal.find(elem); }, + /** * Gets visible modal count. * * @return {Number} - visible modal count. */ - _getVisibleCount: function() { - return this.modalWrapper.find('.'+this.options.modalVisibleClass).length; + _getVisibleCount: function () { + var modals = this.modalWrapper.find(this.options.modalBlock); + + return modals.filter('.' + this.options.modalVisibleClass).length; }, + /** * Gets count of visible modal by slide type. * * @return {Number} - visible modal count. */ - _getVisibleSlideCount: function() { + _getVisibleSlideCount: function () { var elems = this.modalWrapper.find('[data-type="slide"]'); - return elems.filter('.'+this.options.modalVisibleClass).length; + return elems.filter('.' + this.options.modalVisibleClass).length; }, - toggleModal: function() { - if (this.options.isOpen == true) { + + /** + * Toggle modal. + * * @return {Element} - current element. + */ + toggleModal: function () { + if (this.options.isOpen === true) { this.closeModal(); } else { this.openModal(); } }, - openModal: function() { - var that = this; + /** + * Open modal. + * * @return {Element} - current element. + */ + openModal: function () { this.options.isOpen = true; this._createOverlay(); this._setActive(); - this.modal.one(this.options.transitionEvent, function() { - that._trigger('opened'); - }); + this.modal.one(this.options.transitionEvent, _.bind(this._trigger, this, 'opened')); this.modal.addClass(this.options.modalVisibleClass); - if ( !this.options.transitionEvent ) { - that._trigger('opened'); + + if (!this.options.transitionEvent) { + this._trigger('opened'); } return this.element; }, - closeModal: function() { + + /** + * Close modal. + * * @return {Element} - current element. + */ + closeModal: function () { var that = this; this.options.isOpen = false; - this.modal.one(this.options.transitionEvent, function() { + this.modal.one(this.options.transitionEvent, function () { that._close(); }); this.modal.removeClass(this.options.modalVisibleClass); - if ( !this.options.transitionEvent ) { + + if (!this.options.transitionEvent) { that._close(); } return this.element; }, + /** * Helper for closeModal function. */ - _close: function() { + _close: function () { var trigger = _.bind(this._trigger, this, 'closed', this.modal); this._destroyOverlay(); this._unsetActive(); _.defer(trigger, this); }, + /** * Set z-index and margin for modal and overlay. */ - _setActive: function() { + _setActive: function () { var zIndex = this.modal.zIndex(); this.prevOverlayIndex = this.overlay.zIndex(); this.modal.zIndex(zIndex + this._getVisibleCount()); this.overlay.zIndex(zIndex + (this._getVisibleCount() - 1)); - if ( this._getVisibleSlideCount() ) { + + if (this._getVisibleSlideCount()) { this.modal.css('marginLeft', this.options.modalLeftMargin * this._getVisibleSlideCount()); } }, + /** * Unset styles for modal and set z-index for previous modal. */ - _unsetActive: function() { + _unsetActive: function () { this.modal.removeAttr('style'); - if ( this.overlay ) { + + if (this.overlay) { this.overlay.zIndex(this.prevOverlayIndex); } }, + /** * Creates wrapper to hold all modals. */ - _createWrapper: function() { - this.modalWrapper = $('.'+this.options.wrapperClass); - if ( !this.modalWrapper.length ) { + _createWrapper: function () { + this.modalWrapper = $('.' + this.options.wrapperClass); + + if (!this.modalWrapper.length) { this.modalWrapper = $('<div></div>') - .addClass(this.options.wrapperClass) - .appendTo(this.options.appendTo); + .addClass(this.options.wrapperClass) + .appendTo(this.options.appendTo); } }, + /** * Compile template and append to wrapper. */ - _renderModal: function() { + _renderModal: function () { $(template( this.options[this.options.type + 'Tpl'], { @@ -178,74 +235,56 @@ define([ this.modal = this.modalWrapper.find(this.options.modalBlock).last(); this.element.show().appendTo(this._getElem(this.options.modalContent)); }, + /** * Creates buttons pane. */ - _createButtons: function() { + _createButtons: function () { var that = this; this.buttons = this._getElem(this.options.modalAction); - _.each(this.options.buttons, function(btn, key) { + _.each(this.options.buttons, function (btn, key) { var button = that.buttons[key]; $(button).on('click', _.bind(btn.click, that)); }); }, + /** * Creates overlay, append it to wrapper, set previous click event on overlay. */ - _createOverlay: function() { + _createOverlay: function () { var that = this, events; this.overlay = $('.' + this.options.overlayClass); - if ( !this.overlay.length ) { + + if (!this.overlay.length) { $(this.options.appendTo).addClass(this.options.parentModalClass); this.overlay = $('<div></div>') .addClass(this.options.overlayClass) .appendTo(this.modalWrapper); } - events = $._data(this.overlay.get(0), 'events'); - if ( events ) { + + if (events) { this.prevOverlayHandler = events.click[0].handler; } - this.overlay.unbind().on('click', function() { + this.overlay.unbind().on('click', function () { that.closeModal(); }); }, + /** * Destroy overlay. */ - _destroyOverlay: function() { - var modalCount = this.modalWrapper.find('.'+this.options.modalVisibleClass).length; - - if ( !modalCount ) { + _destroyOverlay: function () { + if (this._getVisibleCount()) { + this.overlay.unbind().on('click', this.prevOverlayHandler); + } else { $(this.options.appendTo).removeClass(this.options.parentModalClass); this.overlay.remove(); this.overlay = null; - - } else { - this.overlay.unbind().on('click', this.prevOverlayHandler); - } - }, - /** - * Detects browser transition event. - */ - whichTransitionEvent: function() { - var transition, - el = document.createElement('element'), - transitions = { - 'transition': 'transitionend', - 'OTransition': 'oTransitionEnd', - 'MozTransition': 'transitionend', - 'WebkitTransition': 'webkitTransitionEnd' - }; - - for (transition in transitions){ - if ( el.style[transition] !== undefined && transitions.hasOwnProperty(transition) ) { - return transitions[transition]; - } } } }); diff --git a/app/code/Magento/Ui/view/base/web/templates/form/components/collection.html b/app/code/Magento/Ui/view/base/web/templates/form/components/collection.html index 60e44c80be894716ba8122e6f3d413052ecb119b..0ff75fa00ea3dc784b453fbefbe10a55be96643f 100644 --- a/app/code/Magento/Ui/view/base/web/templates/form/components/collection.html +++ b/app/code/Magento/Ui/view/base/web/templates/form/components/collection.html @@ -15,7 +15,7 @@ </button> </div> <!-- ko template: previewTpl --><!-- /ko --> - <div data-bind="foreach: { data: element.getRegion('head'), as: 'element' }, stopPropagation: true"> + <div data-bind="foreach: { data: element.getRegion('head'), as: 'element' }"> <!-- ko template: element.getTemplate() --><!-- /ko --> </div> </li> diff --git a/app/code/Magento/Ups/Model/Carrier.php b/app/code/Magento/Ups/Model/Carrier.php index fca7588c0ae155c8385f87d3ab9654d9e1d45e97..fdb91b82f9dd63fc0ad260d93e3c0520eaff2bdc 100644 --- a/app/code/Magento/Ups/Model/Carrier.php +++ b/app/code/Magento/Ups/Model/Carrier.php @@ -14,6 +14,7 @@ use Magento\Shipping\Model\Carrier\CarrierInterface; use Magento\Shipping\Model\Rate\Result; use Magento\Shipping\Model\Simplexml\Element; use Magento\Ups\Helper\Config; +use Magento\Framework\Xml\Security; /** * UPS shipping implementation @@ -124,6 +125,7 @@ class Carrier extends AbstractCarrierOnline implements CarrierInterface * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory * @param \Psr\Log\LoggerInterface $logger + * @param Security $xmlSecurity * @param \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory * @param \Magento\Shipping\Model\Rate\ResultFactory $rateFactory * @param \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory @@ -145,6 +147,7 @@ class Carrier extends AbstractCarrierOnline implements CarrierInterface \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory, \Psr\Log\LoggerInterface $logger, + Security $xmlSecurity, \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory, \Magento\Shipping\Model\Rate\ResultFactory $rateFactory, \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory, @@ -166,6 +169,7 @@ class Carrier extends AbstractCarrierOnline implements CarrierInterface $scopeConfig, $rateErrorFactory, $logger, + $xmlSecurity, $xmlElFactory, $rateFactory, $rateMethodFactory, diff --git a/app/code/Magento/Usps/Model/Carrier.php b/app/code/Magento/Usps/Model/Carrier.php index 2aa0517e787d4542532f33244d1454aefc40af08..eb2b5f3234288a29d0c70136387cec140a130e1b 100644 --- a/app/code/Magento/Usps/Model/Carrier.php +++ b/app/code/Magento/Usps/Model/Carrier.php @@ -11,6 +11,7 @@ namespace Magento\Usps\Model; use Magento\Shipping\Helper\Carrier as CarrierHelper; use Magento\Shipping\Model\Carrier\AbstractCarrierOnline; use Magento\Shipping\Model\Rate\Result; +use Magento\Framework\Xml\Security; /** * USPS shipping @@ -114,6 +115,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory * @param \Psr\Log\LoggerInterface $logger + * @param Security $xmlSecurity * @param \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory * @param \Magento\Shipping\Model\Rate\ResultFactory $rateFactory * @param \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory @@ -136,6 +138,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory, \Psr\Log\LoggerInterface $logger, + Security $xmlSecurity, \Magento\Shipping\Model\Simplexml\ElementFactory $xmlElFactory, \Magento\Shipping\Model\Rate\ResultFactory $rateFactory, \Magento\Quote\Model\Quote\Address\RateResult\MethodFactory $rateMethodFactory, @@ -159,6 +162,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C $scopeConfig, $rateErrorFactory, $logger, + $xmlSecurity, $xmlElFactory, $rateFactory, $rateMethodFactory, diff --git a/app/code/Magento/Usps/Test/Unit/Model/CarrierTest.php b/app/code/Magento/Usps/Test/Unit/Model/CarrierTest.php index 50bc4a1ae4d079231371ffb8734c483b80c8192f..ce80e36ea98f0a5ecadc074e47de940f7b633f3d 100644 --- a/app/code/Magento/Usps/Test/Unit/Model/CarrierTest.php +++ b/app/code/Magento/Usps/Test/Unit/Model/CarrierTest.php @@ -114,6 +114,7 @@ class CarrierTest extends \PHPUnit_Framework_TestCase $arguments = [ 'scopeConfig' => $scopeConfig, + 'xmlSecurity' => new \Magento\Framework\Xml\Security(), 'xmlElFactory' => $xmlElFactory, 'rateFactory' => $rateFactory, 'rateMethodFactory' => $rateMethodFactory, diff --git a/app/etc/di.xml b/app/etc/di.xml index 18e52f6b117b25b56e27c1af4dce82c164b14652..67456f362528af1e637ff4b05581c5f7c4bc2196 100644 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -89,7 +89,6 @@ <preference for="Magento\Framework\Mview\View\CollectionInterface" type="Magento\Framework\Mview\View\Collection" /> <preference for="Magento\Framework\Mview\View\SubscriptionInterface" type="Magento\Framework\Mview\View\Subscription" /> <preference for="Magento\Framework\Mview\View\ChangelogInterface" type="Magento\Framework\Mview\View\Changelog" /> - <preference for="Magento\Framework\View\Design\FileResolution\Fallback\CacheDataInterface" type="Magento\Framework\View\Design\FileResolution\Fallback\CacheData\Flat"/> <preference for="Magento\Framework\Api\MetadataServiceInterface" type="Magento\Framework\Api\DefaultMetadataService"/> <preference for="Magento\Framework\Api\MetadataObjectInterface" type="Magento\Framework\Api\AttributeMetadata"/> <preference for="Magento\Framework\Api\SearchCriteriaInterface" type="Magento\Framework\Api\SearchCriteria"/> @@ -213,11 +212,6 @@ <argument name="appMode" xsi:type="init_parameter">Magento\Framework\App\State::PARAM_MODE</argument> </arguments> </type> - <type name="Magento\Framework\View\Asset\MinifyService"> - <arguments> - <argument name="appMode" xsi:type="init_parameter">Magento\Framework\App\State::PARAM_MODE</argument> - </arguments> - </type> <type name="Magento\Framework\App\Cache\Frontend\Factory"> <arguments> <argument name="enforcedOptions" xsi:type="init_parameter">Magento\Framework\App\Cache\Frontend\Factory::PARAM_CACHE_FORCED_OPTIONS</argument> @@ -601,29 +595,23 @@ <argument name="publisher" xsi:type="object">developerPublisher</argument> </arguments> </virtualType> - <virtualType name="fallbackResolverSimpleWithGroupedCache" type="Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Simple"> - <arguments> - <argument name="cache" xsi:type="object">Magento\Framework\View\Design\FileResolution\Fallback\CacheData\Grouped</argument> - </arguments> - </virtualType> <type name="Magento\Framework\View\Design\FileResolution\Fallback\File"> <arguments> - <argument name="resolver" xsi:type="object">fallbackResolverSimpleWithGroupedCache</argument> + <argument name="resolver" xsi:type="object">Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Simple</argument> </arguments> </type> <type name="Magento\Framework\View\Design\FileResolution\Fallback\TemplateFile"> <arguments> - <argument name="resolver" xsi:type="object">fallbackResolverSimpleWithGroupedCache</argument> + <argument name="resolver" xsi:type="object">Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Simple</argument> </arguments> </type> <type name="Magento\Framework\View\Design\FileResolution\Fallback\LocaleFile"> <arguments> - <argument name="resolver" xsi:type="object">fallbackResolverSimpleWithGroupedCache</argument> + <argument name="resolver" xsi:type="object">Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Simple</argument> </arguments> </type> <virtualType name="viewFileFallbackResolver" type="Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Alternative"> <arguments> - <argument name="cache" xsi:type="object">Magento\Framework\View\Design\FileResolution\Fallback\CacheData\Flat</argument> <argument name="alternativeExtensions" xsi:type="array"> <item name="css" xsi:type="array"> <item name="less" xsi:type="string">less</item> @@ -631,9 +619,14 @@ </argument> </arguments> </virtualType> + <virtualType name="viewFileMinifiedFallbackResolver" type="Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Minification"> + <arguments> + <argument name="fallback" xsi:type="object">viewFileFallbackResolver</argument> + </arguments> + </virtualType> <type name="Magento\Framework\View\Design\FileResolution\Fallback\StaticFile"> <arguments> - <argument name="resolver" xsi:type="object">viewFileFallbackResolver</argument> + <argument name="resolver" xsi:type="object">viewFileMinifiedFallbackResolver</argument> </arguments> </type> <type name="Magento\Framework\Code\Generator"> diff --git a/composer.json b/composer.json index 2f128cb5c41f6b095f54c5dc5916f2070311213d..d1688a0bf2a16475f188ea3b7013f29740b537a2 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,8 @@ "tubalmartin/cssmin": "2.4.8-p4", "magento/magento-composer-installer": "*", "braintree/braintree_php": "2.39.0", - "symfony/console": "~2.3 <2.7" + "symfony/console": "~2.3 <2.7", + "tedivm/jshrink": "~1.0.1" }, "require-dev": { "phpunit/phpunit": "4.1.0", @@ -167,7 +168,6 @@ "trentrichardson/jquery-timepicker-addon": "1.4.3", "colinmollenhour/cache-backend-redis": "1.8", "colinmollenhour/credis": "1.5", - "linkorb/jsmin-php": "1.1.2", "phpseclib/phpseclib": "0.2.1", "components/jquery": "1.11.0", "blueimp/jquery-file-upload": "5.6.14", @@ -180,7 +180,6 @@ "trentrichardson/jquery-timepicker-addon": "lib/web/jquery/jquery-ui-timepicker-addon.js", "colinmollenhour/cache-backend-redis": "lib/internal/Cm/Cache/Backend/Redis.php", "colinmollenhour/credis": "lib/internal/Credis", - "linkorb/jsmin-php": "lib/internal/JSMin", "phpseclib/phpseclib": "lib/internal/phpseclib", "components/jquery": [ "lib/web/jquery.js", diff --git a/composer.lock b/composer.lock index da31b73ce352ce24368741ddf4321fd03d3712ec..97afe2b5a0ccdf4c08176539c5bee844fa48430c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "08facbf9eb603e2ca8d6c0eb2f63fa5e", + "hash": "2213824594a29c1311ab731de9678212", "packages": [ { "name": "braintree/braintree_php", @@ -735,6 +735,52 @@ "homepage": "https://symfony.com", "time": "2015-07-01 11:25:50" }, + { + "name": "tedivm/jshrink", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/tedious/JShrink.git", + "reference": "7575d9d96f113bc7c1c28ec8231ee086751a9078" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tedious/JShrink/zipball/7575d9d96f113bc7c1c28ec8231ee086751a9078", + "reference": "7575d9d96f113bc7c1c28ec8231ee086751a9078", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "fabpot/php-cs-fixer": "0.4.0", + "phpunit/phpunit": "4.0.*", + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "autoload": { + "psr-0": { + "JShrink": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Robert Hafner", + "email": "tedivm@tedivm.com" + } + ], + "description": "Javascript Minifier built in PHP", + "homepage": "http://github.com/tedious/JShrink", + "keywords": [ + "javascript", + "minifier" + ], + "time": "2014-11-11 03:54:14" + }, { "name": "tubalmartin/cssmin", "version": "v2.4.8-p4", 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 new file mode 100644 index 0000000000000000000000000000000000000000..88955c3a9841a5bd3fece225dc021764a407ea7e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Cache/Additional.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\Block\Cache; + +use Magento\Mtf\Block\Block; +use Magento\Mtf\Client\Locator; + +/** + * Additional Cache Management block. + */ +class Additional extends Block +{ + public function click($selector, $strategy = Locator::SELECTOR_XPATH) + { + $this->_rootElement->find($selector, $strategy)->click(); + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..edebf73913e7ce24032513668bdc3a847fd8fec7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertCacheManagementAction.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\Constraint; + +use Magento\Backend\Test\Fixture\GlobalSearch; +use Magento\Backend\Test\Page\Adminhtml\AdminCache; +use Magento\Mtf\Constraint\AbstractConstraint; + +/** + * Assert Cache Management Action + */ +class AssertCacheManagementAction extends AbstractConstraint +{ + /** + * Assert that backend page has correct title and 404 Error is absent on the page. + * + * @param AdminCache $adminCache + * @param string $successMessage + * @return void + */ + public function processAssert(AdminCache $adminCache, $successMessage) + { + \PHPUnit_Framework_Assert::assertEquals( + $successMessage, + $adminCache->getMessagesBlock()->getSuccessMessages(), + 'Action is not successful' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Cache management action is successful'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/AdminCache.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/AdminCache.xml index 5db150ec298d51e049428d2fa215ce071eac1287..1c5883a5119abc4e78591992a1e4276e9da9daab 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/AdminCache.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/AdminCache.xml @@ -5,9 +5,14 @@ * 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="AdminCache" area="Adminhtml" mca="admin/cache/" module="Magento_Backend"> - <block name="messagesBlock" class="Magento\Backend\Test\Block\Messages" locator="#messages .messages" strategy="css selector"/> - <block name="actionsBlock" class="Magento\Backend\Test\Block\Cache" locator="div.page-actions" strategy="css selector"/> - </page> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/pages.xsd"> + <page name="AdminCache" area="Adminhtml" mca="admin/cache/" module="Magento_Backend"> + <block name="messagesBlock" class="Magento\Backend\Test\Block\Messages" locator="#messages .messages" + strategy="css selector"/> + <block name="actionsBlock" class="Magento\Backend\Test\Block\Cache" locator="div.page-actions" + strategy="css selector"/> + <block name="additionalBlock" class="Magento\Backend\Test\Block\Cache\Additional" locator="div.fieldset.additional-cache-management" + strategy="css selector"/> + </page> </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 new file mode 100644 index 0000000000000000000000000000000000000000..e106bd9e3299a97099fbb072b10384565e3f6c0c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.php @@ -0,0 +1,41 @@ +<?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 throught menu to cache management page. + * 3. Click a button. + * 4. Perform asserts. + * + * @ZephyrId MAGETWO-34502 MAGETWO-34503 MAGETWO-39934 + */ +class CacheManagementTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + const DOMAIN = 'PS'; + /* end tags */ + + /** + * Open admin cache management page + * + * @param AdminCache $adminCache + * @param string $button + * @return void + */ + public function test(AdminCache $adminCache, $button) + { + $selector = "//div/button[normalize-space(.)= '" . $button . "']"; + $adminCache->open(); + $adminCache->getAdditionalBlock()->click($selector); + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..f018b02d4daa40b4a10d08a924c1cb4e06aaf351 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/CacheManagementTest.xml @@ -0,0 +1,26 @@ +<?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\CacheManagementTest"> + <variation name="FlushCatalogImagesCacheTest"> + <data name="button" xsi:type="string">Flush Catalog Images Cache</data> + <data name="successMessage" xsi:type="string">The image cache was cleaned.</data> + <constraint name="Magento\Backend\Test\Constraint\AssertCacheManagementAction"/> + </variation> + <variation name="FlushJavaScriptCSSCacheTest"> + <data name="button" xsi:type="string">Flush JavaScript/CSS Cache</data> + <data name="successMessage" xsi:type="string">The JavaScript/CSS cache has been cleaned.</data> + <constraint name="Magento\Backend\Test\Constraint\AssertCacheManagementAction"/> + </variation> + <variation name="FlushStaticFilesCacheTest"> + <data name="button" xsi:type="string">Flush Static Files Cache</data> + <data name="successMessage" xsi:type="string">The static files cache has been cleaned.</data> + <constraint name="Magento\Backend\Test\Constraint\AssertCacheManagementAction"/> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.php b/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.php index 64a90917c4c0245490565f507e3def561752cd70..9d1f12a1c4c86a4162c87458d20e5c3ebb35c413 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.php @@ -9,6 +9,7 @@ namespace Magento\Install\Test\Block; use Magento\Mtf\Block\Form; use Magento\Mtf\Fixture\FixtureInterface; use Magento\Mtf\Client\Element\SimpleElement; +use Magento\Mtf\Client\Locator; /** * Web configuration block. @@ -29,6 +30,13 @@ class WebConfiguration extends Form */ protected $advancedOptions = "[ng-click*='advanced']"; + /** + * Admin URI check. + * + * @var string + */ + protected $adminUriCheck = '#admin'; + /** * Fill web configuration form. * @@ -70,4 +78,9 @@ class WebConfiguration extends Form { $this->_rootElement->find($this->advancedOptions)->click(); } + + public function getAdminUriCheck() + { + return $this->_rootElement->find($this->adminUriCheck)->getAttribute('ng-init'); + } } diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php new file mode 100644 index 0000000000000000000000000000000000000000..a211ced5e97ad2adab155a5b2261cca109a34a80 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Install\Test\Constraint; + +use Magento\Install\Test\Page\Install; +use Magento\Mtf\Constraint\AbstractConstraint; + +/** + * Check that default Admin URI is generated according to the pattern + */ +class AssertAdminUriAutogenerated extends AbstractConstraint +{ + /** + * Admin URI pattern. + */ + const ADMIN_URI_PATTERN = '/config\.address\.admin = \'admin_[a-z0-9]{1,6}/'; + + /** + * Assert that default Admin URI is generated according to the pattern. + * + * @param Install $installPage + * @return void + */ + public function processAssert(Install $installPage) + { + \PHPUnit_Framework_Assert::assertRegExp( + self::ADMIN_URI_PATTERN, + $installPage->getWebConfigBlock()->getAdminUriCheck(), + 'Unexpected Backend Frontname pattern.' + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Default Admin URI is OK."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.php b/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.php index ccf21709a84ab2f1d5f59eaf62cb5444a49df765..49626cf4db5d0477277a14a268794aa127a011fd 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.php @@ -14,6 +14,7 @@ use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\TestCase\Injectable; use Magento\Install\Test\Constraint\AssertAgreementTextPresent; use Magento\Install\Test\Constraint\AssertSuccessfulReadinessCheck; +use Magento\Install\Test\Constraint\AssertAdminUriAutogenerated; /** * PLEASE ADD NECESSARY INFO BEFORE RUNNING TEST TO @@ -108,6 +109,7 @@ class InstallTest extends Injectable FixtureFactory $fixtureFactory, AssertAgreementTextPresent $assertLicense, AssertSuccessfulReadinessCheck $assertReadiness, + AssertAdminUriAutogenerated $assertAdminUri, array $install = [] ) { $dataConfig = array_merge($install, $configData); @@ -131,6 +133,7 @@ class InstallTest extends Injectable $this->installPage->getDatabaseBlock()->fill($installConfig); $this->installPage->getDatabaseBlock()->clickNext(); // Step 3: Web Configuration. + $assertAdminUri->processAssert($this->installPage); $this->installPage->getWebConfigBlock()->clickAdvancedOptions(); $this->installPage->getWebConfigBlock()->fill($installConfig); $this->installPage->getWebConfigBlock()->clickNext(); diff --git a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFilesTest.php b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFilesTest.php new file mode 100644 index 0000000000000000000000000000000000000000..8bd09d48a7c82d028a235a36300249ec4e58917a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFilesTest.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Controller\Adminhtml\Cache; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\App\Filesystem\DirectoryList; + +class CleanStaticFilesTest extends \Magento\TestFramework\TestCase\AbstractBackendController +{ + public function setUp() + { + $this->resource = 'Magento_Backend::cache'; + $this->uri = 'backend/admin/cache/cleanStaticFiles'; + parent::setUp(); + } + + public function testAclHasAccess() + { + // setup + /** @var \Magento\Framework\Filesystem $filesystem */ + $filesystem = Bootstrap::getObjectManager()->get('Magento\Framework\Filesystem'); + $dirStatic = $filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); + $subStaticDir = 'subdir'; + $dirStatic->create($subStaticDir); + $this->assertTrue($dirStatic->isExist($subStaticDir)); + + $dirVar= $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR); + $subVarDir = DirectoryList::TMP_MATERIALIZATION_DIR . '/subdir'; + $dirVar->create($subVarDir); + $this->assertTrue($dirVar->isExist($subVarDir)); + + // test + parent::testAclHasAccess(); + $this->assertSessionMessages( + $this->contains("The static files cache has been cleaned."), + \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS, + 'Magento\Framework\Message\ManagerInterface' + ); + $this->assertFalse($dirStatic->isExist($subStaticDir)); + $this->assertTrue($dirVar->isExist(DirectoryList::TMP_MATERIALIZATION_DIR)); + $this->assertFalse($dirVar->isExist($subVarDir)); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Asset/MinifierTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/Asset/MinifierTest.php index 9e64e9345c6fa2d84885c4ec01e469ed1df7277c..6fda3a8d0c2d9b9ee6f752a4fc0eb410e0c6aa65 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Asset/MinifierTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Asset/MinifierTest.php @@ -6,6 +6,7 @@ namespace Magento\Framework\View\Asset; use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\App\State as AppState; /** * Tests for minifier @@ -13,15 +14,31 @@ use Magento\TestFramework\Helper\Bootstrap; class MinifierTest extends \PHPUnit_Framework_TestCase { /** - * @var \Magento\Framework\ObjectManagerInterface + * @var \Magento\TestFramework\ObjectManager */ protected $objectManager; + /** + * {@inheritDoc} + */ protected function setUp() { + parent::setUp(); $this->objectManager = Bootstrap::getInstance()->getObjectManager(); - $this->objectManager->get('Magento\Framework\App\State')->setAreaCode('frontend'); - Bootstrap::getInstance()->reinitialize(); + /** @var \Magento\TestFramework\App\State $appState */ + $appState = $this->objectManager->get('Magento\TestFramework\App\State'); + $appState->setMode(AppState::MODE_DEFAULT); + } + + /** + * {@inheritDoc} + */ + protected function tearDown() + { + /** @var \Magento\TestFramework\App\State $appState */ + $appState = $this->objectManager->get('Magento\TestFramework\App\State'); + $appState->setMode(AppState::MODE_DEVELOPER); + parent::tearDown(); } /** @@ -34,14 +51,10 @@ class MinifierTest extends \PHPUnit_Framework_TestCase * 4 - ensure that new minified CSS is fully workable in all supported browsers * 5 - replace `_files/static/css/styles.magento.min.css` with new minified css */ - public function testCssMinifierLibrary() + public function testCSSminLibrary() { - /** @var \Magento\Framework\View\Asset\Config $config */ - $config = $this->objectManager->get('Magento\Framework\View\Asset\Config'); - $adapterClass = $config->getAssetMinificationAdapter('css'); - /** @var \Magento\Framework\Code\Minifier\AdapterInterface $adapter */ - $adapter = $this->objectManager->get($adapterClass); + $adapter = $this->objectManager->get('cssMinificationAdapter'); $this->assertEquals( file_get_contents(dirname(__DIR__) . '/_files/static/css/styles.magento.min.css'), $adapter->minify(file_get_contents(dirname(__DIR__) . '/_files/static/css/styles.css')), @@ -51,6 +64,24 @@ class MinifierTest extends \PHPUnit_Framework_TestCase ); } + /** + * Test JS minification library + * + * @return void + */ + public function testJshrinkLibrary() + { + /** @var \Magento\Framework\Code\Minifier\AdapterInterface $adapter */ + $adapter = $this->objectManager->get('jsMinificationAdapter'); + $this->assertEquals( + file_get_contents(dirname(__DIR__) . '/_files/static/js/test.min.js'), + $adapter->minify(file_get_contents(dirname(__DIR__) . '/_files/static/js/test.js')), + 'Minified JS differs from initial minified JS snapshot. ' + . 'Ensure that new JS is fully valid for all supported browsers ' + . 'and replace old minified snapshot with new one.' + ); + } + /** * Test CSS minification * @@ -62,50 +93,23 @@ class MinifierTest extends \PHPUnit_Framework_TestCase */ protected function _testCssMinification($requestedUri, $requestedFilePath, $testFile, $assertionCallback) { - /** @var \Magento\Framework\App\State|\PHPUnit_Framework_MockObject_MockObject $appState */ - $appState = $this->getMock('\Magento\Framework\App\State', ['getMode'], [], '', false); - $appState->expects($this->any()) - ->method('getMode') - ->will($this->returnValue(\Magento\Framework\App\State::MODE_DEFAULT)); - /** @var \Magento\Framework\App\Request\Http $request */ $request = $this->objectManager->get('Magento\Framework\App\Request\Http'); $request->setRequestUri($requestedUri); $request->setParam('resource', $requestedUri); - $response = $this->getMockForAbstractClass( - 'Magento\Framework\App\Response\FileInterface', - [], - '', - false, - false, - true, - ['setFilePath'] - ); - $response->expects( - $this->any() - )->method( - 'setFilePath' - )->will( - $this->returnCallback( - $assertionCallback - ) - ); - - $publisher = $this->objectManager->create( - 'Magento\Framework\App\View\Asset\Publisher', - [ - 'appState' => $appState - ] - ); + $response = $this->getMockBuilder('Magento\Framework\App\Response\FileInterface') + ->setMethods(['setFilePath']) + ->getMockForAbstractClass(); + $response + ->expects($this->any()) + ->method('setFilePath') + ->will($this->returnCallback($assertionCallback)); /** @var \Magento\Framework\App\StaticResource $staticResourceApp */ $staticResourceApp = $this->objectManager->create( 'Magento\Framework\App\StaticResource', - [ - 'response' => $response, - 'publisher' => $publisher - ] + ['response' => $response] ); $initParams = Bootstrap::getInstance()->getAppInitParams(); $designPath = $initParams[\Magento\Framework\App\Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]['design']['path']; @@ -128,7 +132,7 @@ class MinifierTest extends \PHPUnit_Framework_TestCase public function testCssMinification() { $this->_testCssMinification( - '/frontend/Magento/blank/en_US/css/styles.css', + '/frontend/Magento/blank/en_US/css/styles.min.css', '/frontend/Magento/blank/web/css/styles.css', dirname(__DIR__) . '/_files/static/css/styles.css', function ($path) { @@ -193,7 +197,7 @@ class MinifierTest extends \PHPUnit_Framework_TestCase $staticPath = $initDirectories['static']['path']; - $fileToBePublished = $staticPath . '/frontend/Magento/blank/en_US/css/styles.css'; + $fileToBePublished = $staticPath . '/frontend/Magento/blank/en_US/css/styles.min.css'; $destFile = $designPath . '/frontend/Magento/blank/web/css/styles.css'; $fileToTestPublishing = dirname(__DIR__) . '/_files/static/css/styles.css'; @@ -229,7 +233,7 @@ class MinifierTest extends \PHPUnit_Framework_TestCase ] )); - /** @var \Magento\Setup\ModelDeployer $deployer */ + /** @var \Magento\Setup\Model\Deployer $deployer */ $deployer = $this->objectManager->create( 'Magento\Setup\Model\Deployer', ['filesUtil' => $filesUtil, 'output' => $output, 'isDryRun' => false] diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/js/test.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/js/test.js new file mode 100644 index 0000000000000000000000000000000000000000..925ae9df33791441a2e54ed6457753a62cba0751 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/js/test.js @@ -0,0 +1,534 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + "jquery", + "matchMedia", + "jquery/ui", + "jquery/jquery.mobile.custom", + "mage/translate" +], function ($, mediaCheck) { + 'use strict'; + + /** + * Menu Widget - this widget is a wrapper for the jQuery UI Menu + */ + $.widget('mage.menu', $.ui.menu, { + options: { + responsive: false, + expanded: false, + delay: 300 + }, + _create: function () { + var self = this; + + this._super(); + $(window).on('resize', function () { + self.element.find('.submenu-reverse').removeClass('submenu-reverse'); + }); + }, + + _init: function () { + this._super(); + this.delay = this.options.delay; + + if (this.options.expanded === true) { + this.isExpanded(); + } + + if (this.options.responsive === true) { + mediaCheck({ + media: '(max-width: 640px)', + entry: $.proxy(function () { + this._toggleMobileMode(); + }, this), + exit: $.proxy(function () { + this._toggleDesktopMode(); + }, this) + }); + } + + this._assignControls()._listen(); + }, + + _assignControls: function () { + this.controls = { + toggleBtn: $('[data-action="toggle-nav"]'), + swipeArea: $('.nav-sections') + }; + + return this; + }, + + _listen: function () { + var controls = this.controls; + var toggle = this.toggle; + + this._on(controls.toggleBtn, {'click': toggle}); + this._on(controls.swipeArea, {'swipeleft': toggle}); + }, + + toggle: function () { + if ($('html').hasClass('nav-open')) { + $('html').removeClass('nav-open'); + setTimeout(function () { + $('html').removeClass('nav-before-open'); + }, 300); + } else { + $('html').addClass('nav-before-open'); + setTimeout(function () { + $('html').addClass('nav-open'); + }, 42); + } + }, + + //Add class for expanded option + isExpanded: function () { + var subMenus = this.element.find(this.options.menus), + expandedMenus = subMenus.find('ul'); + + expandedMenus.addClass('expanded'); + }, + + _activate: function (event) { + window.location.href = this.active.find('> a').attr('href'); + this.collapseAll(event); + }, + + _keydown: function (event) { + + var match, prev, character, skip, regex, + preventDefault = true; + + function escape(value) { + return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); + } + + if (this.active.closest('ul').attr('aria-expanded') != 'true') { + + switch (event.keyCode) { + case $.ui.keyCode.PAGE_UP: + this.previousPage(event); + break; + case $.ui.keyCode.PAGE_DOWN: + this.nextPage(event); + break; + case $.ui.keyCode.HOME: + this._move("first", "first", event); + break; + case $.ui.keyCode.END: + this._move("last", "last", event); + break; + case $.ui.keyCode.UP: + this.previous(event); + break; + case $.ui.keyCode.DOWN: + if (this.active && !this.active.is(".ui-state-disabled")) { + this.expand(event); + } + break; + case $.ui.keyCode.LEFT: + this.previous(event); + break; + case $.ui.keyCode.RIGHT: + this.next(event); + break; + case $.ui.keyCode.ENTER: + case $.ui.keyCode.SPACE: + this._activate(event); + break; + case $.ui.keyCode.ESCAPE: + this.collapse(event); + break; + default: + preventDefault = false; + prev = this.previousFilter || ""; + character = String.fromCharCode(event.keyCode); + skip = false; + + clearTimeout(this.filterTimer); + + if (character === prev) { + skip = true; + } else { + character = prev + character; + } + + regex = new RegExp("^" + escape(character), "i"); + match = this.activeMenu.children(".ui-menu-item").filter(function () { + return regex.test($(this).children("a").text()); + }); + match = skip && match.index(this.active.next()) !== -1 ? + this.active.nextAll(".ui-menu-item") : + match; + + // If no matches on the current filter, reset to the last character pressed + // to move down the menu to the first item that starts with that character + if (!match.length) { + character = String.fromCharCode(event.keyCode); + regex = new RegExp("^" + escape(character), "i"); + match = this.activeMenu.children(".ui-menu-item").filter(function () { + return regex.test($(this).children("a").text()); + }); + } + + if (match.length) { + this.focus(event, match); + if (match.length > 1) { + this.previousFilter = character; + this.filterTimer = this._delay(function () { + delete this.previousFilter; + }, 1000); + } else { + delete this.previousFilter; + } + } else { + delete this.previousFilter; + } + } + } else { + switch (event.keyCode) { + case $.ui.keyCode.DOWN: + this.next(event); + break; + case $.ui.keyCode.UP: + this.previous(event); + break; + case $.ui.keyCode.RIGHT: + if (this.active && !this.active.is(".ui-state-disabled")) { + this.expand(event); + } + break; + case $.ui.keyCode.ENTER: + case $.ui.keyCode.SPACE: + this._activate(event); + break; + case $.ui.keyCode.LEFT: + case $.ui.keyCode.ESCAPE: + this.collapse(event); + break; + default: + preventDefault = false; + prev = this.previousFilter || ""; + character = String.fromCharCode(event.keyCode); + skip = false; + + clearTimeout(this.filterTimer); + + if (character === prev) { + skip = true; + } else { + character = prev + character; + } + + regex = new RegExp("^" + escape(character), "i"); + match = this.activeMenu.children(".ui-menu-item").filter(function () { + return regex.test($(this).children("a").text()); + }); + match = skip && match.index(this.active.next()) !== -1 ? + this.active.nextAll(".ui-menu-item") : + match; + + // If no matches on the current filter, reset to the last character pressed + // to move down the menu to the first item that starts with that character + if (!match.length) { + character = String.fromCharCode(event.keyCode); + regex = new RegExp("^" + escape(character), "i"); + match = this.activeMenu.children(".ui-menu-item").filter(function () { + return regex.test($(this).children("a").text()); + }); + } + + if (match.length) { + this.focus(event, match); + if (match.length > 1) { + this.previousFilter = character; + this.filterTimer = this._delay(function () { + delete this.previousFilter; + }, 1000); + } else { + delete this.previousFilter; + } + } else { + delete this.previousFilter; + } + } + } + + if (preventDefault) { + event.preventDefault(); + } + }, + + _toggleMobileMode: function () { + $(this.element).off('mouseenter mouseleave'); + this._on({ + "click .ui-menu-item:has(a)": function (event) { + event.preventDefault(); + + var target = $(event.target).closest(".ui-menu-item"); + + if (!target.hasClass('level-top') || !target.has(".ui-menu").length) { + window.location.href = target.find('> a').attr('href'); + } + } + }); + + var subMenus = this.element.find('.level-top'); + $.each(subMenus, $.proxy(function (index, item) { + var category = $(item).find('> a span').not('.ui-menu-icon').text(), + categoryUrl = $(item).find('> a').attr('href'), + menu = $(item).find('> .ui-menu'); + + this.categoryLink = $('<a>') + .attr('href', categoryUrl) + .text($.mage.__('All ') + category); + + this.categoryParent = $('<li>') + .addClass('ui-menu-item all-category') + .html(this.categoryLink); + + if (menu.find('.all-category').length === 0) { + menu.prepend(this.categoryParent); + } + + }, this)); + }, + + _toggleDesktopMode: function () { + this._on({ + // Prevent focus from sticking to links inside menu after clicking + // them (focus should always stay on UL during navigation). + "mousedown .ui-menu-item > a": function (event) { + event.preventDefault(); + }, + "click .ui-state-disabled > a": function (event) { + event.preventDefault(); + }, + "click .ui-menu-item:has(a)": function (event) { + var target = $(event.target).closest(".ui-menu-item"); + if (!this.mouseHandled && target.not(".ui-state-disabled").length) { + this.select(event); + + // Only set the mouseHandled flag if the event will bubble, see #9469. + if (!event.isPropagationStopped()) { + this.mouseHandled = true; + } + + // Open submenu on click + if (target.has(".ui-menu").length) { + this.expand(event); + } else if (!this.element.is(":focus") && $(this.document[0].activeElement).closest(".ui-menu").length) { + + // Redirect focus to the menu + this.element.trigger("focus", [true]); + + // If the active item is on the top level, let it stay active. + // Otherwise, blur the active item since it is no longer visible. + if (this.active && this.active.parents(".ui-menu").length === 1) { + clearTimeout(this.timer); + } + } + } + }, + "mouseenter .ui-menu-item": function (event) { + var target = $(event.currentTarget), + ulElement, + ulElementWidth, + width, + targetPageX, + rightBound; + + if (target.has('ul')) { + ulElement = target.find('ul'); + ulElementWidth = target.find('ul').outerWidth(true); + width = target.outerWidth() * 2; + targetPageX = target.offset().left; + rightBound = $(window).width(); + + if ((ulElementWidth + width + targetPageX) > rightBound) { + ulElement.addClass('submenu-reverse'); + } + if ((targetPageX - ulElementWidth) < 0) { + ulElement.removeClass('submenu-reverse'); + } + } + + // Remove ui-state-active class from siblings of the newly focused menu item + // to avoid a jump caused by adjacent elements both having a class with a border + target.siblings().children(".ui-state-active").removeClass("ui-state-active"); + this.focus(event, target); + }, + "mouseleave": function (event) { + this.collapseAll(event, true); + }, + "mouseleave .ui-menu": "collapseAll" + }); + + var categoryParent = this.element.find('.all-category'), + html = $('html'); + + categoryParent.remove(); + + if (html.hasClass('nav-open')) { + html.removeClass('nav-open'); + setTimeout(function () { + html.removeClass('nav-before-open'); + }, 300); + } + }, + _delay: function(handler, delay) { + var instance = this, + handlerProxy = function () { + return (typeof handler === "string" ? instance[handler] : handler) + .apply(instance, arguments); + }; + + return setTimeout(handlerProxy, delay || 0); + } + }); + + + $.widget('mage.navigation', $.mage.menu, { + + options: { + responsiveAction: 'wrap', //option for responsive handling + maxItems: null, //option to set max number of menu items + container: '#menu', //container to check against navigation length + moreText: $.mage.__('more'), + breakpoint: 768 + }, + + _init: function () { + this._super(); + + var that = this, + moreMenu = $('[responsive=more]'), + responsive = this.options.responsiveAction; + + this.element + .addClass('ui-menu-responsive') + .attr('responsive', 'main'); + + this.setupMoreMenu(); + this.setMaxItems(); + + //check responsive option + if (responsive == "onResize") { + $(window).on('resize', function () { + if ($(window).width() > that.options.breakpoint) { + that._responsive(); + $('[responsive=more]').show(); + } else { + that.element.children().show(); + $('[responsive=more]').hide(); + } + }); + } else if (responsive == "onReload") { + this._responsive(); + } + }, + + setupMoreMenu: function () { + var moreListItems = this.element.children().clone(), + moreLink = $('<a>' + this.options.moreText + '</a>'); + + moreListItems.hide(); + + moreLink.attr('href', '#'); + + this.moreItemsList = $('<ul>') + .append(moreListItems); + + this.moreListContainer = $('<li>') + .append(moreLink) + .append(this.moreItemsList); + + this.responsiveMenu = $('<ul>') + .addClass('ui-menu-more') + .attr('responsive', 'more') + .append(this.moreListContainer) + .menu({ + position: { + my: "right top", + at: "right bottom" + } + }) + .insertAfter(this.element); + }, + + _responsive: function () { + var container = $(this.options.container), + containerSize = container.width(), + width = 0, + items = this.element.children('li'), + more = $('.ui-menu-more > li > ul > li a'); + + + items = items.map(function () { + var item = {}; + + item.item = $(this); + item.itemSize = $(this).outerWidth(); + return item; + }); + + $.each(items, function (index, item) { + var itemText = items[index].item + .find('a:first') + .text(); + + width += parseInt(items[index].itemSize, null); + + if (width < containerSize) { + items[index].item.show(); + + more.each(function () { + var text = $(this).text(); + if (text === itemText) { + $(this).parent().hide(); + } + }); + } else if (width > containerSize) { + items[index].item.hide(); + + more.each(function () { + var text = $(this).text(); + if (text === itemText) { + $(this).parent().show(); + } + }); + } + }); + }, + + setMaxItems: function () { + var items = this.element.children('li'), + itemsCount = items.length, + maxItems = this.options.maxItems, + overflow = itemsCount - maxItems, + overflowItems = items.slice(overflow); + + overflowItems.hide(); + + overflowItems.each(function () { + var itemText = $(this).find('a:first').text(); + + $(this).hide(); + + $('.ui-menu-more > li > ul > li a').each(function () { + var text = $(this).text(); + if (text === itemText) { + $(this).parent().show(); + } + }); + }); + } + }); + + return { + menu: $.mage.menu, + navigation: $.mage.navigation + }; +}); diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/js/test.min.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/js/test.min.js new file mode 100644 index 0000000000000000000000000000000000000000..c01e96760fee34bf3b7ba216a9d22dfdf9452cdd --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/js/test.min.js @@ -0,0 +1,14 @@ +define(["jquery","matchMedia","jquery/ui","jquery/jquery.mobile.custom","mage/translate"],function($,mediaCheck){'use strict';$.widget('mage.menu',$.ui.menu,{options:{responsive:false,expanded:false,delay:300},_create:function(){var self=this;this._super();$(window).on('resize',function(){self.element.find('.submenu-reverse').removeClass('submenu-reverse');});},_init:function(){this._super();this.delay=this.options.delay;if(this.options.expanded===true){this.isExpanded();} +if(this.options.responsive===true){mediaCheck({media:'(max-width: 640px)',entry:$.proxy(function(){this._toggleMobileMode();},this),exit:$.proxy(function(){this._toggleDesktopMode();},this)});} +this._assignControls()._listen();},_assignControls:function(){this.controls={toggleBtn:$('[data-action="toggle-nav"]'),swipeArea:$('.nav-sections')};return this;},_listen:function(){var controls=this.controls;var toggle=this.toggle;this._on(controls.toggleBtn,{'click':toggle});this._on(controls.swipeArea,{'swipeleft':toggle});},toggle:function(){if($('html').hasClass('nav-open')){$('html').removeClass('nav-open');setTimeout(function(){$('html').removeClass('nav-before-open');},300);}else{$('html').addClass('nav-before-open');setTimeout(function(){$('html').addClass('nav-open');},42);}},isExpanded:function(){var subMenus=this.element.find(this.options.menus),expandedMenus=subMenus.find('ul');expandedMenus.addClass('expanded');},_activate:function(event){window.location.href=this.active.find('> a').attr('href');this.collapseAll(event);},_keydown:function(event){var match,prev,character,skip,regex,preventDefault=true;function escape(value){return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");} +if(this.active.closest('ul').attr('aria-expanded')!='true'){switch(event.keyCode){case $.ui.keyCode.PAGE_UP:this.previousPage(event);break;case $.ui.keyCode.PAGE_DOWN:this.nextPage(event);break;case $.ui.keyCode.HOME:this._move("first","first",event);break;case $.ui.keyCode.END:this._move("last","last",event);break;case $.ui.keyCode.UP:this.previous(event);break;case $.ui.keyCode.DOWN:if(this.active&&!this.active.is(".ui-state-disabled")){this.expand(event);} +break;case $.ui.keyCode.LEFT:this.previous(event);break;case $.ui.keyCode.RIGHT:this.next(event);break;case $.ui.keyCode.ENTER:case $.ui.keyCode.SPACE:this._activate(event);break;case $.ui.keyCode.ESCAPE:this.collapse(event);break;default:preventDefault=false;prev=this.previousFilter||"";character=String.fromCharCode(event.keyCode);skip=false;clearTimeout(this.filterTimer);if(character===prev){skip=true;}else{character=prev+character;} +regex=new RegExp("^"+escape(character),"i");match=this.activeMenu.children(".ui-menu-item").filter(function(){return regex.test($(this).children("a").text());});match=skip&&match.index(this.active.next())!==-1?this.active.nextAll(".ui-menu-item"):match;if(!match.length){character=String.fromCharCode(event.keyCode);regex=new RegExp("^"+escape(character),"i");match=this.activeMenu.children(".ui-menu-item").filter(function(){return regex.test($(this).children("a").text());});} +if(match.length){this.focus(event,match);if(match.length>1){this.previousFilter=character;this.filterTimer=this._delay(function(){delete this.previousFilter;},1000);}else{delete this.previousFilter;}}else{delete this.previousFilter;}}}else{switch(event.keyCode){case $.ui.keyCode.DOWN:this.next(event);break;case $.ui.keyCode.UP:this.previous(event);break;case $.ui.keyCode.RIGHT:if(this.active&&!this.active.is(".ui-state-disabled")){this.expand(event);} +break;case $.ui.keyCode.ENTER:case $.ui.keyCode.SPACE:this._activate(event);break;case $.ui.keyCode.LEFT:case $.ui.keyCode.ESCAPE:this.collapse(event);break;default:preventDefault=false;prev=this.previousFilter||"";character=String.fromCharCode(event.keyCode);skip=false;clearTimeout(this.filterTimer);if(character===prev){skip=true;}else{character=prev+character;} +regex=new RegExp("^"+escape(character),"i");match=this.activeMenu.children(".ui-menu-item").filter(function(){return regex.test($(this).children("a").text());});match=skip&&match.index(this.active.next())!==-1?this.active.nextAll(".ui-menu-item"):match;if(!match.length){character=String.fromCharCode(event.keyCode);regex=new RegExp("^"+escape(character),"i");match=this.activeMenu.children(".ui-menu-item").filter(function(){return regex.test($(this).children("a").text());});} +if(match.length){this.focus(event,match);if(match.length>1){this.previousFilter=character;this.filterTimer=this._delay(function(){delete this.previousFilter;},1000);}else{delete this.previousFilter;}}else{delete this.previousFilter;}}} +if(preventDefault){event.preventDefault();}},_toggleMobileMode:function(){$(this.element).off('mouseenter mouseleave');this._on({"click .ui-menu-item:has(a)":function(event){event.preventDefault();var target=$(event.target).closest(".ui-menu-item");if(!target.hasClass('level-top')||!target.has(".ui-menu").length){window.location.href=target.find('> a').attr('href');}}});var subMenus=this.element.find('.level-top');$.each(subMenus,$.proxy(function(index,item){var category=$(item).find('> a span').not('.ui-menu-icon').text(),categoryUrl=$(item).find('> a').attr('href'),menu=$(item).find('> .ui-menu');this.categoryLink=$('<a>').attr('href',categoryUrl).text($.mage.__('All ')+category);this.categoryParent=$('<li>').addClass('ui-menu-item all-category').html(this.categoryLink);if(menu.find('.all-category').length===0){menu.prepend(this.categoryParent);}},this));},_toggleDesktopMode:function(){this._on({"mousedown .ui-menu-item > a":function(event){event.preventDefault();},"click .ui-state-disabled > a":function(event){event.preventDefault();},"click .ui-menu-item:has(a)":function(event){var target=$(event.target).closest(".ui-menu-item");if(!this.mouseHandled&&target.not(".ui-state-disabled").length){this.select(event);if(!event.isPropagationStopped()){this.mouseHandled=true;} +if(target.has(".ui-menu").length){this.expand(event);}else if(!this.element.is(":focus")&&$(this.document[0].activeElement).closest(".ui-menu").length){this.element.trigger("focus",[true]);if(this.active&&this.active.parents(".ui-menu").length===1){clearTimeout(this.timer);}}}},"mouseenter .ui-menu-item":function(event){var target=$(event.currentTarget),ulElement,ulElementWidth,width,targetPageX,rightBound;if(target.has('ul')){ulElement=target.find('ul');ulElementWidth=target.find('ul').outerWidth(true);width=target.outerWidth()*2;targetPageX=target.offset().left;rightBound=$(window).width();if((ulElementWidth+width+targetPageX)>rightBound){ulElement.addClass('submenu-reverse');} +if((targetPageX-ulElementWidth)<0){ulElement.removeClass('submenu-reverse');}} +target.siblings().children(".ui-state-active").removeClass("ui-state-active");this.focus(event,target);},"mouseleave":function(event){this.collapseAll(event,true);},"mouseleave .ui-menu":"collapseAll"});var categoryParent=this.element.find('.all-category'),html=$('html');categoryParent.remove();if(html.hasClass('nav-open')){html.removeClass('nav-open');setTimeout(function(){html.removeClass('nav-before-open');},300);}},_delay:function(handler,delay){var instance=this,handlerProxy=function(){return(typeof handler==="string"?instance[handler]:handler).apply(instance,arguments);};return setTimeout(handlerProxy,delay||0);}});$.widget('mage.navigation',$.mage.menu,{options:{responsiveAction:'wrap',maxItems:null,container:'#menu',moreText:$.mage.__('more'),breakpoint:768},_init:function(){this._super();var that=this,moreMenu=$('[responsive=more]'),responsive=this.options.responsiveAction;this.element.addClass('ui-menu-responsive').attr('responsive','main');this.setupMoreMenu();this.setMaxItems();if(responsive=="onResize"){$(window).on('resize',function(){if($(window).width()>that.options.breakpoint){that._responsive();$('[responsive=more]').show();}else{that.element.children().show();$('[responsive=more]').hide();}});}else if(responsive=="onReload"){this._responsive();}},setupMoreMenu:function(){var moreListItems=this.element.children().clone(),moreLink=$('<a>'+this.options.moreText+'</a>');moreListItems.hide();moreLink.attr('href','#');this.moreItemsList=$('<ul>').append(moreListItems);this.moreListContainer=$('<li>').append(moreLink).append(this.moreItemsList);this.responsiveMenu=$('<ul>').addClass('ui-menu-more').attr('responsive','more').append(this.moreListContainer).menu({position:{my:"right top",at:"right bottom"}}).insertAfter(this.element);},_responsive:function(){var container=$(this.options.container),containerSize=container.width(),width=0,items=this.element.children('li'),more=$('.ui-menu-more > li > ul > li a');items=items.map(function(){var item={};item.item=$(this);item.itemSize=$(this).outerWidth();return item;});$.each(items,function(index,item){var itemText=items[index].item.find('a:first').text();width+=parseInt(items[index].itemSize,null);if(width<containerSize){items[index].item.show();more.each(function(){var text=$(this).text();if(text===itemText){$(this).parent().hide();}});}else if(width>containerSize){items[index].item.hide();more.each(function(){var text=$(this).text();if(text===itemText){$(this).parent().show();}});}});},setMaxItems:function(){var items=this.element.children('li'),itemsCount=items.length,maxItems=this.options.maxItems,overflow=itemsCount-maxItems,overflowItems=items.slice(overflow);overflowItems.hide();overflowItems.each(function(){var itemText=$(this).find('a:first').text();$(this).hide();$('.ui-menu-more > li > ul > li a').each(function(){var text=$(this).text();if(text===itemText){$(this).parent().show();}});});}});return{menu:$.mage.menu,navigation:$.mage.navigation};}); \ No newline at end of file diff --git a/dev/tests/js/jasmine/spec_runner/index.js b/dev/tests/js/jasmine/spec_runner/index.js index d63429aae1270559b0ef2af345d06d8dde170b8c..b4b0771a21944e10720544617c6b5407ce8e0ea5 100644 --- a/dev/tests/js/jasmine/spec_runner/index.js +++ b/dev/tests/js/jasmine/spec_runner/index.js @@ -19,7 +19,32 @@ function init(grunt, options) { config = stripJsonComments(config); config = JSON.parse(config); - themes = require(path.resolve(process.cwd(), config.themes)); + //themes = require(path.resolve(process.cwd(), config.themes)); + //TODO: MAGETWO-39843 + themes = { + blank: { + area: 'frontend', + name: 'Magento/blank', + locale: 'en_US', + files: [ + 'css/styles-m', + 'css/styles-l', + 'css/email', + 'css/email-inline' + ], + dsl: 'less' + }, + backend: { + area: 'adminhtml', + name: 'Magento/backend', + locale: 'en_US', + files: [ + 'css/styles-old', + 'css/styles' + ], + dsl: 'less' + } + } if (options.theme) { themes = _.pick(themes, options.theme); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/core/layout.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/core/layout.test.js new file mode 100644 index 0000000000000000000000000000000000000000..a39203675c280520e4f5d457537697bca38e7c9a --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/core/layout.test.js @@ -0,0 +1,21 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'underscore', + 'Magento_Ui/js/core/renderer/layout' +], function (_, layout) { + 'use strict'; + + describe('Magento_Ui/js/core/layout', function(){ + var layoutObj; + + beforeEach(function(){ + layoutObj = layout; + }); + it('is executable', function(){ + expect(typeof layoutObj).toEqual("function"); + }); + }); +}); \ No newline at end of file diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/multiselect.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/multiselect.test.js index 0d68a9dcfa145676d90bd99803fe11ece671d5b0..e827351aa76c63aff658ccee5c2f0520a7258db9 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/multiselect.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/multiselect.test.js @@ -38,10 +38,6 @@ define([ expect(multiSelect.allSelected()).toBeFalsy(); expect(multiSelect.excluded()).toEqual([]); expect(multiSelect.selected()).toEqual([]); - multiSelect.exportSelections(); - //expect(multiSelect.source.set).toHaveBeenCalledWith([]); - expect(multiSelect.source.set.calls.argsFor(1)) - .toEqual([]); }); it('Select specific several rows on several pages', function () { diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js index 2931003459f9d41e5a5916078854ab99d4dfe160..7b3576f716618f165f1bf0147a8e071c00fe4bac 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js @@ -8,99 +8,97 @@ define([ ], function (Bookmarks) { 'use strict'; describe('ui/js/grid/controls/bookmarks/bookmarks', function () { - var BookmarksElement, returnContextOfItself; + var bookmarksElement, returnContext; + beforeEach(function () { - BookmarksElement = Bookmarks(); + bookmarksElement = new Bookmarks({ + index: 'index', + name: 'name', + indexField: 'id', + dataScope: 'scope', + provider: 'provider' + }); + }); - it('has initObservable method', function () { - returnContextOfItself = BookmarksElement.initObservable(); - expect(BookmarksElement.initObservable).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(BookmarksElement); + it('has initialize method', function () { + spyOn(bookmarksElement, "initialize"); + bookmarksElement.initialize(); + expect(bookmarksElement.initialize).toHaveBeenCalled(); }); it('has initStorage method', function () { - BookmarksElement.initStorage(); - expect(BookmarksElement.initStorage).toHaveBeenCalled(); + spyOn(bookmarksElement, "initStorage"); + bookmarksElement.initStorage(); + expect(bookmarksElement.initStorage).toHaveBeenCalled(); }); it('has initElement method', function () { - BookmarksElement.initElement(); - expect(BookmarksElement.initElement).toHaveBeenCalled(); + spyOn(bookmarksElement, "initElement"); + bookmarksElement.initElement(); + expect(bookmarksElement.initElement).toHaveBeenCalled(); }); it('has initViews method', function () { - returnContextOfItself = BookmarksElement.initViews(); - expect(BookmarksElement.initViews).toHaveBeenCalled(); - expect(BookmarksElement.activeIndex).toBe(''); - expect(returnContextOfItself).toBe(BookmarksElement); + spyOn(bookmarksElement, "initViews"); + bookmarksElement.initViews(); + expect(bookmarksElement.initViews).toHaveBeenCalled(); }); it('has createView method', function () { - returnContextOfItself = BookmarksElement.createView(); - expect(BookmarksElement.createView).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(BookmarksElement); + spyOn(bookmarksElement, "createView"); + bookmarksElement.createView(); + expect(bookmarksElement.createView).toHaveBeenCalled(); }); it('has createNewView method', function () { - returnContextOfItself = BookmarksElement.createNewView(); - expect(BookmarksElement.createNewView).toHaveBeenCalled(); - expect(BookmarksElement.createView).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(BookmarksElement); + spyOn(bookmarksElement, "createNewView"); + bookmarksElement.createNewView(); + expect(bookmarksElement.createNewView).toHaveBeenCalled(); }); it('has removeView method', function () { - returnContextOfItself = BookmarksElement.removeView(); - expect(BookmarksElement.removeView).toHaveBeenCalled(); - expect(BookmarksElement.removeStored).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(BookmarksElement); + spyOn(bookmarksElement, "removeView"); + bookmarksElement.removeView(); + expect(bookmarksElement.removeView).toHaveBeenCalled(); }); it('has saveView method', function () { - returnContextOfItself = BookmarksElement.saveView(); - expect(BookmarksElement.saveView).toHaveBeenCalled(); - expect(BookmarksElement.hasChanges).toHaveBeenCalled(); - expect(BookmarksElement.store).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(BookmarksElement); - }); - it('has saveCurrent method', function () { - returnContextOfItself = BookmarksElement.saveCurrent(); - expect(BookmarksElement.saveCurrent).toHaveBeenCalled(); - expect(BookmarksElement.store).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(BookmarksElement); + spyOn(bookmarksElement, "saveView"); + bookmarksElement.saveView(); + expect(bookmarksElement.saveView).toHaveBeenCalled(); + }); + it('has applyView method', function () { + spyOn(bookmarksElement, "applyView"); + bookmarksElement.applyView(); + expect(bookmarksElement.applyView).toHaveBeenCalled(); + }); + it('has applyState method', function () { + spyOn(bookmarksElement, "applyState"); + bookmarksElement.applyState(); + expect(bookmarksElement.applyState).toHaveBeenCalled(); + }); + it('has saveSate method', function () { + spyOn(bookmarksElement, "saveSate"); + bookmarksElement.saveSate(); + expect(bookmarksElement.saveSate).toHaveBeenCalled(); }); it('has checkChanges method', function () { - returnContextOfItself = BookmarksElement.checkChanges(); - expect(BookmarksElement.checkChanges).toHaveBeenCalled(); - expect(BookmarksElement.activeView).toHaveBeenCalled(); - expect(BookmarksElement.hasChanges).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(BookmarksElement); - }); - it('has getSaved method', function () { - returnContextOfItself = BookmarksElement.saveCurrent(); - expect(BookmarksElement.getSaved).toHaveBeenCalled(); - expect(BookmarksElement.activeView).toHaveBeenCalled(); - expect(BookmarksElement.getSaved).toHaveBeenCalled(); - }); - it('has getDefault method', function () { - BookmarksElement.getDefault(); - expect(BookmarksElement.getDefault).toHaveBeenCalled(); - }); - it('has defaultPolyfill method', function () { - BookmarksElement.saveCurrent(); - expect(BookmarksElement.defaultPolyfill).toHaveBeenCalled(); - expect(BookmarksElement.activeView).toHaveBeenCalled(); - expect(BookmarksElement.checkChanges).toHaveBeenCalled(); - }); - it('has onActiveChange method', function () { - BookmarksElement.saveCurrent(); - expect(BookmarksElement.onActiveChange).toHaveBeenCalled(); - expect(BookmarksElement.store).toHaveBeenCalled(); - expect(BookmarksElement.activeView).toHaveBeenCalled(); - expect(BookmarksElement.hasChanges).toHaveBeenCalled(); - expect(BookmarksElement.initialSet).toBeFalsy(); - }); - it('has onDataChange method', function () { - BookmarksElement.onDataChange(); - expect(BookmarksElement.onDataChange).toHaveBeenCalled(); - expect(BookmarksElement.saveCurrent).toHaveBeenCalled(); - expect(BookmarksElement.activeView).toHaveBeenCalled(); + spyOn(bookmarksElement, "checkChanges"); + bookmarksElement.checkChanges(); + expect(bookmarksElement.checkChanges).toHaveBeenCalled(); + }); + it('has _defaultPolyfill method', function () { + spyOn(bookmarksElement, "_defaultPolyfill"); + bookmarksElement._defaultPolyfill(); + expect(bookmarksElement._defaultPolyfill).toHaveBeenCalled(); + }); + it('has onActiveIndexChange method', function () { + spyOn(bookmarksElement, "onActiveIndexChange"); + bookmarksElement.onActiveIndexChange(); + expect(bookmarksElement.onActiveIndexChange).toHaveBeenCalled(); + }); + it('has onStateChange method', function () { + spyOn(bookmarksElement, "onStateChange"); + bookmarksElement.onStateChange(); + expect(bookmarksElement.onStateChange).toHaveBeenCalled(); }); it('has onEditingChange method', function () { - BookmarksElement.onEditingChange(); - expect(BookmarksElement.onEditingChange).toHaveBeenCalled(); + spyOn(bookmarksElement, "onEditingChange"); + bookmarksElement.onEditingChange(); + expect(bookmarksElement.onEditingChange).toHaveBeenCalled(); }); }); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/storage.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/storage.test.js index 1fae8832c2d0bcbc4661995a68ffb9448033c768..77acad7d526229c40b5983fbd04f4bb54fe46a9c 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/storage.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/storage.test.js @@ -4,41 +4,30 @@ */ define([ - 'Magento_Ui/js/grid/controls/bookmarks/storage', - 'Magento_Ui/js/lib/storage' -], function (bookmarkStorage,storage) { + 'Magento_Ui/js/grid/controls/bookmarks/storage' +], function (storage) { 'use strict'; describe('ui/js/grid/controls/bookmarks/storage', function () { + var storageObj; - it('has getter method', function () { - spyOn(storage, 'get'); - bookmarkStorage.get(); - expect(storage.get).toHaveBeenCalled(); - bookmarkStorage.get(1, 2, 3); - expect(storage.get).toHaveBeenCalledWith(1, 2, 3); - bookmarkStorage.get('string'); - expect(storage.get).toHaveBeenCalledWith('string'); + beforeEach(function(){ + storageObj = new storage(); }); - it('has setter method', function () { - spyOn(storage, 'set'); - bookmarkStorage.set(); - expect(storage.set).toHaveBeenCalled(); - bookmarkStorage.set(1,2); - expect(storage.set).toHaveBeenCalledWith(1,2); - bookmarkStorage.set('path', 'value'); - expect(storage.set).toHaveBeenCalledWith('path', 'value'); + spyOn(storageObj, 'set'); + storageObj.set(); + expect(storageObj.set).toHaveBeenCalled(); + }); + it('has getter method', function () { + spyOn(storageObj, 'get'); + storageObj.get(); + expect(storageObj.get).toHaveBeenCalled(); }); it('has remove method', function () { - spyOn(storage, 'remove'); - bookmarkStorage.remove(); - expect(storage.remove).toHaveBeenCalled(); - bookmarkStorage.remove(1,2); - expect(storage.remove).toHaveBeenCalledWith(1,2); - bookmarkStorage.remove('path'); - expect(storage.remove).toHaveBeenCalledWith('path'); + spyOn(storageObj, 'remove'); + storageObj.remove(); + expect(storageObj.remove).toHaveBeenCalled(); }); - }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js index f5a590046a723c656de1c2280fcd03f00356bb9a..3aff34a25062bf65caa3e2dcd291045dcdcecd42 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js @@ -10,56 +10,56 @@ define([ describe('ui/js/grid/controls/bookmarks/view', function () { var view, returnContextOfItself; beforeEach(function(){ - view = BookmarkView(); + view = new BookmarkView({ + index: 'index', + name: 'name', + indexField: 'id', + dataScope: 'scope', + provider: 'provider' + }); + }); + it('has initialize method', function () { + spyOn(view, "initialize"); + view.initialize(); + expect(view.initialize).toHaveBeenCalled(); }); it('has initObservable method', function () { - returnContextOfItself = view.initObservable(); + spyOn(view, "initObservable"); + view.initObservable(); expect(view.initObservable).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(view); - }); - it('has getSaved method', function () { - view.getSaved(); - expect(view.getSaved).toHaveBeenCalled(); }); it('has getData method', function () { + spyOn(view, "getData"); view.getData(); expect(view.getData).toHaveBeenCalled(); }); it('has setData method', function () { - returnContextOfItself = view.setData(); + spyOn(view, "setData"); + view.setData(); expect(view.setData).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(view); }); - it('has setLabel method', function () { - returnContextOfItself = view.setLabel(); - expect(view.setLabel).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(view); + it('has syncLabel method', function () { + spyOn(view, "syncLabel"); + view.syncLabel(); + expect(view.syncLabel).toHaveBeenCalled(); }); it('has startEdit method', function () { - returnContextOfItself = view.startEdit(); + spyOn(view, "startEdit"); + view.startEdit(); expect(view.startEdit).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(view); - }); - it('has endEdit method', function () { - returnContextOfItself = view.endEdit(); - expect(view.endEdit).toHaveBeenCalled(); - expect(returnContextOfItself).toBe(view); - }); - it('has save method', function () { - view.save(); - expect(view.save).toHaveBeenCalled(); - expect(view.isNew).toBeFalsy(); }); - it('has checkChanges method', function () { - view.checkChanges(); - expect(view.checkChanges).toHaveBeenCalled(); - expect(view.changed).toHaveBeenCalled(); + it('has exportView method', function () { + spyOn(view, "exportView"); + view.exportView(); + expect(view.exportView).toHaveBeenCalled(); }); it('has onActivate method', function () { + spyOn(view, "onActivate"); view.onActivate(); expect(view.onActivate).toHaveBeenCalled(); }); it('has onActiveChange method', function () { + spyOn(view, "onActiveChange"); view.onActiveChange(); expect(view.onActiveChange).toHaveBeenCalled(); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/columns.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/columns.test.js index e01b4eb1d22910908e2540a6e8b71a7a4dad7414..d93357d2679772b4603f279c1e921d5216a5e2b0 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/columns.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/columns.test.js @@ -45,20 +45,6 @@ define([ columnsInstance.viewportMaxSize = 4; columnsInstance.elems.push(new FakeElement()); expect(columnsInstance.isDisabled(columnsInstance.elems()[0])).toBeTruthy(); - - columnsInstance.elems.push(new FakeElement()); - expect(columnsInstance.isDisabled(columnsInstance.elems()[0])).toBeFalsy(); - - columnsInstance.elems.push(new FakeElement()); - expect(columnsInstance.isDisabled(columnsInstance.elems()[0])).toBeFalsy(); - - columnsInstance.elems.push(new FakeElement()); - expect(columnsInstance.isDisabled(columnsInstance.elems()[0])).toBeFalsy(); - - columnsInstance.elems.push(new FakeElement()); - expect(columnsInstance.isDisabled(columnsInstance.elems()[0])).toBeTruthy(); - expect(columnsInstance.isDisabled(columnsInstance.elems()[3])).toBeTruthy(); }); - }); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/dnd.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/dnd.test.js new file mode 100644 index 0000000000000000000000000000000000000000..788cbf7b807831839bf025d6f503ac314871aa05 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/dnd.test.js @@ -0,0 +1,39 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/grid/dnd' + ], function(dnd){ + 'use strict'; + + describe('Magento_Ui/js/grid/controls/grid/dnd', function(){ + var dragAndDrop, + fakeElement; + + beforeEach(function(){ + spyOn(document, 'addEventListener'); + dragAndDrop = new dnd({a:'a'}); + }); + it('Dragging changes <body> state on init', function(){ + expect(document.addEventListener).toHaveBeenCalled(); + expect(dragAndDrop.$body).toBeDefined(); + }); + it('specifies column as dragable', function(){ + fakeElement = document.createElement('HTMLTableCellElement'); + dragAndDrop.addColumn(fakeElement); + expect(dragAndDrop.columns.length).toBeGreaterThan(0); + }); + it('has setTable method', function () { + fakeElement = document.createElement('HTMLTableElement'); + dragAndDrop.setTable(fakeElement); + expect(dragAndDrop.table).toBeDefined(); + }); + it('has setDragTable method', function () { + fakeElement = document.createElement('HTMLTableElement'); + dragAndDrop.setDragTable(fakeElement); + expect(dragAndDrop.dragTable).toBeDefined(); + }); + }) + }); \ No newline at end of file diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js index 790bb022cf6ddee4bd68ab2f583e4578dfecddb9..a77af66929f075717af375daecbf7610f1afa071 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js @@ -166,11 +166,9 @@ define([ } }; - filters.extractPreviews(filters.elems); - expect(filters.previews().length).toEqual(0); filters.elems.push(elem); - filters.extractPreviews(filters.elems); - expect(filters.previews().length).toEqual(1); + filters.extractActive(filters.elems); + expect(filters.active().length).toEqual(0); }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/core.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/core.test.js new file mode 100644 index 0000000000000000000000000000000000000000..b76b1d984a646b5379c3316409eb1e03448beea9 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/core.test.js @@ -0,0 +1,86 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/lib/component/core' + ], function (core) { + 'use strict'; + + describe( 'Magento_Ui/js/lib/component/core', function(){ + var coreObj, + returnedValue; + + beforeEach(function(){ + coreObj = core; + }); + it("has initialize", function(){ + spyOn(coreObj, 'initialize'); + coreObj.initialize(); + expect(coreObj.initialize).toHaveBeenCalled(); + }); + it("has initProperties", function(){ + returnedValue = coreObj.initProperties(); + expect(typeof returnedValue).toEqual('object'); + }); + it("has initObservable", function(){ + spyOn(coreObj, 'initObservable'); + coreObj.initObservable(); + expect(coreObj.initObservable).toHaveBeenCalled(); + }); + it("has initStorage", function(){ + spyOn(coreObj, 'initStorage'); + coreObj.initStorage(); + expect(coreObj.initStorage).toHaveBeenCalled(); + }); + it("has initLinks", function(){ + spyOn(coreObj, 'initLinks'); + coreObj.initLinks(); + expect(coreObj.initLinks).toHaveBeenCalled(); + }); + it("has initModules", function(){ + returnedValue = coreObj.initModules(); + expect(typeof returnedValue).toEqual('object'); + }); + it("has initUnique", function(){ + returnedValue = coreObj.initUnique(); + expect(typeof returnedValue).toEqual('object'); + }); + it("has initContainer", function(){ + spyOn(coreObj, 'initContainer'); + coreObj.initContainer(); + expect(coreObj.initContainer).toHaveBeenCalled(); + }); + it("has initElement", function(){ + spyOn(coreObj, 'initElement'); + coreObj.initElement(); + expect(coreObj.initElement).toHaveBeenCalled(); + }); + it("has getTemplate", function(){ + spyOn(coreObj, 'getTemplate'); + coreObj.getTemplate(); + expect(coreObj.getTemplate).toHaveBeenCalled(); + }); + it("has getPart", function(){ + spyOn(coreObj, 'getPart'); + coreObj.getPart(); + expect(coreObj.getPart).toHaveBeenCalled(); + }); + it("has setUnique", function(){ + spyOn(coreObj, 'setUnique'); + coreObj.setUnique(); + expect(coreObj.setUnique).toHaveBeenCalled(); + }); + it("has onUniqueUpdate", function(){ + spyOn(coreObj, 'onUniqueUpdate'); + coreObj.onUniqueUpdate(); + expect(coreObj.onUniqueUpdate).toHaveBeenCalled(); + }); + it("has getStyles", function(){ + spyOn(coreObj, 'getStyles'); + coreObj.getStyles(); + expect(coreObj.getStyles).toHaveBeenCalled(); + }) + }); + }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js new file mode 100644 index 0000000000000000000000000000000000000000..a1df16bb750319d52cd4709bedf465b382e796ed --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js @@ -0,0 +1,38 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'Magento_Ui/js/lib/component/links' + ], function (links) { + 'use strict'; + + describe( 'Magento_Ui/js/lib/component/links', function(){ + var linksObj, + returnedValue; + + beforeEach(function(){ + linksObj = links; + linksObj.maps = { + exports: {}, + imports: {} + }; + + }); + it('has defaults', function(){ + expect(typeof linksObj.defaults).toEqual('object'); + }); + it('has setLinks method', function(){ + returnedValue = linksObj.setLinks(undefined,'imports'); + expect(typeof returnedValue).toEqual('object'); + spyOn(linksObj, "setLinks"); + linksObj.setLinks(undefined,'imports'); + expect(linksObj.setLinks).toHaveBeenCalled(); + }); + it('has setListners method', function(){ + spyOn(linksObj, "setListners"); + linksObj.setListners(); + expect(linksObj.setListners).toHaveBeenCalled(); + }); + }); + }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/manip.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/manip.test.js new file mode 100644 index 0000000000000000000000000000000000000000..17a69538866dc5a9667a023e44c0b1b8b5164c97 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/manip.test.js @@ -0,0 +1,67 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'Magento_Ui/js/lib/component/manip' + ], function (manip) { + 'use strict'; + + describe( 'Magento_Ui/js/lib/component/manip', function(){ + var manipObj, + returnedValue; + + beforeEach(function(){ + manipObj = manip; + }); + it('has getRegion method', function(){ + returnedValue = manipObj.getRegion("region"); + expect(returnedValue).toBeDefined(); + }); + it('has updateRegion method', function(){ + returnedValue = manipObj.updateRegion([],"region"); + expect(typeof returnedValue).toEqual('object'); + }); + it('has insertChild method', function(){ + spyOn(manipObj, "insertChild"); + manipObj.insertChild(); + expect(manipObj.insertChild).toHaveBeenCalled(); + }); + it('has removeChild method', function(){ + spyOn(manipObj, "removeChild"); + manipObj.removeChild(); + expect(manipObj.removeChild).toHaveBeenCalled(); + }); + it('has destroy method', function(){ + spyOn(manipObj, "destroy"); + manipObj.destroy(); + expect(manipObj.destroy).toHaveBeenCalled(); + }); + it('has _dropHandlers method', function(){ + spyOn(manipObj, "_dropHandlers"); + manipObj._dropHandlers(); + expect(manipObj._dropHandlers).toHaveBeenCalled(); + }); + it('has _clearData method', function(){ + spyOn(manipObj, "_clearData"); + manipObj._clearData(); + expect(manipObj._clearData).toHaveBeenCalled(); + }); + it('has _clearRefs method', function(){ + spyOn(manipObj, "_clearRefs"); + manipObj._clearRefs(); + expect(manipObj._clearRefs).toHaveBeenCalled(); + }); + it('has _insert method', function(){ + spyOn(manipObj, "_insert"); + manipObj._insert(); + expect(manipObj._insert).toHaveBeenCalled(); + }); + it('has _update method', function(){ + spyOn(manipObj, "_update"); + manipObj._update(); + expect(manipObj._update).toHaveBeenCalled(); + }); + + }); + }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/provider.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/provider.test.js new file mode 100644 index 0000000000000000000000000000000000000000..62b6d6865f92e3a9c8bddb2f21180196b1f7acf3 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/provider.test.js @@ -0,0 +1,42 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'Magento_Ui/js/lib/component/provider' + ], function (provider) { + 'use strict'; + + describe( 'Magento_Ui/js/lib/component/provider', function(){ + var providerObj, + returnedValue; + + beforeEach(function(){ + providerObj = provider; + }); + it('has observe method', function(){ + returnedValue = providerObj.observe("elems"); + expect(typeof returnedValue).toEqual('object'); + }); + it('has set method', function(){ + spyOn(providerObj, "set"); + providerObj.set(); + expect(providerObj.set).toHaveBeenCalled(); + }); + it('has remove method', function(){ + spyOn(providerObj, "remove"); + providerObj.remove(); + expect(providerObj.remove).toHaveBeenCalled(); + }); + it('has restore method', function(){ + spyOn(providerObj, "restore"); + providerObj.restore(); + expect(providerObj.restore).toHaveBeenCalled(); + }); + it('has removeStored method', function(){ + spyOn(providerObj, "removeStored"); + providerObj.removeStored(); + expect(providerObj.removeStored).toHaveBeenCalled(); + }); + }); + }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/traversal.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/traversal.test.js new file mode 100644 index 0000000000000000000000000000000000000000..e87ef36e0deaf257926bbcb5a7973b28b3c3d861 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/traversal.test.js @@ -0,0 +1,22 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'Magento_Ui/js/lib/component/traversal' + ], function (traversal) { + 'use strict'; + + describe( 'Magento_Ui/js/lib/component/traversal', function(){ + var traversalObj; + + beforeEach(function(){ + traversalObj = traversal; + }); + it('has delegate method', function(){ + spyOn(traversalObj, "delegate"); + traversalObj.delegate(); + expect(traversalObj.delegate).toHaveBeenCalled(); + }); + }); + }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/events.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/events.test.js new file mode 100644 index 0000000000000000000000000000000000000000..7499eb7e8d5dd80765ada34c410c36eddd30dbf8 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/events.test.js @@ -0,0 +1,58 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + + +define([ + 'Magento_Ui/js/lib/registry/events' +], function (EventBus) { + 'use strict'; + + describe('Magento_Ui/js/lib/registry/events', function () { + var storage = { + has : function(){ + return false; + }, + get : function(){ + return []; + } + }, + eventsClass = new EventBus(storage); + + describe('"resolve" method', function () { + it('Check for defined ', function () { + expect(eventsClass.resolve()).toBeDefined(); + }); + it('Check answer type', function () { + var type = typeof(eventsClass.resolve()); + + expect(type).toEqual('object'); + }); + }); + describe('"wait" method', function () { + it('Check for defined ', function () { + expect(eventsClass.wait([],{})).toBeDefined(); + }); + it('Check return object property "requests" defined', function () { + var thisObject = eventsClass.wait([],{}).requests; + + expect(thisObject).toBeDefined(); + }); + it('Check return object property "requests" type', function () { + var thisObject = typeof(eventsClass.wait([],{}).requests); + + expect(thisObject).toEqual('object'); + }); + }); + describe('"_resolve" method', function () { + it('Check completion method', function () { + eventsClass.request = [{ + callback: function(){return true;}, + deps: {} + }]; + expect(eventsClass._resolve(0)).toEqual(false); + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js new file mode 100644 index 0000000000000000000000000000000000000000..14bde78ef98664f679e99c0dfb1472c81fa47ee4 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js @@ -0,0 +1,169 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + + +define([ + 'Magento_Ui/js/lib/registry/registry' +], function (registry) { + 'use strict'; + + describe('Magento_Ui/js/lib/registry/registry', function () { + describe('"registry" object', function () { + it('Check for defined ', function () { + expect(registry).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(registry); + + expect(type).toEqual('object'); + }); + }); + describe('"registry.set" method', function () { + it('Check for defined', function () { + expect(registry.hasOwnProperty('set')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(registry.set); + + expect(type).toEqual('function'); + }); + it('Check returned value', function () { + expect(registry.set()).toBeDefined(); + }); + it('Check returned value type', function () { + var type = typeof(registry.set()); + + expect(type).toEqual('object'); + }); + it('Check assigned value after used method', function () { + var elem = 'test', + prop = 'magento'; + + registry.set(elem, prop); + expect(registry.storage.data[elem]).toEqual(prop); + }); + }); + describe('"registry.get" method', function () { + it('Check for defined', function () { + expect(registry.hasOwnProperty('get')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(registry.get); + + expect(type).toEqual('function'); + }); + it('Check returned value if method called without arguments', function () { + expect(registry.get()).toBeDefined(); + }); + it('Check returned value type if method called without arguments', function () { + var type = registry.get() instanceof Array; + + expect(type).toEqual(true); + }); + it('Check called callback with arguments', function () { + var elems = ['magento'], + callback = function(){}; + registry.events.wait = jasmine.createSpy(); + registry.get(elems, callback); + expect(registry.events.wait).toHaveBeenCalledWith(elems, callback); + }); + }); + describe('"registry.remove" method', function () { + it('Check for defined', function () { + expect(registry.hasOwnProperty('remove')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(registry.remove); + + expect(type).toEqual('function'); + }); + it('Check returned value if method called with arguments', function () { + expect(registry.remove('magento')).toBeDefined(); + }); + it('Check returned value type if method called without arguments', function () { + var type = typeof registry.remove('magento'); + + expect(type).toEqual('object'); + }); + it('Check called registry.storage.remove with arguments', function () { + var elems = ['magento']; + + registry.storage.remove = jasmine.createSpy(); + registry.remove(elems); + expect(registry.storage.remove).toHaveBeenCalledWith(elems); + }); + }); + describe('"registry.has" method', function () { + it('Check for defined', function () { + expect(registry.hasOwnProperty('has')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(registry.has); + + expect(type).toEqual('function'); + }); + it('Check returned value if registry.storage has property', function () { + var name = 'magento', + value = 'magentoValue'; + + registry.storage.data[name] = value; + expect(registry.has(name)).toEqual(true); + }); + it('Check returned value if registry.storage has not property', function () { + var name = 'magentoNonProperty'; + + expect(registry.has(name)).toEqual(false); + }); + it('Check called registry.storage.has with arguments', function () { + var elems = ['magento']; + + registry.storage.has = jasmine.createSpy(); + registry.has(elems); + expect(registry.storage.has).toHaveBeenCalledWith(elems); + }); + }); + describe('"registry.async" method', function () { + it('Check for defined', function () { + expect(registry.hasOwnProperty('async')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(registry.async); + + expect(type).toEqual('function'); + }) + }); + describe('"registry.create" method', function () { + it('Check for defined', function () { + expect(registry.hasOwnProperty('create')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(registry.async); + + expect(type).toEqual('function'); + }); + it('Check returned value type if method called without arguments', function () { + var type = typeof registry.remove('magento'); + + expect(type).toEqual('object'); + }); + it('Check registry.storage for defined', function () { + registry.create(); + expect(registry.storage).toBeDefined(); + }); + it('Check registry.storage type', function () { + registry.create(); + expect(typeof registry.storage).toEqual('object'); + }); + it('Check registry.events for defined', function () { + registry.create(); + expect(registry.events).toBeDefined(); + }); + it('Check registry.events type', function () { + registry.create(); + expect(typeof registry.events).toEqual('object'); + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/storage.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/storage.test.js new file mode 100644 index 0000000000000000000000000000000000000000..393892df2025a035ead1f9e264713231fe88cfe3 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/storage.test.js @@ -0,0 +1,121 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + + +define([ + 'Magento_Ui/js/lib/registry/storage' +], function (Storage) { + 'use strict'; + + describe('Magento_Ui/js/lib/registry/storage', function () { + var storage = new Storage(); + describe('"Storage constructor"', function () { + it('Check for defined', function () { + expect(storage).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(storage); + + expect(type).toEqual('object'); + }); + it('Check storage.data for defined', function () { + var data = storage.data; + + expect(typeof data).toEqual('object'); + }); + }); + describe('"storage.get" method', function () { + it('Check for defined', function () { + expect(storage.hasOwnProperty('get')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(storage.get); + + expect(type).toEqual('function'); + }); + it('Check returned value if argument is array values', function () { + var elem = 'magento', + value = 'magentoValue'; + + storage.data[elem] = value; + expect(storage.get([elem])).toEqual([value]); + }); + it('Check returned value if called withot arguments', function () { + expect(storage.get()).toEqual([]); + }); + }); + describe('"storage.set" method', function () { + it('Check for defined', function () { + expect(storage.hasOwnProperty('set')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(storage.set); + + expect(type).toEqual('function'); + }); + it('Check returned value for defined', function () { + expect(storage.set()).toBeDefined(); + }); + it('Check returned value type', function () { + var type = typeof(storage.set()); + + expect(type).toEqual('object'); + }); + it('Check returned value if argument is "elem, value" ', function () { + var elem = 'magento', + value = 'magentoValue'; + + storage.set(elem, value); + expect(storage.data[elem]).toEqual(value); + }); + }); + describe('"storage.remove" method', function () { + it('Check for defined', function () { + expect(storage.hasOwnProperty('remove')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(storage.remove); + + expect(type).toEqual('function'); + }); + it('Check returned value for defined', function () { + expect(storage.remove([])).toBeDefined(); + }); + it('Check returned value type', function () { + var type = typeof(storage.remove([])); + + expect(type).toEqual('object'); + }); + it('Check if called with argument "elem" ', function () { + var elem = ['magento'], + value = 'magentoValue'; + + storage.data[elem] = value; + storage.remove(elem); + expect(storage.data[elem]).not.toBeDefined(); + }); + }); + describe('"storage.has" method', function () { + it('Check for defined', function () { + expect(storage.hasOwnProperty('has')).toBeDefined(); + }); + it('Check type', function () { + var type = typeof(storage.has); + + expect(type).toEqual('function'); + }); + it('Check returned value if data has element property', function () { + var elem = 'magento', + value = 'magentoValue'; + + storage.data[elem] = value; + expect(storage.has([elem])).toEqual(true); + }); + it('Check returned value if data has not element property', function () { + expect(storage.has(['value'])).toEqual(false); + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-text.test.js b/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-text.test.js index d593e224d66ca16a3e21c9368f3e94774d89dc35..b5bd195fc62016fd2a31e6e65afa0354c62fb3aa 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-text.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-text.test.js @@ -27,8 +27,10 @@ define([ require([ external.path ], function (data) { + var regExp = /\s+/g; + expect(text._load).toHaveBeenCalled(); - expect(data).toEqual(external.result); + expect(data.replace(regExp,' ')).toEqual(external.result.replace(regExp,' ')); done(); }); diff --git a/dev/tests/static/testsuite/Magento/Test/Js/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Js/LiveCodeTest.php index 0a1aa90f1534770d6b2997583b904029f536c0f6..3e05589de50b79c40c641999b7ba87004a7ad389 100644 --- a/dev/tests/static/testsuite/Magento/Test/Js/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Js/LiveCodeTest.php @@ -64,8 +64,8 @@ class LiveCodeTest extends \PHPUnit_Framework_TestCase } self::$_reportFile = $reportDir . '/js_report.txt'; @unlink(self::$_reportFile); - $whiteList = Files::readLists(__DIR__ . '/_files/whitelist/*.txt'); - $blackList = Files::readLists(__DIR__ . '/_files/blacklist/*.txt'); + $whiteList = Files::readLists(__DIR__ . '/_files/jshint/whitelist/*.txt'); + $blackList = Files::readLists(__DIR__ . '/_files/jshint/blacklist/*.txt'); foreach ($blackList as $listFiles) { self::$_blackListJsFiles = array_merge(self::$_blackListJsFiles, self::_scanJsFile($listFiles)); } diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt b/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt new file mode 100644 index 0000000000000000000000000000000000000000..a9b8c53a6636eb6c32994373ce2b4cd8578e7c20 --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt @@ -0,0 +1,564 @@ +app/code/Magento/AdminNotification/view/adminhtml/requirejs-config.js +app/code/Magento/AdminNotification/view/adminhtml/web/system/notification.js +app/code/Magento/AdminNotification/view/adminhtml/web/toolbar_entry.js +app/code/Magento/Authorizenet/view/adminhtml/web/js/direct-post.js +app/code/Magento/Authorizenet/view/frontend/requirejs-config.js +app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/authorizenet.js +app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/method-renderer/authorizenet-directpost.js +app/code/Magento/Backend/view/adminhtml/web/js/bootstrap/editor.js +app/code/Magento/Braintree/view/adminhtml/requirejs-config.js +app/code/Magento/Braintree/view/adminhtml/web/js/cc-data.js +app/code/Magento/Braintree/view/adminhtml/web/js/cc-form.js +app/code/Magento/Braintree/view/frontend/requirejs-config.js +app/code/Magento/Braintree/view/frontend/web/js/braintree-paypal-shortcut.js +app/code/Magento/Braintree/view/frontend/web/js/cc-data.js +app/code/Magento/Braintree/view/frontend/web/js/cc-edit-form.js +app/code/Magento/Braintree/view/frontend/web/js/cc-form.js +app/code/Magento/Braintree/view/frontend/web/js/view/payment/braintree-methods.js +app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/braintree-paypal.js +app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/cc-form.js +app/code/Magento/Bundle/view/adminhtml/web/js/bundle-product.js +app/code/Magento/Bundle/view/base/web/js/price-bundle.js +app/code/Magento/Bundle/view/frontend/requirejs-config.js +app/code/Magento/Bundle/view/frontend/web/js/float.js +app/code/Magento/Bundle/view/frontend/web/js/product-summary.js +app/code/Magento/Bundle/view/frontend/web/js/slide.js +app/code/Magento/Captcha/view/frontend/requirejs-config.js +app/code/Magento/Captcha/view/frontend/web/captcha.js +app/code/Magento/Captcha/view/frontend/web/js/action/refresh.js +app/code/Magento/Captcha/view/frontend/web/js/model/captcha.js +app/code/Magento/Captcha/view/frontend/web/js/model/captchaList.js +app/code/Magento/Captcha/view/frontend/web/js/view/checkout/defaultCaptcha.js +app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js +app/code/Magento/Captcha/view/frontend/web/onepage.js +app/code/Magento/Catalog/view/adminhtml/requirejs-config.js +app/code/Magento/Catalog/view/adminhtml/web/catalog/base-image-uploader.js +app/code/Magento/Catalog/view/adminhtml/web/catalog/category/edit.js +app/code/Magento/Catalog/view/adminhtml/web/catalog/category/form.js +app/code/Magento/Catalog/view/adminhtml/web/catalog/product-attributes.js +app/code/Magento/Catalog/view/adminhtml/web/catalog/product.js +app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js +app/code/Magento/Catalog/view/adminhtml/web/catalog/type-switcher.js +app/code/Magento/Catalog/view/adminhtml/web/js/category-tree.js +app/code/Magento/Catalog/view/adminhtml/web/js/custom-options.js +app/code/Magento/Catalog/view/adminhtml/web/js/new-category-dialog.js +app/code/Magento/Catalog/view/adminhtml/web/js/product-gallery.js +app/code/Magento/Catalog/view/base/web/js/price-box.js +app/code/Magento/Catalog/view/base/web/js/price-option-date.js +app/code/Magento/Catalog/view/base/web/js/price-option-file.js +app/code/Magento/Catalog/view/base/web/js/price-options.js +app/code/Magento/Catalog/view/base/web/js/price-utils.js +app/code/Magento/Catalog/view/base/web/js/tier-price.js +app/code/Magento/Catalog/view/frontend/requirejs-config.js +app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js +app/code/Magento/Catalog/view/frontend/web/js/compare.js +app/code/Magento/Catalog/view/frontend/web/js/gallery.js +app/code/Magento/Catalog/view/frontend/web/js/list.js +app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js +app/code/Magento/Catalog/view/frontend/web/js/related-products.js +app/code/Magento/Catalog/view/frontend/web/js/upsell-products.js +app/code/Magento/Catalog/view/frontend/web/js/view/compare-products.js +app/code/Magento/Catalog/view/frontend/web/js/view/image.js +app/code/Magento/Catalog/view/frontend/web/js/zoom.js +app/code/Magento/Catalog/view/frontend/web/product/view/validation.js +app/code/Magento/CatalogSearch/view/frontend/requirejs-config.js +app/code/Magento/Checkout/view/frontend/requirejs-config.js +app/code/Magento/Checkout/view/frontend/web/js/action/create-billing-address.js +app/code/Magento/Checkout/view/frontend/web/js/action/create-shipping-address.js +app/code/Magento/Checkout/view/frontend/web/js/action/get-totals.js +app/code/Magento/Checkout/view/frontend/web/js/action/place-order.js +app/code/Magento/Checkout/view/frontend/web/js/action/select-billing-address.js +app/code/Magento/Checkout/view/frontend/web/js/action/select-payment-method.js +app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-address.js +app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-method.js +app/code/Magento/Checkout/view/frontend/web/js/action/set-payment-information.js +app/code/Magento/Checkout/view/frontend/web/js/action/set-shipping-information.js +app/code/Magento/Checkout/view/frontend/web/js/discount-codes.js +app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js +app/code/Magento/Checkout/view/frontend/web/js/model/error-processor.js +app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js +app/code/Magento/Checkout/view/frontend/web/js/model/payment-service.js +app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-converter.js +app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-list.js +app/code/Magento/Checkout/view/frontend/web/js/model/payment/renderer-list.js +app/code/Magento/Checkout/view/frontend/web/js/model/postcode-validator.js +app/code/Magento/Checkout/view/frontend/web/js/model/quote.js +app/code/Magento/Checkout/view/frontend/web/js/model/resource-url-manager.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-address/form-popup-state.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-processor/customer-address.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-processor/new-address.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-registry.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-service.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validation-rules.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validator.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/default.js +app/code/Magento/Checkout/view/frontend/web/js/model/shipping-service.js +app/code/Magento/Checkout/view/frontend/web/js/model/sidebar.js +app/code/Magento/Checkout/view/frontend/web/js/model/step-loader.js +app/code/Magento/Checkout/view/frontend/web/js/model/step-navigator.js +app/code/Magento/Checkout/view/frontend/web/js/model/totals.js +app/code/Magento/Checkout/view/frontend/web/js/model/url-builder.js +app/code/Magento/Checkout/view/frontend/web/js/opc-billing-info.js +app/code/Magento/Checkout/view/frontend/web/js/opc-checkout-method.js +app/code/Magento/Checkout/view/frontend/web/js/opc-order-review.js +app/code/Magento/Checkout/view/frontend/web/js/opc-payment-info.js +app/code/Magento/Checkout/view/frontend/web/js/opc-shipping-info.js +app/code/Magento/Checkout/view/frontend/web/js/opc-shipping-method.js +app/code/Magento/Checkout/view/frontend/web/js/opcheckout.js +app/code/Magento/Checkout/view/frontend/web/js/payment-authentication.js +app/code/Magento/Checkout/view/frontend/web/js/payment.js +app/code/Magento/Checkout/view/frontend/web/js/proceed-to-checkout.js +app/code/Magento/Checkout/view/frontend/web/js/region-updater.js +app/code/Magento/Checkout/view/frontend/web/js/shopping-cart.js +app/code/Magento/Checkout/view/frontend/web/js/sidebar.js +app/code/Magento/Checkout/view/frontend/web/js/view/authentication.js +app/code/Magento/Checkout/view/frontend/web/js/view/beforePlaceOrder.js +app/code/Magento/Checkout/view/frontend/web/js/view/billing-address.js +app/code/Magento/Checkout/view/frontend/web/js/view/estimation.js +app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js +app/code/Magento/Checkout/view/frontend/web/js/view/payment.js +app/code/Magento/Checkout/view/frontend/web/js/view/payment/default.js +app/code/Magento/Checkout/view/frontend/web/js/view/payment/list.js +app/code/Magento/Checkout/view/frontend/web/js/view/progress-bar.js +app/code/Magento/Checkout/view/frontend/web/js/view/registration.js +app/code/Magento/Checkout/view/frontend/web/js/view/review/actions.js +app/code/Magento/Checkout/view/frontend/web/js/view/review/actions/default.js +app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address/address-renderer/default.js +app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address/list.js +app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information.js +app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information/address-renderer/default.js +app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information/list.js +app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js +app/code/Magento/Checkout/view/frontend/web/js/view/sidebar.js +app/code/Magento/Checkout/view/frontend/web/js/view/summary.js +app/code/Magento/Checkout/view/frontend/web/js/view/summary/abstract-total.js +app/code/Magento/Checkout/view/frontend/web/js/view/summary/cart-items.js +app/code/Magento/Checkout/view/frontend/web/js/view/summary/grand-total.js +app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details.js +app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details/subtotal.js +app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details/thumbnail.js +app/code/Magento/Checkout/view/frontend/web/js/view/summary/shipping.js +app/code/Magento/Checkout/view/frontend/web/js/view/summary/subtotal.js +app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements-link.js +app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements-modal.js +app/code/Magento/Cms/view/adminhtml/requirejs-config.js +app/code/Magento/Cms/view/adminhtml/web/js/folder-tree.js +app/code/Magento/ConfigurableProduct/view/adminhtml/requirejs-config.js +app/code/Magento/ConfigurableProduct/view/adminhtml/web/catalog/product/attribute.js +app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/configurable.js +app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/attributes_values.js +app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js +app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/select_attributes.js +app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js +app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js +app/code/Magento/ConfigurableProduct/view/frontend/requirejs-config.js +app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js +app/code/Magento/Cookie/View/adminhtml/requirejs-config.js +app/code/Magento/Cookie/View/frontend/requirejs-config.js +app/code/Magento/Cookie/View/frontend/web/js/notices.js +app/code/Magento/Cookie/View/frontend/web/js/require-cookie.js +app/code/Magento/Customer/view/adminhtml/requirejs-config.js +app/code/Magento/Customer/view/adminhtml/web/edit/tab/js/addresses.js +app/code/Magento/Customer/view/frontend/requirejs-config.js +app/code/Magento/Customer/view/frontend/web/address.js +app/code/Magento/Customer/view/frontend/web/js/action/check-email-availability.js +app/code/Magento/Customer/view/frontend/web/js/action/login.js +app/code/Magento/Customer/view/frontend/web/js/checkout-balance.js +app/code/Magento/Customer/view/frontend/web/js/customer-data.js +app/code/Magento/Customer/view/frontend/web/js/model/address-list.js +app/code/Magento/Customer/view/frontend/web/js/model/authentication-popup.js +app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js +app/code/Magento/Customer/view/frontend/web/js/model/customer.js +app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js +app/code/Magento/Customer/view/frontend/web/js/section-config.js +app/code/Magento/Customer/view/frontend/web/js/view/authentication-popup.js +app/code/Magento/Customer/view/frontend/web/js/view/customer-email.js +app/code/Magento/Customer/view/frontend/web/js/view/customer.js +app/code/Magento/Customer/view/frontend/web/set-password.js +app/code/Magento/DesignEditor/view/adminhtml/requirejs-config.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/bootstrap/edit.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/bootstrap/launch.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/custom-css.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/dialog.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/image-sizing.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/infinitescroll.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/message.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/quick-style-element.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/quick-style-uploader.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/theme-assign.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/theme-delete.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/theme-edit.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/theme-revert.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/theme-save.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/theme-selector.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/tools-files.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/tools-panel.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/tools.js +app/code/Magento/DesignEditor/view/adminhtml/web/js/vde-frame.js +app/code/Magento/Dhl/view/frontend/web/js/model/shipping-rates-validation-rules.js +app/code/Magento/Dhl/view/frontend/web/js/model/shipping-rates-validator.js +app/code/Magento/Dhl/view/frontend/web/js/view/shipping-rates-validation.js +app/code/Magento/Downloadable/view/frontend/requirejs-config.js +app/code/Magento/Downloadable/view/frontend/web/downloadable.js +app/code/Magento/Fedex/view/frontend/web/js/model/shipping-rates-validation-rules.js +app/code/Magento/Fedex/view/frontend/web/js/model/shipping-rates-validator.js +app/code/Magento/Fedex/view/frontend/web/js/view/shipping-rates-validation.js +app/code/Magento/GiftMessage/view/frontend/requirejs-config.js +app/code/Magento/GiftMessage/view/frontend/web/extra-options.js +app/code/Magento/GiftMessage/view/frontend/web/gift-options.js +app/code/Magento/GiftMessage/view/frontend/web/js/action/gift-options.js +app/code/Magento/GiftMessage/view/frontend/web/js/model/gift-message.js +app/code/Magento/GiftMessage/view/frontend/web/js/model/gift-options.js +app/code/Magento/GiftMessage/view/frontend/web/js/model/url-builder.js +app/code/Magento/GiftMessage/view/frontend/web/js/view/gift-message.js +app/code/Magento/GroupedProduct/view/adminhtml/requirejs-config.js +app/code/Magento/GroupedProduct/view/adminhtml/web/js/grouped-product.js +app/code/Magento/Integration/view/adminhtml/requirejs-config.js +app/code/Magento/Integration/view/adminhtml/web/js/integration.js +app/code/Magento/Msrp/view/base/web/js/msrp.js +app/code/Magento/Msrp/view/frontend/requirejs-config.js +app/code/Magento/Multishipping/view/frontend/requirejs-config.js +app/code/Magento/Multishipping/view/frontend/web/js/multi-shipping.js +app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/banktransfer-method.js +app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/cashondelivery-method.js +app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/checkmo-method.js +app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/purchaseorder-method.js +app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/offline-payments.js +app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/flatrate.js +app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/freeshipping.js +app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/tablerate.js +app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/flatrate.js +app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/freeshipping.js +app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/tablerate.js +app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/flatrate.js +app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/freeshipping.js +app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/tablerate.js +app/code/Magento/PageCache/view/frontend/requirejs-config.js +app/code/Magento/PageCache/view/frontend/web/js/page-cache.js +app/code/Magento/Payment/view/adminhtml/web/transparent.js +app/code/Magento/Payment/view/frontend/requirejs-config.js +app/code/Magento/Payment/view/frontend/web/cc-type.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-data.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js +app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js +app/code/Magento/Payment/view/frontend/web/js/view/payment/cc-form.js +app/code/Magento/Payment/view/frontend/web/js/view/payment/iframe.js +app/code/Magento/Payment/view/frontend/web/js/view/payment/method-renderer/free-method.js +app/code/Magento/Payment/view/frontend/web/js/view/payment/payments.js +app/code/Magento/Payment/view/frontend/web/transparent.js +app/code/Magento/Paypal/view/adminhtml/web/js/predicate/confirm.js +app/code/Magento/Paypal/view/adminhtml/web/js/rule.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/conflict.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/disable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/bml/disable-conditional-express.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/bml/disable-conditional.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/bml/disable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/bml/enable-conditional.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/bml/enable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/bml/lock-conditional.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/express/disable-conditional.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/express/disable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/express/enable-conditional.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/express/enable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/payflow/express/lock-conditional.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/paypal/bml/disable-conditional.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/paypal/bml/disable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/paypal/bml/enable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/paypal/express/disable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/paypal/express/lock-configuration-conditional.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/paypal/express/lock-configuration.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/paypal/express/mark-disable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/paypal/express/unlock-configuration.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/simple/disable.js +app/code/Magento/Paypal/view/adminhtml/web/js/rules/simple/mark-enable.js +app/code/Magento/Paypal/view/adminhtml/web/js/solution.js +app/code/Magento/Paypal/view/adminhtml/web/js/solutions.js +app/code/Magento/Paypal/view/base/requirejs-config.js +app/code/Magento/Paypal/view/frontend/requirejs-config.js +app/code/Magento/Paypal/view/frontend/web/js/action/set-payment-method.js +app/code/Magento/Paypal/view/frontend/web/js/model/iframe-redirect.js +app/code/Magento/Paypal/view/frontend/web/js/model/iframe.js +app/code/Magento/Paypal/view/frontend/web/js/opcheckout.js +app/code/Magento/Paypal/view/frontend/web/js/paypal-checkout.js +app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/iframe-methods.js +app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/payflow-express-bml.js +app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/payflow-express.js +app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/payflowpro-method.js +app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/paypal-billing-agreement.js +app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/paypal-express-abstract.js +app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/paypal-express-bml.js +app/code/Magento/Paypal/view/frontend/web/js/view/payment/method-renderer/paypal-express.js +app/code/Magento/Paypal/view/frontend/web/js/view/payment/paypal-payments.js +app/code/Magento/Paypal/view/frontend/web/js/view/review/actions/iframe.js +app/code/Magento/Paypal/view/frontend/web/order-review.js +app/code/Magento/Persistent/view/frontend/web/js/view/remember-me.js +app/code/Magento/Reports/view/frontend/requirejs-config.js +app/code/Magento/Reports/view/frontend/web/js/recently-viewed.js +app/code/Magento/Review/view/adminhtml/web/js/rating.js +app/code/Magento/Review/view/frontend/web/js/view/review.js +app/code/Magento/Rule/view/adminhtml/web/rules.js +app/code/Magento/Sales/view/adminhtml/requirejs-config.js +app/code/Magento/Sales/view/adminhtml/web/js/bootstrap/order-create-index.js +app/code/Magento/Sales/view/adminhtml/web/order/create/form.js +app/code/Magento/Sales/view/adminhtml/web/order/create/giftmessage.js +app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js +app/code/Magento/Sales/view/adminhtml/web/order/edit/message.js +app/code/Magento/Sales/view/adminhtml/web/order/giftoptions_tooltip.js +app/code/Magento/Sales/view/frontend/requirejs-config.js +app/code/Magento/Sales/view/frontend/web/gift-message.js +app/code/Magento/Sales/view/frontend/web/js/view/last-ordered-items.js +app/code/Magento/Sales/view/frontend/web/orders-returns.js +app/code/Magento/SalesRule/view/frontend/web/js/action/cancel-coupon.js +app/code/Magento/SalesRule/view/frontend/web/js/action/set-coupon-code.js +app/code/Magento/SalesRule/view/frontend/web/js/view/payment/discount.js +app/code/Magento/SalesRule/view/frontend/web/js/view/summary/discount.js +app/code/Magento/Search/view/frontend/requirejs-config.js +app/code/Magento/Search/view/frontend/web/form-mini.js +app/code/Magento/Shipping/view/adminhtml/web/order/packaging.js +app/code/Magento/Shipping/view/frontend/web/js/model/config.js +app/code/Magento/Shipping/view/frontend/web/js/view/checkout/shipping/shipping-policy.js +app/code/Magento/Store/view/base/requirejs-config.js +app/code/Magento/Store/view/base/web/js/listing/filter/store.js +app/code/Magento/Tax/view/adminhtml/web/js/bootstrap.js +app/code/Magento/Tax/view/frontend/web/js/view/checkout/minicart/subtotal/totals.js +app/code/Magento/Tax/view/frontend/web/js/view/checkout/shipping_method/price.js +app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/grand-total.js +app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/item/details/subtotal.js +app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/shipping.js +app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/subtotal.js +app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/tax.js +app/code/Magento/Theme/view/adminhtml/requirejs-config.js +app/code/Magento/Theme/view/adminhtml/web/js/bootstrap.js +app/code/Magento/Theme/view/adminhtml/web/js/custom-js-list.js +app/code/Magento/Theme/view/adminhtml/web/js/form.js +app/code/Magento/Theme/view/adminhtml/web/js/sortable.js +app/code/Magento/Theme/view/base/requirejs-config.js +app/code/Magento/Theme/view/frontend/requirejs-config.js +app/code/Magento/Theme/view/frontend/web/js/row-builder.js +app/code/Magento/Theme/view/frontend/web/js/truncate.js +app/code/Magento/Theme/view/frontend/web/js/view/messages.js +app/code/Magento/Theme/view/frontend/web/menu.js +app/code/Magento/Ui/view/base/requirejs-config.js +app/code/Magento/Ui/view/base/web/js/block-loader.js +app/code/Magento/Ui/view/base/web/js/core/app.js +app/code/Magento/Ui/view/base/web/js/core/renderer/layout.js +app/code/Magento/Ui/view/base/web/js/core/renderer/types.js +app/code/Magento/Ui/view/base/web/js/form/adapter.js +app/code/Magento/Ui/view/base/web/js/form/client.js +app/code/Magento/Ui/view/base/web/js/form/components/area.js +app/code/Magento/Ui/view/base/web/js/form/components/collection.js +app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js +app/code/Magento/Ui/view/base/web/js/form/components/fieldset.js +app/code/Magento/Ui/view/base/web/js/form/components/group.js +app/code/Magento/Ui/view/base/web/js/form/components/html.js +app/code/Magento/Ui/view/base/web/js/form/components/tab_group.js +app/code/Magento/Ui/view/base/web/js/form/components/tab.js +app/code/Magento/Ui/view/base/web/js/form/element/abstract.js +app/code/Magento/Ui/view/base/web/js/form/element/boolean.js +app/code/Magento/Ui/view/base/web/js/form/element/date.js +app/code/Magento/Ui/view/base/web/js/form/element/multiselect.js +app/code/Magento/Ui/view/base/web/js/form/element/post-code.js +app/code/Magento/Ui/view/base/web/js/form/element/region.js +app/code/Magento/Ui/view/base/web/js/form/element/select.js +app/code/Magento/Ui/view/base/web/js/form/element/textarea.js +app/code/Magento/Ui/view/base/web/js/form/form.js +app/code/Magento/Ui/view/base/web/js/form/provider.js +app/code/Magento/Ui/view/base/web/js/grid/columns/actions.js +app/code/Magento/Ui/view/base/web/js/grid/columns/column.js +app/code/Magento/Ui/view/base/web/js/grid/columns/date.js +app/code/Magento/Ui/view/base/web/js/grid/columns/multiselect.js +app/code/Magento/Ui/view/base/web/js/grid/columns/select.js +app/code/Magento/Ui/view/base/web/js/grid/columns/thumbnail.js +app/code/Magento/Ui/view/base/web/js/grid/controls/bookmarks/bookmarks.js +app/code/Magento/Ui/view/base/web/js/grid/controls/bookmarks/storage.js +app/code/Magento/Ui/view/base/web/js/grid/controls/bookmarks/view.js +app/code/Magento/Ui/view/base/web/js/grid/controls/columns.js +app/code/Magento/Ui/view/base/web/js/grid/dnd.js +app/code/Magento/Ui/view/base/web/js/grid/export.js +app/code/Magento/Ui/view/base/web/js/grid/filters/chips.js +app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js +app/code/Magento/Ui/view/base/web/js/grid/filters/group.js +app/code/Magento/Ui/view/base/web/js/grid/listing.js +app/code/Magento/Ui/view/base/web/js/grid/massactions.js +app/code/Magento/Ui/view/base/web/js/grid/paging.js +app/code/Magento/Ui/view/base/web/js/grid/provider.js +app/code/Magento/Ui/view/base/web/js/grid/search/search.js +app/code/Magento/Ui/view/base/web/js/lib/class.js +app/code/Magento/Ui/view/base/web/js/lib/collapsible.js +app/code/Magento/Ui/view/base/web/js/lib/component/core.js +app/code/Magento/Ui/view/base/web/js/lib/component/links.js +app/code/Magento/Ui/view/base/web/js/lib/component/main.js +app/code/Magento/Ui/view/base/web/js/lib/component/manip.js +app/code/Magento/Ui/view/base/web/js/lib/component/provider.js +app/code/Magento/Ui/view/base/web/js/lib/component/traversal.js +app/code/Magento/Ui/view/base/web/js/lib/events.js +app/code/Magento/Ui/view/base/web/js/lib/i18n.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/after-render.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/class.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/datepicker.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/fadeVisible.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/keyboard.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/mage-init.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/optgroup.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/outer_click.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/scope.js +app/code/Magento/Ui/view/base/web/js/lib/ko/bind/stop_propagation.js +app/code/Magento/Ui/view/base/web/js/lib/ko/extender/observable_array.js +app/code/Magento/Ui/view/base/web/js/lib/ko/initialize.js +app/code/Magento/Ui/view/base/web/js/lib/ko/template/engine.js +app/code/Magento/Ui/view/base/web/js/lib/ko/template/observable_source.js +app/code/Magento/Ui/view/base/web/js/lib/loader.js +app/code/Magento/Ui/view/base/web/js/lib/registry/events.js +app/code/Magento/Ui/view/base/web/js/lib/registry/registry.js +app/code/Magento/Ui/view/base/web/js/lib/registry/storage.js +app/code/Magento/Ui/view/base/web/js/lib/renderer/renderer.js +app/code/Magento/Ui/view/base/web/js/lib/spinner.js +app/code/Magento/Ui/view/base/web/js/lib/step-registry.js +app/code/Magento/Ui/view/base/web/js/lib/step-wizard.js +app/code/Magento/Ui/view/base/web/js/lib/storage.js +app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js +app/code/Magento/Ui/view/base/web/js/lib/validation/utils.js +app/code/Magento/Ui/view/base/web/js/lib/validation/validator.js +app/code/Magento/Ui/view/base/web/js/modal/alert.js +app/code/Magento/Ui/view/base/web/js/modal/confirm.js +app/code/Magento/Ui/view/base/web/js/modal/modal.js +app/code/Magento/Ui/view/base/web/js/modal/modalToggle.js +app/code/Magento/Ui/view/frontend/web/js/model/messageList.js +app/code/Magento/Ui/view/frontend/web/js/view/messages.js +app/code/Magento/Ups/view/frontend/web/js/model/shipping-rates-validation-rules.js +app/code/Magento/Ups/view/frontend/web/js/model/shipping-rates-validator.js +app/code/Magento/Ups/view/frontend/web/js/view/shipping-rates-validation.js +app/code/Magento/User/view/adminhtml/requirejs-config.js +app/code/Magento/User/view/adminhtml/web/app-config.js +app/code/Magento/User/view/adminhtml/web/js/roles-tree.js +app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validation-rules.js +app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validator.js +app/code/Magento/Usps/view/frontend/web/js/view/shipping-rates-validation.js +app/code/Magento/Variable/view/adminhtml/web/variables.js +app/code/Magento/Weee/view/adminhtml/requirejs-config.js +app/code/Magento/Weee/view/adminhtml/web/js/fpt-attribute.js +app/code/Magento/Weee/view/frontend/requirejs-config.js +app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/row_excl_tax.js +app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/row_incl_tax.js +app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/weee.js +app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/weee.js +app/code/Magento/Weee/view/frontend/web/tax-toggle.js +app/code/Magento/Wishlist/view/frontend/requirejs-config.js +app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js +app/code/Magento/Wishlist/view/frontend/web/js/search.js +app/code/Magento/Wishlist/view/frontend/web/js/view/wishlist.js +app/code/Magento/Wishlist/view/frontend/web/wishlist.js +app/design/adminhtml/Magento/backend/web/js/theme.js +app/design/frontend/Magento/blank/web/js/navigation-menu.js +app/design/frontend/Magento/blank/web/js/responsive.js +app/design/frontend/Magento/blank/web/js/theme.js +dev/tests/js/jasmine/tests/app/code/Magento/Msrp/frontend/js/msrp.test.js +dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/page-cache.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/actions.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/multiselect.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/storage.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/columns.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/group.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/events.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/datepicker.test.js +dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/modal.test.js +dev/tests/js/jasmine/tests/lib/mage/apply.test.js +dev/tests/js/jasmine/tests/lib/mage/requirejs/static-jsbuild.test.js +dev/tests/js/jasmine/tests/lib/mage/requirejs/static-text.test.js +dev/tests/js/jasmine/tests/lib/mage/requirejs/statistician.test.js +dev/tests/js/jasmine/tests/lib/mage/scripts.test.js +dev/tests/js/jasmine/tests/lib/mage/template.test.js +lib/web/mage/accordion.js +lib/web/mage/adminhtml/accordion.js +lib/web/mage/adminhtml/backup.js +lib/web/mage/adminhtml/browser.js +lib/web/mage/adminhtml/events.js +lib/web/mage/adminhtml/form.js +lib/web/mage/adminhtml/globals.js +lib/web/mage/adminhtml/grid.js +lib/web/mage/adminhtml/tools.js +lib/web/mage/adminhtml/varienLoader.js +lib/web/mage/adminhtml/wysiwyg/tiny_mce/plugins/magentovariable/editor_plugin.js +lib/web/mage/adminhtml/wysiwyg/tiny_mce/plugins/magentowidget/editor_plugin.js +lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js +lib/web/mage/adminhtml/wysiwyg/widget.js +lib/web/mage/app/config.js +lib/web/mage/apply/main.js +lib/web/mage/apply/scripts.js +lib/web/mage/backend/action-link.js +lib/web/mage/backend/bootstrap.js +lib/web/mage/backend/button.js +lib/web/mage/backend/editablemultiselect.js +lib/web/mage/backend/floating-header.js +lib/web/mage/backend/form.js +lib/web/mage/backend/menu.js +lib/web/mage/backend/notification.js +lib/web/mage/backend/suggest.js +lib/web/mage/backend/tabs.js +lib/web/mage/backend/tree-suggest.js +lib/web/mage/backend/validation.js +lib/web/mage/bootstrap.js +lib/web/mage/calendar.js +lib/web/mage/captcha.js +lib/web/mage/collapsible.js +lib/web/mage/common.js +lib/web/mage/cookies.js +lib/web/mage/dataPost.js +lib/web/mage/decorate.js +lib/web/mage/deletable-item.js +lib/web/mage/dialog.js +lib/web/mage/dropdown_old.js +lib/web/mage/dropdown.js +lib/web/mage/dropdowns.js +lib/web/mage/edit-trigger.js +lib/web/mage/fieldset-controls.js +lib/web/mage/gallery-fullscreen.js +lib/web/mage/gallery.js +lib/web/mage/ie-class-fixer.js +lib/web/mage/item-table.js +lib/web/mage/layout.js +lib/web/mage/list.js +lib/web/mage/loader_old.js +lib/web/mage/loader.js +lib/web/mage/mage.js +lib/web/mage/menu.js +lib/web/mage/popup-window.js +lib/web/mage/redirect-url.js +lib/web/mage/requirejs/plugin/id-normalizer.js +lib/web/mage/requirejs/resolver.js +lib/web/mage/requirejs/static.js +lib/web/mage/smart-keyboard-handler.js +lib/web/mage/sticky.js +lib/web/mage/storage.js +lib/web/mage/tabs.js +lib/web/mage/template.js +lib/web/mage/terms.js +lib/web/mage/toggle.js +lib/web/mage/tooltip.js +lib/web/mage/translate-inline-vde.js +lib/web/mage/translate-inline.js +lib/web/mage/translate.js +lib/web/mage/url.js +lib/web/mage/utils/arrays.js +lib/web/mage/utils/compare.js +lib/web/mage/utils/main.js +lib/web/mage/utils/misc.js +lib/web/mage/utils/objects.js +lib/web/mage/utils/strings.js +lib/web/mage/utils/template.js +lib/web/mage/validation.js +lib/web/mage/validation/validation.js +lib/web/mage/view/composite.js +lib/web/mage/webapi.js +lib/web/mage/zoom.js diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc b/dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc new file mode 100644 index 0000000000000000000000000000000000000000..611105806dd4af5c87235ce4261821ffbecf01d8 --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc @@ -0,0 +1,6 @@ +{ + "extends": [ + "./.eslintrc-reset", + "./.eslintrc-magento" + ] +} \ No newline at end of file diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc-magento b/dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc-magento new file mode 100644 index 0000000000000000000000000000000000000000..3e2ce35ce29a66bcedd0b94194b47096eb395dba --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc-magento @@ -0,0 +1,64 @@ +{ + "env": { + "browser": true, + "node": true, + "jasmine": true, + "amd": true + }, + "rules": { + "lines-around-comment": [2, {"beforeBlockComment": true}], + "eqeqeq": [2, "smart"], + "no-extend-native": 2, + "no-native-reassign": 2, + "no-use-before-define": 2, + "no-undef": 2, + "no-undef-init": 2, + "no-caller": 2, + "no-unused-vars": [2, {"vars": "all", "args": "after-used"}], + "strict": 2, + "max-depth": [2, 2], + "max-len": [2, 120, 4], + "no-cond-assign": 2, + "no-constant-condition": 2, + "no-ex-assign": 2, + "no-extra-boolean-cast": 2, + "no-extra-parens": 2, + "no-extra-semi": 2, + "no-func-assign": 2, + "no-inner-declarations": 2, + "no-invalid-regexp": 2, + "no-negated-in-lhs": 2, + "no-regex-spaces": 2, + "no-unreachable": 2, + "use-isnan": 2, + "valid-typeof": 2, + "guard-for-in": 2, + "no-else-return": 2, + "no-extra-bind": 2, + "no-fallthrough": 2, + "no-floating-decimal": 2, + "no-implied-eval": 2, + "no-lone-blocks": 2, + "no-loop-func": 2, + "no-multi-str": 2, + "no-proto": 2, + "no-redeclare": 2, + "no-return-assign": 2, + "no-self-compare": 2, + "no-with": 2, + "radix": 2, + "vars-on-top": 2, + "no-catch-shadow": 2, + "no-shadow": 2, + "max-nested-callbacks": [2, 3], + "no-array-constructor": 2, + "no-lonely-if": 2, + "no-new-object": 2, + "semi-spacing": 2, + "no-extra-parens": 2, + "operator-assignment": [2, "always"], + "semi": [2, "always"], + "strict": 2, + "consistent-return": 2 + } +} diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc-reset b/dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc-reset new file mode 100644 index 0000000000000000000000000000000000000000..ceb9a8c421c937553b7720f1c911c547b74af2f2 --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc-reset @@ -0,0 +1,217 @@ +{ + // http://eslint.org/docs/rules/ + + "ecmaFeatures": { + "binaryLiterals": false, // enable binary literals + "blockBindings": false, // enable let and const (aka block bindings) + "defaultParams": false, // enable default function parameters + "forOf": false, // enable for-of loops + "generators": false, // enable generators + "objectLiteralComputedProperties": false, // enable computed object literal property names + "objectLiteralDuplicateProperties": false, // enable duplicate object literal properties in strict mode + "objectLiteralShorthandMethods": false, // enable object literal shorthand methods + "objectLiteralShorthandProperties": false, // enable object literal shorthand properties + "octalLiterals": false, // enable octal literals + "regexUFlag": false, // enable the regular expression u flag + "regexYFlag": false, // enable the regular expression y flag + "templateStrings": false, // enable template strings + "unicodeCodePointEscapes": false, // enable code point escapes + "jsx": false // enable JSX + }, + + "env": { + "browser": false, // browser global variables. + "node": false, // Node.js global variables and Node.js-specific rules. + "amd": false, // defines require() and define() as global variables as per the amd spec. + "mocha": false, // adds all of the Mocha testing global variables. + "jasmine": false, // adds all of the Jasmine testing global variables for version 1.3 and 2.0. + "phantomjs": false, // phantomjs global variables. + "jquery": false, // jquery global variables. + "prototypejs": false, // prototypejs global variables. + "shelljs": false, // shelljs global variables. + }, + + "globals": { + // e.g. "angular": true + }, + + "plugins": [ + // e.g. "react" (must run `npm install eslint-plugin-react` first) + ], + + "rules": { + ////////// Possible Errors ////////// + + "no-comma-dangle": 0, // disallow trailing commas in object literals + "no-cond-assign": 0, // disallow assignment in conditional expressions + "no-console": 0, // disallow use of console (off by default in the node environment) + "no-constant-condition": 0, // disallow use of constant expressions in conditions + "no-control-regex": 0, // disallow control characters in regular expressions + "no-debugger": 0, // disallow use of debugger + "no-dupe-keys": 0, // disallow duplicate keys when creating object literals + "no-empty": 0, // disallow empty statements + "no-empty-class": 0, // disallow the use of empty character classes in regular expressions + "no-ex-assign": 0, // disallow assigning to the exception in a catch block + "no-extra-boolean-cast": 0, // disallow double-negation boolean casts in a boolean context + "no-extra-parens": 0, // disallow unnecessary parentheses (off by default) + "no-extra-semi": 0, // disallow unnecessary semicolons + "no-func-assign": 0, // disallow overwriting functions written as function declarations + "no-inner-declarations": 0, // disallow function or variable declarations in nested blocks + "no-invalid-regexp": 0, // disallow invalid regular expression strings in the RegExp constructor + "no-irregular-whitespace": 0, // disallow irregular whitespace outside of strings and comments + "no-negated-in-lhs": 0, // disallow negation of the left operand of an in expression + "no-obj-calls": 0, // disallow the use of object properties of the global object (Math and JSON) as functions + "no-regex-spaces": 0, // disallow multiple spaces in a regular expression literal + "no-reserved-keys": 0, // disallow reserved words being used as object literal keys (off by default) + "no-sparse-arrays": 0, // disallow sparse arrays + "no-unreachable": 0, // disallow unreachable statements after a return, throw, continue, or break statement + "use-isnan": 0, // disallow comparisons with the value NaN + "valid-jsdoc": 0, // Ensure JSDoc comments are valid (off by default) + "valid-typeof": 0, // Ensure that the results of typeof are compared against a valid string + + + ////////// Best Practices ////////// + + "block-scoped-var": 0, // treat var statements as if they were block scoped (off by default) + "complexity": 0, // specify the maximum cyclomatic complexity allowed in a program (off by default) + "consistent-return": 0, // require return statements to either always or never specify values + "curly": 0, // specify curly brace conventions for all control statements + "default-case": 0, // require default case in switch statements (off by default) + "dot-notation": 0, // encourages use of dot notation whenever possible + "eqeqeq": 0, // require the use of === and !== + "guard-for-in": 0, // make sure for-in loops have an if statement (off by default) + "no-alert": 0, // disallow the use of alert, confirm, and prompt + "no-caller": 0, // disallow use of arguments.caller or arguments.callee + "no-div-regex": 0, // disallow division operators explicitly at beginning of regular expression (off by default) + "no-else-return": 0, // disallow else after a return in an if (off by default) + "no-empty-label": 0, // disallow use of labels for anything other then loops and switches + "no-eq-null": 0, // disallow comparisons to null without a type-checking operator (off by default) + "no-eval": 0, // disallow use of eval() + "no-extend-native": 0, // disallow adding to native types + "no-extra-bind": 0, // disallow unnecessary function binding + "no-fallthrough": 0, // disallow fallthrough of case statements + "no-floating-decimal": 0, // disallow the use of leading or trailing decimal points in numeric literals (off by default) + "no-implied-eval": 0, // disallow use of eval()-like methods + "no-iterator": 0, // disallow usage of __iterator__ property + "no-labels": 0, // disallow use of labeled statements + "no-lone-blocks": 0, // disallow unnecessary nested blocks + "no-loop-func": 0, // disallow creation of functions within loops + "no-multi-spaces": 0, // disallow use of multiple spaces + "no-multi-str": 0, // disallow use of multiline strings + "no-native-reassign": 0, // disallow reassignments of native objects + "no-new": 0, // disallow use of new operator when not part of the assignment or comparison + "no-new-func": 0, // disallow use of new operator for Function object + "no-new-wrappers": 0, // disallows creating new instances of String, Number, and Boolean + "no-octal": 0, // disallow use of octal literals + "no-octal-escape": 0, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251"; + "no-process-env": 0, // disallow use of process.env (off by default) + "no-proto": 0, // disallow usage of __proto__ property + "no-redeclare": 0, // disallow declaring the same variable more then once + "no-return-assign": 0, // disallow use of assignment in return statement + "no-script-url": 0, // disallow use of javascript: urls. + "no-self-compare": 0, // disallow comparisons where both sides are exactly the same (off by default) + "no-sequences": 0, // disallow use of comma operator + "no-unused-expressions": 0, // disallow usage of expressions in statement position + "no-void": 0, // disallow use of void operator (off by default) + "no-warning-comments": 0, // disallow usage of configurable warning terms in comments, e.g. TODO or FIXME (off by default) + "no-with": 0, // disallow use of the with statement + "radix": 0, // require use of the second argument for parseInt() (off by default) + "vars-on-top": 0, // requires to declare all vars on top of their containing scope (off by default) + "wrap-iife": 0, // require immediate function invocation to be wrapped in parentheses (off by default) + "yoda": 0, // require or disallow Yoda conditions + + + ////////// Strict Mode ////////// + + "global-strict": 0, // (deprecated) require or disallow the "use strict" pragma in the global scope (off by default in the node environment) + "no-extra-strict": 0, // (deprecated) disallow unnecessary use of "use strict"; when already in strict mode + "strict": 0, // controls location of Use Strict Directives + + + ////////// Variables ////////// + + "no-catch-shadow": 0, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment) + "no-delete-var": 0, // disallow deletion of variables + "no-label-var": 0, // disallow labels that share a name with a variable + "no-shadow": 0, // disallow declaration of variables already declared in the outer scope + "no-shadow-restricted-names": 0, // disallow shadowing of names such as arguments + "no-undef": 0, // disallow use of undeclared variables unless mentioned in a /*global */ block + "no-undef-init": 0, // disallow use of undefined when initializing variables + "no-undefined": 0, // disallow use of undefined variable (off by default) + "no-unused-vars": 0, // disallow declaration of variables that are not used in the code + "no-use-before-define": 0, // disallow use of variables before they are defined + + + ////////// Node.js ////////// + + "handle-callback-err": 0, // enforces error handling in callbacks (off by default) (on by default in the node environment) + "no-mixed-requires": 0, // disallow mixing regular variable and require declarations (off by default) (on by default in the node environment) + "no-new-require": 0, // disallow use of new operator with the require function (off by default) (on by default in the node environment) + "no-path-concat": 0, // disallow string concatenation with __dirname and __filename (off by default) (on by default in the node environment) + "no-process-exit": 0, // disallow process.exit() (on by default in the node environment) + "no-restricted-modules": 0, // restrict usage of specified node modules (off by default) + "no-sync": 0, // disallow use of synchronous methods (off by default) + + + ////////// Stylistic Issues ////////// + + "brace-style": 0, // enforce one true brace style (off by default) + "camelcase": 0, // require camel case names + "comma-spacing": 0, // enforce spacing before and after comma + "comma-style": 0, // enforce one true comma style (off by default) + "consistent-this": 0, // enforces consistent naming when capturing the current execution context (off by default) + "eol-last": 0, // enforce newline at the end of file, with no multiple empty lines + "func-names": 0, // require function expressions to have a name (off by default) + "func-style": 0, // enforces use of function declarations or expressions (off by default) + "key-spacing": 0, // enforces spacing between keys and values in object literal properties + "max-nested-callbacks": 0, // specify the maximum depth callbacks can be nested (off by default) + "new-cap": 0, // require a capital letter for constructors + "new-parens": 0, // disallow the omission of parentheses when invoking a constructor with no arguments + "no-array-constructor": 0, // disallow use of the Array constructor + "no-inline-comments": 0, // disallow comments inline after code (off by default) + "no-lonely-if": 0, // disallow if as the only statement in an else block (off by default) + "no-mixed-spaces-and-tabs": 0, // disallow mixed spaces and tabs for indentation + "no-multiple-empty-lines": 0, // disallow multiple empty lines (off by default) + "no-nested-ternary": 0, // disallow nested ternary expressions (off by default) + "no-new-object": 0, // disallow use of the Object constructor + "no-space-before-semi": 0, // disallow space before semicolon + "no-spaced-func": 0, // disallow space between function identifier and application + "no-ternary": 0, // disallow the use of ternary operators (off by default) + "no-trailing-spaces": 0, // disallow trailing whitespace at the end of lines + "no-underscore-dangle": 0, // disallow dangling underscores in identifiers + "no-wrap-func": 0, // disallow wrapping of non-IIFE statements in parens + "one-var": 0, // allow just one var statement per function (off by default) + "operator-assignment": 0, // require assignment operator shorthand where possible or prohibit it entirely (off by default) + "padded-blocks": 0, // enforce padding within blocks (off by default) + "quote-props": 0, // require quotes around object literal property names (off by default) + "quotes": 0, // specify whether double or single quotes should be used + "semi": 0, // require or disallow use of semicolons instead of ASI + "sort-vars": 0, // sort variables within the same declaration block (off by default) + "space-after-function-name": 0, // require a space after function names (off by default) + "space-after-keywords": 0, // require a space after certain keywords (off by default) + "space-before-blocks": 0, // require or disallow space before blocks (off by default) + "space-in-brackets": 0, // require or disallow spaces inside brackets (off by default) + "space-in-parens": 0, // require or disallow spaces inside parentheses (off by default) + "space-infix-ops": 0, // require spaces around operators + "space-return-throw-case": 0, // require a space after return, throw, and case + "space-unary-ops": 0, // Require or disallow spaces before/after unary operators (words on by default, nonwords off by default) + "spaced-line-comment": 0, // require or disallow a space immediately following the // in a line comment (off by default) + "wrap-regex": 0, // require regex literals to be wrapped in parentheses (off by default) + + + ////////// ECMAScript 6 ////////// + + "no-var": 0, // require let or const instead of var (off by default) + "generator-star": 0, // enforce the position of the * in generator functions (off by default) + + + ////////// Legacy ////////// + + "max-depth": 0, // specify the maximum depth that blocks can be nested (off by default) + "max-len": 0, // specify the maximum length of a line in your program (off by default) + "max-params": 0, // limits the number of parameters that can be used in the function declaration. (off by default) + "max-statements": 0, // specify the maximum number of statement allowed in a function (off by default) + "no-bitwise": 0, // disallow use of bitwise operators (off by default) + "no-plusplus": 0 // disallow use of unary operators, ++ and -- (off by default) + } +} \ No newline at end of file diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/jscs/.jscsrc b/dev/tests/static/testsuite/Magento/Test/Js/_files/jscs/.jscsrc new file mode 100644 index 0000000000000000000000000000000000000000..96ea18895001fd3b195667caf2042c3b4f938f1d --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Js/_files/jscs/.jscsrc @@ -0,0 +1,54 @@ +{ + "preset": "crockford", + "plugins": [ + "jscs-jsdoc" + ], + "requirePaddingNewlinesBeforeKeywords": [ + "do", + "for", + "if", + "switch", + "case", + "try", + "void", + "while", + "with", + "return" + ], + "requireSpaceBeforeKeywords": [ + "else", + "while", + "catch" + ], + "disallowMultipleLineStrings": true, + "validateQuoteMarks": "'", + "requireOperatorBeforeLineBreak": true, + "disallowYodaConditions": true, + "disallowMultipleLineBreaks": true, + "disallowSpacesInCallExpression": true, + "requirePaddingNewLinesInObjects": true, + "requireLineFeedAtFileEnd": true, + "disallowSpaceAfterObjectKeys": true, + "requireSpaceBeforeObjectValues": true, + "disallowSpaceAfterPrefixUnaryOperators": true, + "requireCamelCaseOrUpperCaseIdentifiers": true, + "validateParameterSeparator": ", ", + "disallowSpacesInsideObjectBrackets": "all", + "disallowSpacesInsideArrayBrackets": "all", + "requireLineBreakAfterVariableAssignment": true, + "requirePaddingNewLinesAfterUseStrict": true, + "disallowDanglingUnderscores": null, + "jsDoc": { + "checkAnnotations": { + "preset": "jsdoc3" + }, + "enforceExistence": "exceptExports", + "requireParamTypes": true, + "checkRedundantParams": true, + "checkReturnTypes": true, + "checkRedundantReturns": true, + "checkParamNames": true, + "checkTypes": "capitalizedNativeCase", + "requireHyphenBeforeDescription": true + } +} \ No newline at end of file diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/core.txt b/dev/tests/static/testsuite/Magento/Test/Js/_files/jshint/blacklist/core.txt similarity index 100% rename from dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/core.txt rename to dev/tests/static/testsuite/Magento/Test/Js/_files/jshint/blacklist/core.txt diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/whitelist/core.txt b/dev/tests/static/testsuite/Magento/Test/Js/_files/jshint/whitelist/core.txt similarity index 100% rename from dev/tests/static/testsuite/Magento/Test/Js/_files/whitelist/core.txt rename to dev/tests/static/testsuite/Magento/Test/Js/_files/jshint/whitelist/core.txt diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/whitelist/magento.txt b/dev/tests/static/testsuite/Magento/Test/Js/_files/whitelist/magento.txt new file mode 100644 index 0000000000000000000000000000000000000000..19aab504018b3ec043fc1fff5a28d6eb23391f89 --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Js/_files/whitelist/magento.txt @@ -0,0 +1,4 @@ +app/code/**/*.js +app/design/**/*.js +dev/tests/js/jasmine/tests/**/*.js +lib/web/mage/**/*.js diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php index 942a0b23d3169d60405531afd1dd4ccd5cca4b2d..7ce25410060614b2afcc4414d5841dfc1a10314d 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php @@ -1420,6 +1420,10 @@ return [ ['Magento\Core\Model\Design\Fallback\Rule\Simple', 'Magento\Framework\View\Design\Fallback\Rule\Simple'], ['Magento\Core\Model\Design\Fallback\Factory', 'Magento\Framework\View\Design\Fallback\RulePool'], ['Magento\Core\Model\Design\FileResolution\Strategy\Fallback\CachingProxy'], + ['Magento\Framework\View\Design\FileResolution\Fallback\Cache'], + ['Magento\Framework\View\Design\FileResolution\Fallback\CacheDataInterface'], + ['Magento\Framework\View\Design\FileResolution\Fallback\CacheData\Flat'], + ['Magento\Framework\View\Design\FileResolution\Fallback\CacheData\Grouped'], ['Magento\Framework\View\Design\FileResolution\Strategy\View\NotifiableInterface'], ['Magento\Framework\View\Design\FileResolution\Strategy\View\FileInterface'], ['Magento\Framework\View\Design\FileResolution\Strategy\View\LocaleInterface'], @@ -2613,6 +2617,7 @@ return [ ['Magento\Less\PreProcessorInterface', 'Magento\Framework\View\Asset\PreProcessorInterface'], ['Magento\Framework\View\Asset\PreProcessorFactory'], ['Magento\Framework\View\Asset\PreProcessor\Composite'], + ['Magento\Framework\View\Asset\PreProcessor\Cache'], [ 'Magento\Framework\View\Asset\PreProcessor\PreProcessorInterface', 'Magento\Framework\View\Asset\PreProcessorInterface', @@ -3671,6 +3676,14 @@ return [ ['Magento\Framework\View\Element\UiComponent\JsConfigInterface'], ['Magento\GiftMessage\Model\Plugin\TotalsDataProcessorPlugin'], ['Magento\Catalog\Model\Product\Attribute\Backend\Startdate', 'Magento\Catalog\Model\Attribute\Backend\Startdate'], + ['Magento\Framework\View\Asset\Minified\AbstractAsset'], + ['Magento\Framework\View\Asset\Minified\ImmutablePathAsset'], + ['Magento\Framework\View\Asset\Minified\MutablePathAsset'], + ['Magento\Framework\View\Asset\MinifyService'], + ['Magento\Framework\View\Test\Unit\Asset\Minified\AbstractAssetTestCase'], + ['Magento\Framework\View\Test\Unit\Asset\Minified\ImmutablePathAssetTest'], + ['Magento\Framework\View\Test\Unit\Asset\Minified\MutablePathAssetTest'], + ['Magento\Framework\View\Test\Unit\Asset\MinifyServiceTest'], ['Magento\Authorizenet\Block\Authorizenet\Form\Cc'], ['Magento\Authorizenet\Block\Authorizenet\Info\Cc'], ['Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Payment\Cancel'], @@ -3786,6 +3799,8 @@ return [ ['Magento\GoogleShopping\Test\Unit\Model\MassOperationsTest'], ['Magento\GoogleShopping\Test\Unit\Model\ObserverTest'], ['Magento\GoogleShopping\Test\Unit\Model\ServiceTest'], + ['Magento\Framework\Code\Minifier\Adapter\Js\JSMin'], + ['Magento\Framework\Code\Minifier\Adapter\Css\CssMinifier'], ['Magento\Framework\View\Asset\ModuleNotation\Resolver', 'Magento\Framework\View\Asset\NotationResolver\Module'], ['Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable\Attribute\Price\Data'], ['Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super\Settings'], diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_config_nodes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_config_nodes.php index af061c650f65bfbb257757b55ffb2244ebd6c524..5e29eb028e2490edf39fe60b40e0818e0a6c11e9 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_config_nodes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_config_nodes.php @@ -102,4 +102,6 @@ return [ '/config/global/currency/import/services' => 'Configurations moved to DI file settings', '/config/global/template' => 'Use /config/template of email_templates.xml', '/config/default/general/file/sitemap_generate_valid_paths' => '/config/default/sitemap/file/valid_paths', + '/config/dev/css/minify_adapter' => 'Was replaced using di', + '/config/dev/js/minify_adapter' => 'Was replaced using di', ]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php index 94bbad3aa4775e041dccd1be16af20baa4db272c..56fe3f6249939c3a2b3574405b58151335aa401e 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php @@ -731,6 +731,12 @@ return [ ], ['CURRENT_CUSTOMER', 'Magento\Customer\Controller\RegistryConstants'], ['METHOD_WPS', 'Magento\Paypal\Model\Config'], + [ + 'XML_PATH_MINIFICATION_ENABLED', + 'Magento\Framework\View\Asset\Config', + 'Magento\Framework\View\Asset\Minification::XML_PATH_MINIFICATION_ENABLED' + ], + ['XML_PATH_MINIFICATION_ADAPTER', 'Magento\Framework\View\Asset\Config'], ['ERROR_INVALID_PRICE_CORRECTION', 'Magento\ConfigurableImportExport\Model\Import\Product\Type\Configurable'], ['EXCEPTION_CODE_NOT_SALABLE', 'Magento\Wishlist\Model\Item'], ['EXCEPTION_CODE_HAS_REQUIRED_OPTIONS', 'Magento\Wishlist\Model\Item'], diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php index ccb2deb9bd8e4850186a6331f980e85aabc36700..6c5dd12a4cafc7c51880cf006a85b20a076c0789 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php @@ -2338,6 +2338,8 @@ return [ ['getChilds', 'Magento\Bundle\Block\Sales\Order\Items\Renderer', 'getChildren'], ['getChilds', 'Magento\Bundle\Model\Sales\Order\Pdf\Items\AbstractItems', 'getChildren'], ['prepareIndexdata', 'Magento\Search\Helper\Data'], + ['isAssetMinification', 'Magento\Framework\View\Asset\ConfigInterface', 'Magento\Framework\View\Asset\Minification::isEnabled'], + ['isAssetMinification', 'Magento\Framework\View\Asset\Config', 'Magento\Framework\View\Asset\Minification::isEnabled'], ['getPriceValues', 'Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable\Attribute\Collection'], ['getPricingValue', 'Magento\ConfigurableProduct\Model\Product\Type\Configurable\OptionValue'], ['getIsPercent', 'Magento\ConfigurableProduct\Model\Product\Type\Configurable\OptionValue'], diff --git a/dev/tools/grunt/configs/eslint.js b/dev/tools/grunt/configs/eslint.js new file mode 100644 index 0000000000000000000000000000000000000000..c72131becc6483bc3ca3b9124877e9406377fc6d --- /dev/null +++ b/dev/tools/grunt/configs/eslint.js @@ -0,0 +1,26 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +'use strict'; + +module.exports = { + file: { + options: { + configFile: 'dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc', + reset: true + }, + src: '' + }, + test: { + options: { + configFile: 'dev/tests/static/testsuite/Magento/Test/Js/_files/eslint/.eslintrc', + reset: true, + outputFile: 'dev/tests/static/eslint-error-report.xml', + format: 'checkstyle', + quiet: true + }, + src: '' + } +}; diff --git a/dev/tools/grunt/configs/jscs.js b/dev/tools/grunt/configs/jscs.js new file mode 100644 index 0000000000000000000000000000000000000000..8b89e0293bdb5de151a19266e8ffe5fe28d83de4 --- /dev/null +++ b/dev/tools/grunt/configs/jscs.js @@ -0,0 +1,23 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +'use strict'; + +module.exports = { + file: { + options: { + config: 'dev/tests/static/testsuite/Magento/Test/Js/_files/jscs/.jscsrc' + }, + src: '' + }, + test: { + options: { + config: 'dev/tests/static/testsuite/Magento/Test/Js/_files/jscs/.jscsrc', + reporterOutput: 'dev/tests/static/jscs-error-report.xml', + reporter: 'checkstyle' + }, + src: '' + } +}; diff --git a/dev/tools/grunt/configs/path.js b/dev/tools/grunt/configs/path.js index f160b35c92823e6826b518a82ea983f3cf3705b5..5021becadca7f8f21fa6d370be255a22e7ffcd16 100644 --- a/dev/tools/grunt/configs/path.js +++ b/dev/tools/grunt/configs/path.js @@ -25,5 +25,11 @@ module.exports = { legacy: 'lib/web/legacy-build.min.js' }, doc: 'lib/web/css/docs', - spec: 'dev/tests/js/spec' + spec: 'dev/tests/js/spec', + static: { + dir: 'dev/tests/static/testsuite/Magento/Test/Js/_files', + whitelist: 'dev/tests/static/testsuite/Magento/Test/Js/_files/whitelist/', + blacklist: 'dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/', + tmp: 'validation-files.txt' + } }; diff --git a/dev/tools/grunt/tasks/black-list-generator.js b/dev/tools/grunt/tasks/black-list-generator.js new file mode 100644 index 0000000000000000000000000000000000000000..cd98b734cf235a45de494f0bda0c75c40da3277e --- /dev/null +++ b/dev/tools/grunt/tasks/black-list-generator.js @@ -0,0 +1,26 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +module.exports = function (grunt) { + 'use strict'; + + var glob = require('glob'), + fs = require('fs'), + path = require('path'), + fst = require('../tools/fs-tools.js'), + pc = require('../configs/path'); + + grunt.registerTask('black-list-generator', function () { + process.chdir(grunt.option('dir') || '.'); + + var whiteListFile = glob.sync(pc.static.whitelist + '*.txt')[0], + blacklistFile = pc.static.blacklist + path.basename(whiteListFile), + whiteList = fst.getData(whiteListFile); + + fst.arrayRead(whiteList, function (data) { + fst.write(blacklistFile, data); + }); + }); +}; \ No newline at end of file diff --git a/dev/tools/grunt/tasks/clean-black-list.js b/dev/tools/grunt/tasks/clean-black-list.js new file mode 100644 index 0000000000000000000000000000000000000000..93318bd628cdfe432459a71dbdc0191bc1f2a086 --- /dev/null +++ b/dev/tools/grunt/tasks/clean-black-list.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +module.exports = function (grunt) { + 'use strict'; + + var fs = require('fs'), + _ = require('underscore'), + glob = require('glob'), + fst = require('../tools/fs-tools'), + pc = require('../configs/path'), + removeFromFile = function (path, files) { + var data = _.difference(fst.getData(path), files); + + fst.write(path, data); + }; + + grunt.registerTask('clean-black-list', function () { + process.chdir(grunt.option('dir') || '.'); + + var filesToRemove = grunt.option('file').split(','), + files = glob.sync(pc.static.blacklist + '*.txt'); + + _.each(files, function (file) { + removeFromFile(file, filesToRemove); + }); + }); +}; diff --git a/dev/tools/grunt/tasks/static.js b/dev/tools/grunt/tasks/static.js new file mode 100644 index 0000000000000000000000000000000000000000..433e7a2b161f3b758fcf383742fccc606ac1293a --- /dev/null +++ b/dev/tools/grunt/tasks/static.js @@ -0,0 +1,36 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +module.exports = function (grunt) { + 'use strict'; + + var pc = require('../configs/path'), + fs = require('fs'), + cvf = require('../tools/collect-validation-files'), + setConfig = function (task, target, data) { + var config = grunt.config.get(task); + + config[target].src = data; + grunt.config.set(task, config); + }; + + grunt.registerTask('static', function (target) { + var currentTarget = target || 'test', + file = grunt.option('file'), + tasks = [ + 'eslint:' + currentTarget, + 'jscs:' + currentTarget + ]; + + setConfig('eslint', currentTarget, cvf.getFiles(file)); + setConfig('jscs', currentTarget, cvf.getFiles(file)); + grunt.option('force', true); + grunt.task.run(tasks); + + if (!grunt.option('path')) { + fs.unlinkSync(pc.static.tmp); + } + }); +}; diff --git a/dev/tools/grunt/tools/collect-validation-files.js b/dev/tools/grunt/tools/collect-validation-files.js new file mode 100644 index 0000000000000000000000000000000000000000..a8c55f75040db2a650d53a4ac2ba091b47b232dd --- /dev/null +++ b/dev/tools/grunt/tools/collect-validation-files.js @@ -0,0 +1,55 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +'use strict'; + +var glob = require('glob'), + fs = require('fs'), + _ = require('underscore'), + fst = require('../tools/fs-tools'), + pc = require('../configs/path'); + +module.exports = { + readFiles: function (paths) { + var data = []; + + _.each(paths, function (path) { + data = _.union(data, fst.getData(path)); + }); + + return data; + }, + + getFilesForValidate: function () { + + var blackListFiles = glob.sync(pc.static.blacklist + '*.txt'), + whiteListFiles = glob.sync(pc.static.whitelist + '*.txt'), + blackList = this.readFiles(blackListFiles), + whiteList = this.readFiles(whiteListFiles), + files = []; + + fst.arrayRead(whiteList, function (data) { + files = _.difference(data, blackList); + }); + + return files; + }, + + getFiles: function (file) { + if (file) { + return file.split(','); + } + + if (!fs.existsSync(pc.static.tmp)) { + fst.write(pc.static.tmp, this.getFilesForValidate()); + } + + return fst.getData(pc.static.tmp); + } +}; diff --git a/dev/tools/grunt/tools/fs-tools.js b/dev/tools/grunt/tools/fs-tools.js new file mode 100644 index 0000000000000000000000000000000000000000..d5e6e924ef47866bd13837238a5c74ae5a17b903 --- /dev/null +++ b/dev/tools/grunt/tools/fs-tools.js @@ -0,0 +1,57 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +'use strict'; + +var fs = require('fs'), + glob = require('glob'), + nl = (function () { + if (process.platform === 'win32') { + return '\r\n'; + } + + return '\n'; + })(); + +module.exports = { + getData: function (filePath) { + return this.parseToReadData(fs.readFileSync(filePath)); + }, + write: function (file, data) { + fs.writeFileSync(file, this.parseToWriteData(data)); + console.log('The file was saved!'); + }, + + read: function (filePath) { + console.log('Collect data from ' + filePath + ': Start!'); + + return glob.sync(filePath); + }, + + arrayRead: function (pathArr, callback) { + var len = pathArr.length, + data = [], + i = 0; + + for (; i < len; i++) { + data = data.concat(this.read(pathArr[i])); + console.log('Collect data from ' + pathArr[i] + ': Finish!'); + } + callback(data); + }, + + parseToReadData: function (data) { + var result = data.toString().split(nl); + + result.pop(); + + return result; + }, + + parseToWriteData: function (data) { + data = data.join(nl) + nl; + + return data; + } +}; diff --git a/lib/internal/JSMin/jsmin.php b/lib/internal/JSMin/jsmin.php deleted file mode 100644 index ee1b442bcecf022f67c5a80c1efdb12473b1960f..0000000000000000000000000000000000000000 --- a/lib/internal/JSMin/jsmin.php +++ /dev/null @@ -1,386 +0,0 @@ -<?php -/** - * jsmin.php - PHP implementation of Douglas Crockford's JSMin. - * - * This is pretty much a direct port of jsmin.c to PHP with just a few - * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and - * outputs to stdout, this library accepts a string as input and returns another - * string as output. - * - * PHP 5 or higher is required. - * - * Permission is hereby granted to use this version of the library under the - * same terms as jsmin.c, which has the following license: - * - * -- - * Copyright (c) 2002 Douglas Crockford (www.crockford.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * The Software shall be used for Good, not Evil. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * -- - * - * @package JSMin - * @author Ryan Grove <ryan@wonko.com> - * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c) - * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port) - * @copyright 2012 Adam Goforth <aag@adamgoforth.com> (Updates) - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 1.1.2 (2012-05-01) - * @link https://github.com/rgrove/jsmin-php - */ - -class JSMin { - const ORD_LF = 10; - const ORD_SPACE = 32; - const ACTION_KEEP_A = 1; - const ACTION_DELETE_A = 2; - const ACTION_DELETE_A_B = 3; - - protected $a = ''; - protected $b = ''; - protected $input = ''; - protected $inputIndex = 0; - protected $inputLength = 0; - protected $lookAhead = null; - protected $output = ''; - - // -- Public Static Methods -------------------------------------------------- - - /** - * Minify Javascript - * - * @uses __construct() - * @uses min() - * @param string $js Javascript to be minified - * @return string - */ - public static function minify($js) { - $jsmin = new JSMin($js); - return $jsmin->min(); - } - - // -- Public Instance Methods ------------------------------------------------ - - /** - * Constructor - * - * @param string $input Javascript to be minified - */ - public function __construct($input) { - $this->input = str_replace("\r\n", "\n", $input); - $this->inputLength = strlen($this->input); - } - - // -- Protected Instance Methods --------------------------------------------- - - /** - * Action -- do something! What to do is determined by the $command argument. - * - * action treats a string as a single character. Wow! - * action recognizes a regular expression if it is preceded by ( or , or =. - * - * @uses next() - * @uses get() - * @throws JSMinException If parser errors are found: - * - Unterminated string literal - * - Unterminated regular expression set in regex literal - * - Unterminated regular expression literal - * @param int $command One of class constants: - * ACTION_KEEP_A Output A. Copy B to A. Get the next B. - * ACTION_DELETE_A Copy B to A. Get the next B. (Delete A). - * ACTION_DELETE_A_B Get the next B. (Delete B). - */ - protected function action($command) { - switch($command) { - case self::ACTION_KEEP_A: - $this->output .= $this->a; - - case self::ACTION_DELETE_A: - $this->a = $this->b; - - if ($this->a === "'" || $this->a === '"') { - for (;;) { - $this->output .= $this->a; - $this->a = $this->get(); - - if ($this->a === $this->b) { - break; - } - - if (ord($this->a) <= self::ORD_LF) { - throw new JSMinException('Unterminated string literal.'); - } - - if ($this->a === '\\') { - $this->output .= $this->a; - $this->a = $this->get(); - } - } - } - - case self::ACTION_DELETE_A_B: - $this->b = $this->next(); - - if ($this->b === '/' && ( - $this->a === '(' || $this->a === ',' || $this->a === '=' || - $this->a === ':' || $this->a === '[' || $this->a === '!' || - $this->a === '&' || $this->a === '|' || $this->a === '?' || - $this->a === '{' || $this->a === '}' || $this->a === ';' || - $this->a === "\n" )) { - - $this->output .= $this->a . $this->b; - - for (;;) { - $this->a = $this->get(); - - if ($this->a === '[') { - /* - inside a regex [...] set, which MAY contain a '/' itself. Example: mootools Form.Validator near line 460: - return Form.Validator.getValidator('IsEmpty').test(element) || (/^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]\.?){0,63}[a-z0-9!#$%&'*+/=?^_`{|}~-]@(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$/i).test(element.get('value')); - */ - for (;;) { - $this->output .= $this->a; - $this->a = $this->get(); - - if ($this->a === ']') { - break; - } elseif ($this->a === '\\') { - $this->output .= $this->a; - $this->a = $this->get(); - } elseif (ord($this->a) <= self::ORD_LF) { - throw new JSMinException('Unterminated regular expression set in regex literal.'); - } - } - } elseif ($this->a === '/') { - break; - } elseif ($this->a === '\\') { - $this->output .= $this->a; - $this->a = $this->get(); - } elseif (ord($this->a) <= self::ORD_LF) { - throw new JSMinException('Unterminated regular expression literal.'); - } - - $this->output .= $this->a; - } - - $this->b = $this->next(); - } - } - } - - /** - * Get next char. Convert ctrl char to space. - * - * @return string|null - */ - protected function get() { - $c = $this->lookAhead; - $this->lookAhead = null; - - if ($c === null) { - if ($this->inputIndex < $this->inputLength) { - $c = substr($this->input, $this->inputIndex, 1); - $this->inputIndex += 1; - } else { - $c = null; - } - } - - if ($c === "\r") { - return "\n"; - } - - if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) { - return $c; - } - - return ' '; - } - - /** - * Is $c a letter, digit, underscore, dollar sign, or non-ASCII character. - * - * @return bool - */ - protected function isAlphaNum($c) { - return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1; - } - - /** - * Perform minification, return result - * - * @uses action() - * @uses isAlphaNum() - * @uses get() - * @uses peek() - * @return string - */ - protected function min() { - if (0 == strncmp($this->peek(), "\xef", 1)) { - $this->get(); - $this->get(); - $this->get(); - } - - $this->a = "\n"; - $this->action(self::ACTION_DELETE_A_B); - - while ($this->a !== null) { - switch ($this->a) { - case ' ': - if ($this->isAlphaNum($this->b)) { - $this->action(self::ACTION_KEEP_A); - } else { - $this->action(self::ACTION_DELETE_A); - } - break; - - case "\n": - switch ($this->b) { - case '{': - case '[': - case '(': - case '+': - case '-': - case '!': - case '~': - $this->action(self::ACTION_KEEP_A); - break; - - case ' ': - $this->action(self::ACTION_DELETE_A_B); - break; - - default: - if ($this->isAlphaNum($this->b)) { - $this->action(self::ACTION_KEEP_A); - } - else { - $this->action(self::ACTION_DELETE_A); - } - } - break; - - default: - switch ($this->b) { - case ' ': - if ($this->isAlphaNum($this->a)) { - $this->action(self::ACTION_KEEP_A); - break; - } - - $this->action(self::ACTION_DELETE_A_B); - break; - - case "\n": - switch ($this->a) { - case '}': - case ']': - case ')': - case '+': - case '-': - case '"': - case "'": - $this->action(self::ACTION_KEEP_A); - break; - - default: - if ($this->isAlphaNum($this->a)) { - $this->action(self::ACTION_KEEP_A); - } - else { - $this->action(self::ACTION_DELETE_A_B); - } - } - break; - - default: - $this->action(self::ACTION_KEEP_A); - break; - } - } - } - - return $this->output; - } - - /** - * Get the next character, skipping over comments. peek() is used to see - * if a '/' is followed by a '/' or '*'. - * - * @uses get() - * @uses peek() - * @throws JSMinException On unterminated comment. - * @return string - */ - protected function next() { - $c = $this->get(); - - if ($c === '/') { - switch($this->peek()) { - case '/': - for (;;) { - $c = $this->get(); - - if (ord($c) <= self::ORD_LF) { - return $c; - } - } - - case '*': - $this->get(); - - for (;;) { - switch($this->get()) { - case '*': - if ($this->peek() === '/') { - $this->get(); - return ' '; - } - break; - - case null: - throw new JSMinException('Unterminated comment.'); - } - } - - default: - return $c; - } - } - - return $c; - } - - /** - * Get next char. If is ctrl character, translate to a space or newline. - * - * @uses get() - * @return string|null - */ - protected function peek() { - $this->lookAhead = $this->get(); - return $this->lookAhead; - } -} - -// -- Exceptions --------------------------------------------------------------- -class JSMinException extends Exception {} -?> diff --git a/lib/internal/Magento/Framework/App/SetupInfo.php b/lib/internal/Magento/Framework/App/SetupInfo.php index 06ce29f02930bbb788bc8b4ece865e46be24cb0c..cc8c53924eebc1fc7dd01b6c588821f1f4d8a22f 100644 --- a/lib/internal/Magento/Framework/App/SetupInfo.php +++ b/lib/internal/Magento/Framework/App/SetupInfo.php @@ -6,6 +6,8 @@ namespace Magento\Framework\App; +use \Magento\Framework\Setup\BackendFrontnameGenerator; + /** * A model for determining information about setup application */ @@ -113,6 +115,16 @@ class SetupInfo return 'http://' . $this->server['HTTP_HOST'] . substr($this->projectRoot . '/', strlen($this->docRoot)); } + /** + * Get the admin area path + * + * @return string + */ + public function getProjectAdminPath() + { + return BackendFrontnameGenerator::generate(); + } + /** * Gets setup application directory path in the filesystem * diff --git a/lib/internal/Magento/Framework/App/StaticResource.php b/lib/internal/Magento/Framework/App/StaticResource.php index bad6ddc7a796b96eb801b83c59434b114665096c..62f31c0acfaeb646d98493e58520c43ee80af5b1 100644 --- a/lib/internal/Magento/Framework/App/StaticResource.php +++ b/lib/internal/Magento/Framework/App/StaticResource.php @@ -54,11 +54,6 @@ class StaticResource implements \Magento\Framework\AppInterface */ private $configLoader; - /** - * @var \Magento\Framework\View\Asset\MinifyService - */ - protected $minifyService; - /** * @param State $state * @param Response\FileInterface $response @@ -68,7 +63,6 @@ class StaticResource implements \Magento\Framework\AppInterface * @param \Magento\Framework\Module\ModuleList $moduleList * @param \Magento\Framework\ObjectManagerInterface $objectManager * @param ConfigLoaderInterface $configLoader - * @param \Magento\Framework\View\Asset\MinifyService $minifyService */ public function __construct( State $state, @@ -78,8 +72,7 @@ class StaticResource implements \Magento\Framework\AppInterface \Magento\Framework\View\Asset\Repository $assetRepo, \Magento\Framework\Module\ModuleList $moduleList, \Magento\Framework\ObjectManagerInterface $objectManager, - ConfigLoaderInterface $configLoader, - \Magento\Framework\View\Asset\MinifyService $minifyService + ConfigLoaderInterface $configLoader ) { $this->state = $state; $this->response = $response; @@ -89,7 +82,6 @@ class StaticResource implements \Magento\Framework\AppInterface $this->moduleList = $moduleList; $this->objectManager = $objectManager; $this->configLoader = $configLoader; - $this->minifyService = $minifyService; } /** @@ -113,7 +105,6 @@ class StaticResource implements \Magento\Framework\AppInterface $file = $params['file']; unset($params['file']); $asset = $this->assetRepo->createAsset($file, $params); - $asset = $this->minifyService->getAssets([$asset], true)[0]; $this->response->setFilePath($asset->getSourceFile()); $this->publisher->publish($asset); } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php b/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php index 5dadd6a1f1716d79ddb529e1f3ffb27c822c7cd5..8cb4304875ab532633ad4a4efb414e349dfe562f 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php @@ -55,11 +55,6 @@ class StaticResourceTest extends \PHPUnit_Framework_TestCase */ private $object; - /** - * @var \Magento\Framework\View\Asset\MinifyService|\PHPUnit_Framework_MockObject_MockObject - */ - private $minifyService; - protected function setUp() { $this->state = $this->getMock('Magento\Framework\App\State', [], [], '', false); @@ -72,11 +67,6 @@ class StaticResourceTest extends \PHPUnit_Framework_TestCase $this->configLoader = $this->getMock( 'Magento\Framework\App\ObjectManager\ConfigLoader', [], [], '', false ); - $this->minifyService = $this->getMockBuilder('Magento\Framework\View\Asset\MinifyService') - ->disableOriginalConstructor() - ->setMethods(['getAssets']) - ->getMock(); - $this->object = new \Magento\Framework\App\StaticResource( $this->state, $this->response, @@ -86,7 +76,6 @@ class StaticResourceTest extends \PHPUnit_Framework_TestCase $this->moduleList, $this->objectManager, $this->configLoader, - $this->minifyService, $this->getMockForAbstractClass('\Magento\Framework\View\DesignInterface') ); } @@ -153,7 +142,6 @@ class StaticResourceTest extends \PHPUnit_Framework_TestCase $this->response->expects($this->once()) ->method('setFilePath') ->with('resource/file.css'); - $this->minifyService->expects($this->once())->method('getAssets')->willReturnArgument(0); $this->object->launch(); } diff --git a/lib/internal/Magento/Framework/Code/Minifier/Adapter/Css/CssMinifier.php b/lib/internal/Magento/Framework/Code/Minifier/Adapter/Css/CSSmin.php similarity index 78% rename from lib/internal/Magento/Framework/Code/Minifier/Adapter/Css/CssMinifier.php rename to lib/internal/Magento/Framework/Code/Minifier/Adapter/Css/CSSmin.php index e1d4d01942333670ac1799df0820c589520b8118..d57873751cdf6e73575c31c660b98925eabd3e99 100644 --- a/lib/internal/Magento/Framework/Code/Minifier/Adapter/Css/CssMinifier.php +++ b/lib/internal/Magento/Framework/Code/Minifier/Adapter/Css/CSSmin.php @@ -6,10 +6,13 @@ namespace Magento\Framework\Code\Minifier\Adapter\Css; -use CSSmin; +use CSSmin as CssMinLibrary; use Magento\Framework\Code\Minifier\AdapterInterface; -class CssMinifier implements AdapterInterface +/** + * Adapter for CSSmin library + */ +class CSSmin implements AdapterInterface { /** * 'pcre.recursion_limit' value for CSSMin minification @@ -17,14 +20,14 @@ class CssMinifier implements AdapterInterface const PCRE_RECURSION_LIMIT = 1000; /** - * @var CSSmin + * @var CssMinLibrary */ protected $cssMinifier; /** - * @param CSSmin $cssMinifier + * @param CssMinLibrary $cssMinifier */ - public function __construct(CSSmin $cssMinifier) + public function __construct(CssMinLibrary $cssMinifier) { $this->cssMinifier = $cssMinifier; } diff --git a/lib/internal/Magento/Framework/Code/Minifier/Adapter/Js/JShrink.php b/lib/internal/Magento/Framework/Code/Minifier/Adapter/Js/JShrink.php new file mode 100644 index 0000000000000000000000000000000000000000..f0b0976ff559578686bed38c6da5fc967de7226a --- /dev/null +++ b/lib/internal/Magento/Framework/Code/Minifier/Adapter/Js/JShrink.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Code\Minifier\Adapter\Js; + +use JShrink\Minifier; +use Magento\Framework\Code\Minifier\AdapterInterface; + +/** + * Adapter for JShrink library + */ +class JShrink implements AdapterInterface +{ + /** + * Takes a string containing javascript and removes unneeded characters in + * order to shrink the code without altering it's functionality. + * + * @param string $content The raw javascript to be minified + * @throws \Exception + * @return bool|string + */ + public function minify($content) + { + return Minifier::minify($content); + } +} diff --git a/lib/internal/Magento/Framework/Code/Minifier/Adapter/Js/Jsmin.php b/lib/internal/Magento/Framework/Code/Minifier/Adapter/Js/Jsmin.php deleted file mode 100644 index fa5d3c2acb12a50be96daf65c5205b2151828a23..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/Code/Minifier/Adapter/Js/Jsmin.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\Code\Minifier\Adapter\Js; - -if (!class_exists('JSMin')) { - require_once __DIR__ . '/../../../../../../JSMin/jsmin.php'; -} -/** - * Adapter for JSMin library - */ -class Jsmin implements \Magento\Framework\Code\Minifier\AdapterInterface -{ - /** - * {@inheritdoc} - */ - public function minify($content) - { - return \JSMin::minify($content); - } -} diff --git a/lib/internal/Magento/Framework/Code/Test/Unit/Minifier/Adapter/Js/JsminTest.php b/lib/internal/Magento/Framework/Code/Test/Unit/Minifier/Adapter/Js/JShrinkTest.php similarity index 79% rename from lib/internal/Magento/Framework/Code/Test/Unit/Minifier/Adapter/Js/JsminTest.php rename to lib/internal/Magento/Framework/Code/Test/Unit/Minifier/Adapter/Js/JShrinkTest.php index 0ebb776c2b70531bb99cbe84bb2c876e7f5a51c3..c77ded66b9ee78e7324921cb666cda47ab58b345 100644 --- a/lib/internal/Magento/Framework/Code/Test/Unit/Minifier/Adapter/Js/JsminTest.php +++ b/lib/internal/Magento/Framework/Code/Test/Unit/Minifier/Adapter/Js/JShrinkTest.php @@ -5,14 +5,14 @@ */ namespace Magento\Framework\Code\Test\Unit\Minifier\Adapter\Js; -class JsminTest extends \PHPUnit_Framework_TestCase +class JShrinkTest extends \PHPUnit_Framework_TestCase { public function testMinify() { $content = file_get_contents(__DIR__ . '/../../_files/js/original.js'); - $minifier = new \Magento\Framework\Code\Minifier\Adapter\Js\Jsmin(); + $minifier = new \Magento\Framework\Code\Minifier\Adapter\Js\JShrink(); $actual = $minifier->minify($content); - $expected = "\nvar one='one';var two='two';"; + $expected = "var one='one';var two='two';"; $this->assertEquals($expected, $actual); } } diff --git a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/LessTest.php b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/LessTest.php index a889a4320f3639f891c117e5cfba26d6cc122d76..33a424bf562a08be19faad8466555e3c25aa52ea 100644 --- a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/LessTest.php +++ b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/LessTest.php @@ -5,6 +5,8 @@ */ namespace Magento\Framework\Css\Test\Unit\PreProcessor; +use Magento\Framework\View\Asset\PreProcessor\Chain; + class LessTest extends \PHPUnit_Framework_TestCase { /** @@ -18,7 +20,7 @@ class LessTest extends \PHPUnit_Framework_TestCase private $adapter; /** - * @var \Magento\Framework\View\Asset\PreProcessor\Chain + * @var Chain */ private $chain; @@ -33,7 +35,7 @@ class LessTest extends \PHPUnit_Framework_TestCase $this->adapter = $this->getMockForAbstractClass('\Magento\Framework\Css\PreProcessor\AdapterInterface'); $asset = $this->getMockForAbstractClass('\Magento\Framework\View\Asset\LocalInterface'); $asset->expects($this->once())->method('getContentType')->will($this->returnValue('origType')); - $this->chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($asset, 'original content', 'origType'); + $this->chain = new Chain($asset, 'original content', 'origType', 'origPath'); $this->object = new \Magento\Framework\Css\PreProcessor\Less($this->fileGenerator, $this->adapter); } diff --git a/lib/internal/Magento/Framework/Less/Test/Unit/PreProcessor/Instruction/ImportTest.php b/lib/internal/Magento/Framework/Less/Test/Unit/PreProcessor/Instruction/ImportTest.php index 367963a47949af3c49ded54298d189a370a5f062..aee9a1dc9bd1b0efea81d5c2d164b0647d951306 100644 --- a/lib/internal/Magento/Framework/Less/Test/Unit/PreProcessor/Instruction/ImportTest.php +++ b/lib/internal/Magento/Framework/Less/Test/Unit/PreProcessor/Instruction/ImportTest.php @@ -45,7 +45,7 @@ class ImportTest extends \PHPUnit_Framework_TestCase */ public function testProcess($originalContent, $foundPath, $resolvedPath, $expectedContent) { - $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'css'); + $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'css', 'path'); $this->notationResolver->expects($this->once()) ->method('convertModuleNotationToPath') ->with($this->asset, $foundPath) @@ -114,7 +114,7 @@ class ImportTest extends \PHPUnit_Framework_TestCase $originalContent = 'color: #000000;'; $expectedContent = 'color: #000000;'; - $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'css'); + $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'css', 'path'); $this->notationResolver->expects($this->never()) ->method('convertModuleNotationToPath'); $this->object->process($chain); @@ -136,10 +136,11 @@ class ImportTest extends \PHPUnit_Framework_TestCase $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain( $this->asset, '@import (type) "Magento_Module::something.css" media;', - 'css' + 'css', + 'path' ); $this->object->process($chain); - $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, 'color: #000000;', 'css'); + $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, 'color: #000000;', 'css', 'path'); $this->object->process($chain); $expected = [['Magento_Module::something.css', $this->asset]]; diff --git a/lib/internal/Magento/Framework/Less/Test/Unit/PreProcessor/Instruction/MagentoImportTest.php b/lib/internal/Magento/Framework/Less/Test/Unit/PreProcessor/Instruction/MagentoImportTest.php index e8837987d1406d6ee9a78b8ea6eb946f6b0b0193..afaa1a4a6e7180fda7f2c658613e4379212efd4a 100644 --- a/lib/internal/Magento/Framework/Less/Test/Unit/PreProcessor/Instruction/MagentoImportTest.php +++ b/lib/internal/Magento/Framework/Less/Test/Unit/PreProcessor/Instruction/MagentoImportTest.php @@ -76,7 +76,7 @@ class MagentoImportTest extends \PHPUnit_Framework_TestCase */ public function testProcess($originalContent, $foundPath, $resolvedPath, $foundFiles, $expectedContent) { - $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'css'); + $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'css', 'path'); $relatedAsset = $this->getMock('\Magento\Framework\View\Asset\File', [], [], '', false); $relatedAsset->expects($this->once()) ->method('getFilePath') @@ -163,7 +163,7 @@ class MagentoImportTest extends \PHPUnit_Framework_TestCase { $originalContent = 'color: #000000;'; $expectedContent = 'color: #000000;'; - $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'css'); + $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'css', 'orig'); $this->assetRepo->expects($this->never()) ->method('createRelated'); $this->object->process($chain); @@ -174,7 +174,7 @@ class MagentoImportTest extends \PHPUnit_Framework_TestCase public function testProcessException() { $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain( - $this->asset, '//@magento_import "some/file.css";', 'css' + $this->asset, '//@magento_import "some/file.css";', 'css', 'path' ); $exception = new \LogicException('Error happened'); $this->assetRepo->expects($this->once()) diff --git a/lib/internal/Magento/Framework/RequireJs/Config.php b/lib/internal/Magento/Framework/RequireJs/Config.php index 125f39876086b0271e3691b16e42d0f8e6b0d6b9..43c80c844c173445ffa1be4b6c3cfb9eac8fa2ef 100644 --- a/lib/internal/Magento/Framework/RequireJs/Config.php +++ b/lib/internal/Magento/Framework/RequireJs/Config.php @@ -6,6 +6,7 @@ namespace Magento\Framework\RequireJs; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\View\Asset\Minification; /** * Provider of RequireJs config information @@ -37,6 +38,11 @@ class Config */ const STATIC_FILE_NAME = 'mage\requirejs\static.js'; + /** + * File name of minified files resolver + */ + const MIN_RESOLVER_FILENAME = 'requirejs-min-resolver.js'; + /** * File name of StaticJs */ @@ -85,22 +91,38 @@ config; */ private $staticContext; + /** + * @var \Magento\Framework\Code\Minifier\AdapterInterface + */ + private $minifyAdapter; + + /** + * @var Minification + */ + private $minification; + /** * @param \Magento\Framework\RequireJs\Config\File\Collector\Aggregated $fileSource * @param \Magento\Framework\View\DesignInterface $design * @param \Magento\Framework\Filesystem $appFilesystem * @param \Magento\Framework\View\Asset\Repository $assetRepo + * @param \Magento\Framework\Code\Minifier\AdapterInterface $minifyAdapter + * @param Minification $minification */ public function __construct( \Magento\Framework\RequireJs\Config\File\Collector\Aggregated $fileSource, \Magento\Framework\View\DesignInterface $design, \Magento\Framework\Filesystem $appFilesystem, - \Magento\Framework\View\Asset\Repository $assetRepo + \Magento\Framework\View\Asset\Repository $assetRepo, + \Magento\Framework\Code\Minifier\AdapterInterface $minifyAdapter, + Minification $minification ) { $this->fileSource = $fileSource; $this->design = $design; $this->baseDir = $appFilesystem->getDirectoryRead(DirectoryList::ROOT); $this->staticContext = $assetRepo->getStaticViewFileContext(); + $this->minifyAdapter = $minifyAdapter; + $this->minification = $minification; } /** @@ -128,6 +150,10 @@ config; self::FULL_CONFIG_TEMPLATE ); + if ($this->minification->isEnabled('js')) { + $fullConfig = $this->minifyAdapter->minify($fullConfig); + } + return $fullConfig; } @@ -138,7 +164,7 @@ config; */ public function getConfigFileRelativePath() { - return self::DIR_NAME . '/' . $this->staticContext->getConfigPath() . '/' . self::CONFIG_FILE_NAME; + return self::DIR_NAME . '/' . $this->staticContext->getConfigPath() . '/' . $this->getConfigFileName(); } /** @@ -158,7 +184,7 @@ config; */ public function getRequireJsFileRelativePath() { - return $this->staticContext->getConfigPath() . '/' .self::REQUIRE_JS_FILE_NAME; + return $this->staticContext->getConfigPath() . '/' . self::REQUIRE_JS_FILE_NAME; } /** @@ -172,6 +198,58 @@ config; 'baseUrl' => $this->staticContext->getBaseUrl() . $this->staticContext->getPath(), ]; $config = json_encode($config, JSON_UNESCAPED_SLASHES); - return "require.config($config);"; + $result = "require.config($config);"; + return $result; + } + + /** + * Get path to '.min' files resolver relative to config files directory + * + * @return string + */ + public function getMinResolverRelativePath() + { + return + $this->staticContext->getConfigPath() . + '/' . + $this->minification->addMinifiedSign(self::MIN_RESOLVER_FILENAME); + } + + /** + * @return string + */ + protected function getConfigFileName() + { + return $this->minification->addMinifiedSign(self::CONFIG_FILE_NAME); + } + + /** + * @return string + */ + public function getMinResolverCode() + { + $excludes = []; + foreach ($this->minification->getExcludes('js') as $expression) { + $excludes[] = '!url.match(/' . str_replace('/', '\/', $expression) . '/)'; + } + $excludesCode = empty($excludes) ? 'true' : implode('&&', $excludes); + + $result = <<<code + if (!require.s.contexts._.__load) { + require.s.contexts._.__load = require.s.contexts._.load; + require.s.contexts._.load = function(id, url) { + if ({$excludesCode}) { + url = url.replace(/(\.min)?\.js$/, '.min.js'); + } + return require.s.contexts._.__load.apply(require.s.contexts._, [id, url]); + } + } + +code; + + if ($this->minification->isEnabled('js')) { + $result = $this->minifyAdapter->minify($result); + } + return $result; } } diff --git a/lib/internal/Magento/Framework/RequireJs/Test/Unit/ConfigTest.php b/lib/internal/Magento/Framework/RequireJs/Test/Unit/ConfigTest.php index 7c3bbcf1214f2eb1cb0a60a027e8ff8946a6bcff..9622e03bdbf0b6b684060db935334c67ea7771e8 100644 --- a/lib/internal/Magento/Framework/RequireJs/Test/Unit/ConfigTest.php +++ b/lib/internal/Magento/Framework/RequireJs/Test/Unit/ConfigTest.php @@ -37,6 +37,16 @@ class ConfigTest extends \PHPUnit_Framework_TestCase */ private $object; + /** + * @var \Magento\Framework\View\Asset\Minification|\PHPUnit_Framework_MockObject_MockObject + */ + private $minificationMock; + + /** + * @var \Magento\Framework\Code\Minifier\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $minifyAdapterMock; + protected function setUp() { $this->fileSource = $this->getMock( @@ -64,7 +74,21 @@ class ConfigTest extends \PHPUnit_Framework_TestCase ) ->getMock(); $repo->expects($this->once())->method('getStaticViewFileContext')->will($this->returnValue($this->context)); - $this->object = new \Magento\Framework\RequireJs\Config($this->fileSource, $this->design, $filesystem, $repo); + $this->minificationMock = $this->getMockBuilder('Magento\Framework\View\Asset\Minification') + ->disableOriginalConstructor() + ->getMock(); + + $this->minifyAdapterMock = $this->getMockBuilder('Magento\Framework\Code\Minifier\AdapterInterface') + ->getMockForAbstractClass(); + + $this->object = new Config( + $this->fileSource, + $this->design, + $filesystem, + $repo, + $this->minifyAdapterMock, + $this->minificationMock + ); } public function testGetConfig() @@ -98,6 +122,11 @@ class ConfigTest extends \PHPUnit_Framework_TestCase ->method('getFiles') ->with($theme, Config::CONFIG_FILE_NAME) ->will($this->returnValue([$fileOne, $fileTwo])); + $this->minificationMock + ->expects($this->atLeastOnce()) + ->method('isEnabled') + ->with('js') + ->willReturn(true); $expected = <<<expected (function(require){ @@ -116,17 +145,70 @@ require.config(config); })(require); expected; + $this->minifyAdapterMock + ->expects($this->once()) + ->method('minify') + ->with($expected) + ->willReturnArgument(0); + $actual = $this->object->getConfig(); $this->assertStringMatchesFormat($expected, $actual); } + public function testGetMinResolverCode() + { + $this->minificationMock + ->expects($this->once()) + ->method('getExcludes') + ->with('js') + ->willReturn(['\.min\.']); + $this->minificationMock + ->expects($this->once()) + ->method('isEnabled') + ->with('js') + ->willReturn(true); + $this->minifyAdapterMock + ->expects($this->once()) + ->method('minify') + ->willReturnArgument(0); + + $expected = <<<code + if (!require.s.contexts._.__load) { + require.s.contexts._.__load = require.s.contexts._.load; + require.s.contexts._.load = function(id, url) { + if (!url.match(/\.min\./)) { + url = url.replace(/(\.min)?\.js$/, '.min.js'); + } + return require.s.contexts._.__load.apply(require.s.contexts._, [id, url]); + } + } + +code; + $this->assertEquals($expected, $this->object->getMinResolverCode()); + } + public function testGetConfigFileRelativePath() { + $this->minificationMock + ->expects($this->any()) + ->method('addMinifiedSign') + ->willReturnArgument(0); $this->context->expects($this->once())->method('getConfigPath')->will($this->returnValue('path')); $actual = $this->object->getConfigFileRelativePath(); $this->assertSame('_requirejs/path/requirejs-config.js', $actual); } + public function testGetMinResolverRelativePath() + { + $this->minificationMock + ->expects($this->any()) + ->method('addMinifiedSign') + ->willReturnArgument(0); + $this->context->expects($this->once())->method('getConfigPath')->will($this->returnValue('path')); + $actual = $this->object->getMinResolverRelativePath(); + $this->assertSame('path/requirejs-min-resolver.js', $actual); + } + public function testGetBaseConfig() { $this->context->expects($this->once())->method('getPath')->will($this->returnValue('area/theme/locale')); diff --git a/lib/internal/Magento/Framework/Setup/BackendFrontnameGenerator.php b/lib/internal/Magento/Framework/Setup/BackendFrontnameGenerator.php new file mode 100644 index 0000000000000000000000000000000000000000..8a66f295175b960061782aa18278e94ab67a0b27 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/BackendFrontnameGenerator.php @@ -0,0 +1,34 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup; + +/** + * Class to generate random backend URI + */ +class BackendFrontnameGenerator +{ + /** + * Prefix for admin area path + */ + const ADMIN_AREA_PATH_PREFIX = 'admin_'; + + /** + * Length of the backend frontname random part + */ + const ADMIN_AREA_PATH_RANDOM_PART_LENGTH = 6; + + /** + * Generate Backend name + * + * @return string + */ + public static function generate() + { + return self::ADMIN_AREA_PATH_PREFIX + . substr(base_convert(rand(0, PHP_INT_MAX), 10, 36), 0, self::ADMIN_AREA_PATH_RANDOM_PART_LENGTH); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/BackendFrontnameGeneratorTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/BackendFrontnameGeneratorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a74917e5e54f3668348232c0ba331ec903381204 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/BackendFrontnameGeneratorTest.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Test\Unit; + +use Magento\Framework\Setup\BackendFrontnameGenerator; + +class BackendFrontnameGeneratorTest extends \PHPUnit_Framework_TestCase +{ + public function testGenerate() + { + $regexp = '/' . BackendFrontnameGenerator::ADMIN_AREA_PATH_PREFIX + . '[a-z0-9]{1,' . BackendFrontnameGenerator::ADMIN_AREA_PATH_RANDOM_PART_LENGTH .'}/'; + + $this->assertRegExp($regexp, BackendFrontnameGenerator::generate(), 'Unexpected Backend Frontname pattern.'); + } +} diff --git a/lib/internal/Magento/Framework/View/Asset/Bundle.php b/lib/internal/Magento/Framework/View/Asset/Bundle.php index 4f9d0e68ef62b1c980a519a38a071340c5150fa2..10573664bc6c936d15aec35a80b7b5464c37c936 100644 --- a/lib/internal/Magento/Framework/View/Asset/Bundle.php +++ b/lib/internal/Magento/Framework/View/Asset/Bundle.php @@ -12,7 +12,7 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\View\Asset\File\FallbackContext; /** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * Bundle model */ class Bundle { @@ -37,16 +37,24 @@ class Bundle */ protected $content = []; + /** + * @var Minification + */ + protected $minification; + /** * @param Filesystem $filesystem * @param Bundle\ConfigInterface $bundleConfig + * @param Minification $minification */ public function __construct( Filesystem $filesystem, - Bundle\ConfigInterface $bundleConfig + Bundle\ConfigInterface $bundleConfig, + Minification $minification ) { $this->filesystem = $filesystem; $this->bundleConfig = $bundleConfig; + $this->minification = $minification; } /** @@ -153,7 +161,9 @@ class Bundle */ protected function getAssetKey(LocalInterface $asset) { - return ($asset->getModule() == '') ? $asset->getFilePath() : $asset->getModule() . '/' . $asset->getFilePath(); + $result = (($asset->getModule() == '') ? '' : $asset->getModule() . '/') . $asset->getFilePath(); + $result = $this->minification->addMinifiedSign($result); + return $result; } /** @@ -228,16 +238,11 @@ class Bundle $this->fillContent($parts, $context); } - $this->content[count($this->content) > 0 ? count($this->content) - 1 : 0] .= $this->getInitJs(); + $this->content[max(0, count($this->content) - 1)] .= $this->getInitJs(); - if (count($this->content) > 1) { - foreach ($this->content as $partIndex => $content) { - $dir->writeFile($bundlePath . "$partIndex.js", $content); - } - return; + foreach ($this->content as $partIndex => $content) { + $dir->writeFile($this->minification->addMinifiedSign($bundlePath . $partIndex . '.js'), $content); } - - $dir->writeFile($bundlePath . '0.js', $this->content[0]); } /** diff --git a/lib/internal/Magento/Framework/View/Asset/Bundle/Manager.php b/lib/internal/Magento/Framework/View/Asset/Bundle/Manager.php index 9c4b1094b23843af10d72d31997f6e1867d27a01..0b1c7f2cd5b05d20d37b951012650d3044cf7c65 100644 --- a/lib/internal/Magento/Framework/View/Asset/Bundle/Manager.php +++ b/lib/internal/Magento/Framework/View/Asset/Bundle/Manager.php @@ -40,23 +40,30 @@ class Manager /** @var array */ public static $availableTypes = [self::ASSET_TYPE_JS, self::ASSET_TYPE_HTML]; + /** + * @var Asset\Minification + */ + private $minification; /** * @param Filesystem $filesystem * @param Bundle $bundle * @param Bundle\ConfigInterface $bundleConfig * @param Asset\ConfigInterface $assetConfig + * @param Asset\Minification $minification */ public function __construct( Filesystem $filesystem, Bundle $bundle, Bundle\ConfigInterface $bundleConfig, - Asset\ConfigInterface $assetConfig + Asset\ConfigInterface $assetConfig, + Asset\Minification $minification ) { $this->filesystem = $filesystem; $this->assetConfig = $assetConfig; $this->bundleConfig = $bundleConfig; $this->bundle = $bundle; + $this->minification = $minification; } /** @@ -186,7 +193,7 @@ class Manager if (in_array($asset->getFilePath(), $this->excluded)) { return false; } - if ($this->assetConfig->isAssetMinification($asset->getContentType())) { + if ($this->minification->isEnabled($asset->getContentType())) { if (strpos($sourceFile, '.min.') !== false) { $this->excluded[] = str_replace('.min.', '', $sourceFile); diff --git a/lib/internal/Magento/Framework/View/Asset/Config.php b/lib/internal/Magento/Framework/View/Asset/Config.php index 1fa3bbde781383f5873c742fe0c358368fa61f46..9845dce1f232c92cf5a46717e52643f34970fe6c 100644 --- a/lib/internal/Magento/Framework/View/Asset/Config.php +++ b/lib/internal/Magento/Framework/View/Asset/Config.php @@ -8,6 +8,7 @@ namespace Magento\Framework\View\Asset; use Magento\Store\Model\ScopeInterface; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\State; /** * View asset configuration interface @@ -24,16 +25,6 @@ class Config implements \Magento\Framework\View\Asset\ConfigInterface */ const XML_PATH_MERGE_JS_FILES = 'dev/js/merge_files'; - /** - * XML path for asset minification configuration - */ - const XML_PATH_MINIFICATION_ENABLED = 'dev/%s/minify_files'; - - /** - * XML path for asset minification adapter configuration - */ - const XML_PATH_MINIFICATION_ADAPTER = 'dev/%s/minify_adapter'; - /** * XML path for asset minification adapter configuration */ @@ -96,34 +87,6 @@ class Config implements \Magento\Framework\View\Asset\ConfigInterface ); } - /** - * Check whether asset minification is on for specified content type - * - * @param string $contentType - * @return bool - */ - public function isAssetMinification($contentType) - { - return (bool)$this->scopeConfig->isSetFlag( - sprintf(self::XML_PATH_MINIFICATION_ENABLED, $contentType), - ScopeInterface::SCOPE_STORE - ); - } - - /** - * Get asset minification adapter for specified content type - * - * @param string $contentType - * @return string - */ - public function getAssetMinificationAdapter($contentType) - { - return (string)$this->scopeConfig->getValue( - sprintf(self::XML_PATH_MINIFICATION_ADAPTER, $contentType), - ScopeInterface::SCOPE_STORE - ); - } - /** * Check whether minify of HTML is on * diff --git a/lib/internal/Magento/Framework/View/Asset/ConfigInterface.php b/lib/internal/Magento/Framework/View/Asset/ConfigInterface.php index f099082ce4442631f9690cca216309906362fe81..607bb10e9aacf0569f5f0a57943b39839c62f633 100644 --- a/lib/internal/Magento/Framework/View/Asset/ConfigInterface.php +++ b/lib/internal/Magento/Framework/View/Asset/ConfigInterface.php @@ -31,22 +31,6 @@ interface ConfigInterface */ public function isBundlingJsFiles(); - /** - * Check whether asset minification is on for specified content type - * - * @param string $contentType - * @return bool - */ - public function isAssetMinification($contentType); - - /** - * Get asset minification adapter for specified content type - * - * @param string $contentType - * @return string - */ - public function getAssetMinificationAdapter($contentType); - /** * Check whether minify of HTML is on * diff --git a/lib/internal/Magento/Framework/View/Asset/File.php b/lib/internal/Magento/Framework/View/Asset/File.php index 09541945b0e03efad1408fef51b477faef45b6aa..4186a5b066f6cec7a37d4c00848199a4b05021c8 100644 --- a/lib/internal/Magento/Framework/View/Asset/File.php +++ b/lib/internal/Magento/Framework/View/Asset/File.php @@ -6,6 +6,8 @@ namespace Magento\Framework\View\Asset; +use Magento\Framework\View\Asset\ConfigInterface as AssetConfigInterface; + /** * A locally available static view file asset that can be referred with a file path * @@ -43,20 +45,33 @@ class File implements MergeableInterface */ private $resolvedFile; + /** + * @var Minification + */ + private $minification; + /** * @param Source $source * @param ContextInterface $context * @param string $filePath * @param string $module * @param string $contentType - */ - public function __construct(Source $source, ContextInterface $context, $filePath, $module, $contentType) - { + * @param Minification $minification + */ + public function __construct( + Source $source, + ContextInterface $context, + $filePath, + $module, + $contentType, + Minification $minification + ) { $this->source = $source; $this->context = $context; $this->filePath = $filePath; $this->module = $module; $this->contentType = $contentType; + $this->minification = $minification; } /** @@ -92,6 +107,7 @@ class File implements MergeableInterface $result = $this->join($result, $this->context->getPath()); $result = $this->join($result, $this->module); $result = $this->join($result, $this->filePath); + $result = $this->minification->addMinifiedSign($result); return $result; } diff --git a/lib/internal/Magento/Framework/View/Asset/File/ContextFactory.php b/lib/internal/Magento/Framework/View/Asset/File/ContextFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..fb375b886f31613d18233fc2c4204538d77461bf --- /dev/null +++ b/lib/internal/Magento/Framework/View/Asset/File/ContextFactory.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Asset\File; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Factory class for \Magento\Framework\View\Asset\File\Context + */ +class ContextFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return \Magento\Framework\View\Asset\File\Context + */ + public function create(array $data = []) + { + return $this->objectManager->create(Context::class, $data); + } +} diff --git a/lib/internal/Magento/Framework/View/Asset/File/FallbackContextFactory.php b/lib/internal/Magento/Framework/View/Asset/File/FallbackContextFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..4d2b7d2cffb5d8c9b11c628212a8f4646191f132 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Asset/File/FallbackContextFactory.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Asset\File; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Factory class for \Magento\Framework\View\Asset\File\FallbackContext + */ +class FallbackContextFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return \Magento\Framework\View\Asset\File\FallbackContext + */ + public function create(array $data = []) + { + return $this->objectManager->create(FallbackContext::class, $data); + } +} diff --git a/lib/internal/Magento/Framework/View/Asset/FileFactory.php b/lib/internal/Magento/Framework/View/Asset/FileFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..13f355c8efe368a5d3f41855bfa539235bacc794 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Asset/FileFactory.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Asset; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Factory class for \Magento\Framework\View\Asset\File + */ +class FileFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return \Magento\Framework\View\Asset\File + */ + public function create(array $data = []) + { + return $this->objectManager->create(File::class, $data); + } +} diff --git a/lib/internal/Magento/Framework/View/Asset/Merged.php b/lib/internal/Magento/Framework/View/Asset/Merged.php index 796af0be5cff413d2027a72714582ae1b221230b..c52e0daa8fb5e62ef6320d005c4ea8da6ff84033 100644 --- a/lib/internal/Magento/Framework/View/Asset/Merged.php +++ b/lib/internal/Magento/Framework/View/Asset/Merged.php @@ -10,6 +10,11 @@ namespace Magento\Framework\View\Asset; */ class Merged implements \Iterator { + /** + * Directory for dynamically generated public view files, relative to STATIC_VIEW + */ + const CACHE_VIEW_REL = '_cache'; + /** * @var \Psr\Log\LoggerInterface */ @@ -169,6 +174,6 @@ class Merged implements \Iterator */ public static function getRelativeDir() { - return Minified\AbstractAsset::CACHE_VIEW_REL . '/merged'; + return self::CACHE_VIEW_REL . '/merged'; } } diff --git a/lib/internal/Magento/Framework/View/Asset/Minification.php b/lib/internal/Magento/Framework/View/Asset/Minification.php new file mode 100644 index 0000000000000000000000000000000000000000..27afca110ddcbb276addbb14a8ca577793f2b82f --- /dev/null +++ b/lib/internal/Magento/Framework/View/Asset/Minification.php @@ -0,0 +1,145 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Asset; + +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\State; + +class Minification +{ + /** + * XML path for asset minification configuration + */ + const XML_PATH_MINIFICATION_ENABLED = 'dev/%s/minify_files'; + + const XML_PATH_MINIFICATION_EXCLUDES = 'dev/%s/minify_exclude'; + + /** + * @var ScopeConfigInterface + */ + private $scopeConfig; + /** + * @var State + */ + private $appState; + /** + * @var string + */ + private $scope; + /** + * @var array + */ + private $excludes = []; + + /** + * @param ScopeConfigInterface $scopeConfig + * @param State $appState + * @param string $scope + */ + public function __construct(ScopeConfigInterface $scopeConfig, State $appState, $scope = 'store') + { + $this->scopeConfig = $scopeConfig; + $this->appState = $appState; + $this->scope = $scope; + } + + /** + * Check whether asset minification is on for specified content type + * + * @param string $contentType + * @return bool + */ + public function isEnabled($contentType) + { + return + $this->appState->getMode() != State::MODE_DEVELOPER && + (bool)$this->scopeConfig->isSetFlag( + sprintf(self::XML_PATH_MINIFICATION_ENABLED, $contentType), + $this->scope + ); + } + + /** + * Add 'min' suffix if minification is enabled and $filename has no one. + * + * @param string $filename + * @return string + */ + public function addMinifiedSign($filename) + { + $extension = pathinfo($filename, PATHINFO_EXTENSION); + + if ( + $this->isEnabled($extension) && + !$this->isExcluded($filename) && + !$this->isMinifiedFilename($filename) + ) { + $filename = substr($filename, 0, -strlen($extension)) . 'min.' . $extension; + } + return $filename; + } + + /** + * Remove 'min' suffix if exists and minification is enabled + * + * @param string $filename + * @return string + */ + public function removeMinifiedSign($filename) + { + $extension = pathinfo($filename, PATHINFO_EXTENSION); + + if ( + $this->isEnabled($extension) && + !$this->isExcluded($filename) && + $this->isMinifiedFilename($filename) + ) { + $filename = substr($filename, 0, -strlen($extension) - 4) . $extension; + } + return $filename; + } + + /** + * @param string $filename + * @return bool + */ + public function isMinifiedFilename($filename) + { + return substr($filename, strrpos($filename, '.') - 4, 5) == '.min.'; + } + + /** + * @param string $filename + * @return boolean + */ + public function isExcluded($filename) + { + foreach ($this->getExcludes(pathinfo($filename, PATHINFO_EXTENSION)) as $exclude) { + if (preg_match('/' . str_replace('/', '\/', $exclude) . '/', $filename)) { + return true; + } + } + return false; + } + + /** + * @param string $contentType + * @return string[] + */ + public function getExcludes($contentType) + { + if (!isset($this->excludes[$contentType])) { + $this->excludes[$contentType] = []; + $key = sprintf(self::XML_PATH_MINIFICATION_EXCLUDES, $contentType); + foreach (explode("\n", $this->scopeConfig->getValue($key, $this->scope)) as $exclude) { + if (trim($exclude) != '') { + $this->excludes[$contentType][] = trim($exclude); + } + }; + } + return $this->excludes[$contentType]; + } +} diff --git a/lib/internal/Magento/Framework/View/Asset/Minified/AbstractAsset.php b/lib/internal/Magento/Framework/View/Asset/Minified/AbstractAsset.php deleted file mode 100644 index bbfa28664ed345a80e178071ee967ecbe281aca3..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Asset/Minified/AbstractAsset.php +++ /dev/null @@ -1,336 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\View\Asset\Minified; - -use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\View\Asset\MergeableInterface; -use Magento\Framework\View\Asset\LocalInterface; -use \Magento\Framework\Phrase; - -/** - * Minified page asset - */ -abstract class AbstractAsset implements MergeableInterface -{ - /**#@+ - * Strategies for verifying whether the files need to be minified - */ - const FILE_EXISTS = 'file_exists'; - const MTIME = 'mtime'; - /**#@-*/ - - /** - * Directory for dynamically generated public view files, relative to STATIC_VIEW - */ - const CACHE_VIEW_REL = '_cache'; - - /** - * LocalInterface - * - * @var LocalInterface - */ - protected $originalAsset; - - /** - * @var string - */ - protected $strategy; - - /** - * File - * - * @var string - */ - protected $file; - - /** - * Relative path to the file - * - * @var string - */ - protected $path; - - /** - * @var string - */ - protected $filePath; - - /** - * @var \Magento\Framework\View\Asset\File\Context - */ - protected $context; - - /** - * URL - * - * @var string - */ - protected $url; - - /** - * @var \Magento\Framework\Code\Minifier\AdapterInterface - */ - protected $adapter; - - /** - * Logger - * - * @var \Psr\Log\LoggerInterface - */ - protected $logger; - - /** - * Directory object for root directory - * - * @var \Magento\Framework\Filesystem\Directory\ReadInterface - */ - protected $rootDir; - - /** - * Directory object for static view directory - * - * @var \Magento\Framework\Filesystem\Directory\ReadInterface - */ - protected $staticViewDir; - - /** - * Url configuration - * - * @var \Magento\Framework\UrlInterface - */ - protected $baseUrl; - - /** - * Constructor - * - * @param LocalInterface $asset - * @param \Psr\Log\LoggerInterface $logger - * @param \Magento\Framework\Filesystem $filesystem - * @param \Magento\Framework\UrlInterface $baseUrl - * @param \Magento\Framework\Code\Minifier\AdapterInterface $adapter - * @param string $strategy - */ - public function __construct( - LocalInterface $asset, - \Psr\Log\LoggerInterface $logger, - \Magento\Framework\Filesystem $filesystem, - \Magento\Framework\UrlInterface $baseUrl, - \Magento\Framework\Code\Minifier\AdapterInterface $adapter, - $strategy = self::FILE_EXISTS - ) { - $this->originalAsset = $asset; - $this->strategy = $strategy; - $this->logger = $logger; - $this->rootDir = $filesystem->getDirectoryRead(DirectoryList::ROOT); - $this->staticViewDir = $filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); - $this->baseUrl = $baseUrl; - $this->adapter = $adapter; - } - - /** - * {@inheritdoc} - */ - public function getUrl() - { - if (empty($this->url)) { - $this->process(); - } - return $this->url; - } - - /** - * {@inheritdoc} - */ - public function getContentType() - { - return $this->originalAsset->getContentType(); - } - - /** - * {@inheritdoc} - */ - public function getSourceFile() - { - if (empty($this->file)) { - $this->process(); - } - return $this->file; - } - - /** - * {@inheritdoc} - */ - public function getPath() - { - if (empty($this->path)) { - $this->process(); - } - return $this->path; - } - - /** - * {@inheritdoc} - */ - public function getFilePath() - { - if (null === $this->filePath) { - $this->process(); - } - return $this->filePath; - } - - /** - * {@inheritdoc} - */ - public function getContext() - { - if (null === $this->context) { - $this->process(); - } - return $this->context; - } - - /** - * {@inheritdoc} - */ - public function getModule() - { - return $this->originalAsset->getModule(); - } - - /** - * {@inheritdoc} - */ - public function getContent() - { - return $this->staticViewDir->readFile($this->getPath()); - } - - /** - * Minify content of child asset - * - * @return void - */ - protected function process() - { - if ($this->isFileMinified($this->originalAsset->getPath())) { - $this->fillPropertiesByOriginalAsset(); - } elseif ($this->hasPreminifiedFile($this->originalAsset->getSourceFile())) { - $this->fillPropertiesByOriginalAssetWithMin(); - } else { - try { - $this->fillPropertiesByMinifyingAsset(); - } catch (\Exception $e) { - $this->logger->critical( - new \Magento\Framework\Exception\LocalizedException( - new Phrase('Could not minify file: %1', [$this->originalAsset->getSourceFile()]), - $e - ) - ); - $this->fillPropertiesByOriginalAsset(); - } - } - } - - /** - * Check, whether file is already minified - * - * @param string $fileName - * @return bool - */ - protected function isFileMinified($fileName) - { - return (bool)preg_match('#\.min\.\w+$#', $fileName); - } - - /** - * Check, whether the file has its preminified version in the same directory - * - * @param string $fileName - * @return bool - */ - protected function hasPreminifiedFile($fileName) - { - $minifiedFile = $this->composeMinifiedName($fileName); - return $this->rootDir->isExist($this->rootDir->getRelativePath($minifiedFile)); - } - - /** - * Compose path to a preminified file in the same folder out of path to an original file - * - * @param string $fileName - * @return string - */ - protected function composeMinifiedName($fileName) - { - return preg_replace('/\\.([^.]*)$/', '.min.$1', $fileName); - } - - /** - * Fill the properties by bare copying properties from original asset - * - * @return void - */ - protected function fillPropertiesByOriginalAsset() - { - $this->file = $this->originalAsset->getSourceFile(); - $this->path = $this->originalAsset->getPath(); - $this->filePath = $this->originalAsset->getFilePath(); - $this->context = $this->originalAsset->getContext(); - $this->url = $this->originalAsset->getUrl(); - - $isExists = $this->staticViewDir->isExist($this->originalAsset->getPath()); - if (!$isExists) { - $this->staticViewDir->writeFile($this->originalAsset->getPath(), $this->originalAsset->getContent()); - } - } - - /** - * Fill the properties by copying properties from original asset and adding '.min' inside them - * - * @return void - */ - protected function fillPropertiesByOriginalAssetWithMin() - { - $this->file = $this->composeMinifiedName($this->originalAsset->getSourceFile()); - $this->path = $this->composeMinifiedName($this->originalAsset->getPath()); - $this->filePath = $this->composeMinifiedName($this->originalAsset->getFilePath()); - $this->context = $this->originalAsset->getContext(); - $this->url = $this->composeMinifiedName($this->originalAsset->getUrl()); - } - - /** - * Perform actual minification - * - * @return void - */ - protected function minify() - { - $isExists = $this->staticViewDir->isExist($this->path); - if (!$isExists) { - $shouldMinify = true; - } elseif ($this->strategy == self::FILE_EXISTS) { - $shouldMinify = false; - } else { - $origlFile = $this->rootDir->getRelativePath($this->originalAsset->getSourceFile()); - $origMtime = $this->rootDir->stat($origlFile)['mtime']; - $minMtime = $this->staticViewDir->stat($this->path)['mtime']; - $shouldMinify = $origMtime != $minMtime; - } - if ($shouldMinify) { - $content = $this->adapter->minify($this->originalAsset->getContent()); - $this->staticViewDir->writeFile($this->path, $content); - } - } - - /** - * Generate minified file and fill the properties to reference that file - * - * @return void - */ - abstract protected function fillPropertiesByMinifyingAsset(); -} diff --git a/lib/internal/Magento/Framework/View/Asset/Minified/ImmutablePathAsset.php b/lib/internal/Magento/Framework/View/Asset/Minified/ImmutablePathAsset.php deleted file mode 100644 index b3e298892bfc4a4a2bbf8c1f5a9119b13c9c03c0..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Asset/Minified/ImmutablePathAsset.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\View\Asset\Minified; - -class ImmutablePathAsset extends AbstractAsset -{ - - /** - * Generate minified file and fill the properties to reference that file - * - * @return void - */ - protected function fillPropertiesByMinifyingAsset() - { - $this->context = $this->originalAsset->getContext(); - $this->filePath = $this->originalAsset->getFilePath(); - $this->path = $this->originalAsset->getPath(); - $this->minify(); - $this->file = $this->staticViewDir->getAbsolutePath($this->path); - $this->url = $this->context->getBaseUrl() . $this->path; - } -} diff --git a/lib/internal/Magento/Framework/View/Asset/Minified/MutablePathAsset.php b/lib/internal/Magento/Framework/View/Asset/Minified/MutablePathAsset.php deleted file mode 100644 index f31e2ef7a0b2ab62429ded00542ba28f2876e5d9..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Asset/Minified/MutablePathAsset.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\View\Asset\Minified; - -use Magento\Framework\App\Filesystem\DirectoryList; - -class MutablePathAsset extends AbstractAsset -{ - /** - * Generate minified file and fill the properties to reference that file - * - * @return void - */ - protected function fillPropertiesByMinifyingAsset() - { - $path = $this->originalAsset->getPath(); - $this->context = new \Magento\Framework\View\Asset\File\Context( - $this->baseUrl->getBaseUrl(['_type' => \Magento\Framework\UrlInterface::URL_TYPE_STATIC]), - DirectoryList::STATIC_VIEW, - self::CACHE_VIEW_REL . '/minified' - ); - $this->filePath = md5($path) . '_' . $this->composeMinifiedName(basename($path)); - $this->path = $this->context->getPath() . '/' . $this->filePath; - $this->minify(); - $this->file = $this->staticViewDir->getAbsolutePath($this->path); - $this->url = $this->context->getBaseUrl() . $this->path; - } -} diff --git a/lib/internal/Magento/Framework/View/Asset/MinifyService.php b/lib/internal/Magento/Framework/View/Asset/MinifyService.php deleted file mode 100644 index 7d5720fb4a8d618c5056106df90c30638da18efb..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Asset/MinifyService.php +++ /dev/null @@ -1,170 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\View\Asset; - -/** - * Service model responsible for configuration of minified asset - */ -class MinifyService -{ - /** - * Config - * - * @var ConfigInterface - */ - protected $config; - - /** - * ObjectManager - * - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $objectManager; - - /** - * Enabled - * - * @var array - */ - protected $enabled = []; - - /** - * @var \Magento\Framework\Code\Minifier\AdapterInterface[] - */ - protected $adapters = []; - - /** - * @var string - */ - protected $appMode; - - /** - * Constructor - * - * @param ConfigInterface $config - * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param string $appMode - */ - public function __construct( - ConfigInterface $config, - \Magento\Framework\ObjectManagerInterface $objectManager, - $appMode = \Magento\Framework\App\State::MODE_DEFAULT - ) { - $this->config = $config; - $this->objectManager = $objectManager; - $this->appMode = $appMode; - } - - /** - * Get filtered assets - * Assets applicable for minification are wrapped with the minified asset - * - * @param array|\Iterator $assets - * @param bool $isDirectRequest - * @return Minified\AbstractAsset[] - */ - public function getAssets($assets, $isDirectRequest = false) - { - $resultAssets = []; - $strategy = $this->appMode == \Magento\Framework\App\State::MODE_PRODUCTION - ? Minified\AbstractAsset::FILE_EXISTS : Minified\AbstractAsset::MTIME; - /** @var $asset AssetInterface */ - foreach ($assets as $asset) { - if ($this->isEnabled($asset->getContentType())) { - $asset = $this->getAssetDecorated($asset, $strategy, $isDirectRequest); - } - $resultAssets[] = $asset; - } - return $resultAssets; - } - - /** - * Check if minification is enabled for specified content type - * - * @param string $contentType - * @return bool - */ - protected function isEnabled($contentType) - { - if (!isset($this->enabled[$contentType])) { - $this->enabled[$contentType] = $this->config->isAssetMinification($contentType); - } - return $this->enabled[$contentType]; - } - - /** - * Get minification adapter by specified content type - * - * @param string $contentType - * @return \Magento\Framework\Code\Minifier\AdapterInterface - * @throws \Magento\Framework\Exception\LocalizedException - */ - protected function getAdapter($contentType) - { - if (!isset($this->adapters[$contentType])) { - $adapterClass = $this->config->getAssetMinificationAdapter($contentType); - if (!$adapterClass) { - throw new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase( - "Minification adapter is not specified for '%1' content type", - [$contentType] - ) - ); - } - $adapter = $this->objectManager->get($adapterClass); - if (!($adapter instanceof \Magento\Framework\Code\Minifier\AdapterInterface)) { - $type = get_class($adapter); - throw new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase( - "Invalid adapter: '%1'. Expected: \\Magento\\Framework\\Code\\Minifier\\AdapterInterface", - [$type] - ) - ); - } - $this->adapters[$contentType] = $adapter; - } - return $this->adapters[$contentType]; - } - - /** - * Returns asset decorated by corresponding minifier - * - * @param AssetInterface $asset - * @param string $strategy - * @param bool $isDirectRequest - * @return AssetInterface - * @throws \Magento\Framework\Exception\LocalizedException - */ - protected function getAssetDecorated(AssetInterface $asset, $strategy, $isDirectRequest) - { - return - $this->objectManager->create( - $this->getDecoratorClass($asset, $isDirectRequest), - [ - 'asset' => $asset, - 'strategy' => $strategy, - 'adapter' => $this->getAdapter($asset->getContentType()) - ] - ); - } - - /** - * Returns minifier decorator class name for given asset - * - * @param AssetInterface $asset - * @param bool $isDirectRequest - * @return string - */ - protected function getDecoratorClass(AssetInterface $asset, $isDirectRequest) - { - if ($isDirectRequest || $asset->getContentType() == 'css') { - $result = 'Magento\Framework\View\Asset\Minified\ImmutablePathAsset'; - } else { - $result = 'Magento\Framework\View\Asset\Minified\MutablePathAsset'; - } - return $result; - } -} diff --git a/lib/internal/Magento/Framework/View/Asset/PreProcessor/Cache.php b/lib/internal/Magento/Framework/View/Asset/PreProcessor/Cache.php deleted file mode 100644 index 0228df175380c3d3f5de2484ab0a9e82b1827f11..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Asset/PreProcessor/Cache.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\View\Asset\PreProcessor; - -class Cache extends \Magento\Framework\Cache\Frontend\Decorator\TagScope -{ - /** - * Cache type code unique among all cache types - */ - const TYPE_IDENTIFIER = 'view_files_preprocessing'; - - /** - * Cache tag used to distinguish the cache type from all other cache - */ - const CACHE_TAG = 'VIEW_FILES_PREPROCESSING'; - - /** - * @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/Asset/PreProcessor/Chain.php b/lib/internal/Magento/Framework/View/Asset/PreProcessor/Chain.php index cf7a30b161a7b27986eba272d084eafb418732eb..eba9cad8083ca00a878e49addd780350cd791300 100644 --- a/lib/internal/Magento/Framework/View/Asset/PreProcessor/Chain.php +++ b/lib/internal/Magento/Framework/View/Asset/PreProcessor/Chain.php @@ -49,15 +49,22 @@ class Chain */ protected $targetAssetPath; + /** + * @var string + */ + protected $origAssetPath; + /** * @param LocalInterface $asset * @param string $origContent * @param string $origContentType + * @param string $origAssetPath */ public function __construct( LocalInterface $asset, $origContent, - $origContentType + $origContentType, + $origAssetPath ) { $this->asset = $asset; $this->origContent = $origContent; @@ -66,6 +73,7 @@ class Chain $this->contentType = $origContentType; $this->targetContentType = $asset->getContentType(); $this->targetAssetPath = $asset->getPath(); + $this->origAssetPath = $origAssetPath; } /** @@ -186,4 +194,13 @@ class Chain { return $this->origContentType != $this->contentType || $this->origContent != $this->content; } + + /** + * @return string + * @codeCoverageIgnore + */ + public function getOrigAssetPath() + { + return $this->origAssetPath; + } } diff --git a/lib/internal/Magento/Framework/View/Asset/PreProcessor/ChainFactory.php b/lib/internal/Magento/Framework/View/Asset/PreProcessor/ChainFactory.php index e817380eff140e92907eb8ffdc453495e0158d86..65fcceecb20696f9e6dde3d044712e0c7421b242 100644 --- a/lib/internal/Magento/Framework/View/Asset/PreProcessor/ChainFactory.php +++ b/lib/internal/Magento/Framework/View/Asset/PreProcessor/ChainFactory.php @@ -7,6 +7,10 @@ namespace Magento\Framework\View\Asset\PreProcessor; use Magento\Framework\ObjectManagerInterface; +/** + * Factory for Magento\Framework\View\Asset\PreProcessor\Chain + * @codeCoverageIgnore + */ class ChainFactory implements ChainFactoryInterface { /** @@ -14,30 +18,21 @@ class ChainFactory implements ChainFactoryInterface * * @var ObjectManagerInterface */ - private $_objectManager; + private $objectManager; /** * @param ObjectManagerInterface $objectManager */ - public function __construct( - ObjectManagerInterface $objectManager - ) { - $this->_objectManager = $objectManager; + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; } /** - * {inheritdoc} + * {@inheritdoc} */ public function create(array $arguments = []) { - $arguments = array_intersect_key( - $arguments, - [ - 'asset' => 'asset', - 'origContent' => 'origContent', - 'origContentType' => 'origContentType' - ] - ); - return $this->_objectManager->create('Magento\Framework\View\Asset\PreProcessor\Chain', $arguments); + return $this->objectManager->create(Chain::class, $arguments); } } diff --git a/lib/internal/Magento/Framework/View/Asset/PreProcessor/Minify.php b/lib/internal/Magento/Framework/View/Asset/PreProcessor/Minify.php new file mode 100644 index 0000000000000000000000000000000000000000..8a023237601c3111e488dd936699dee035f79c21 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Asset/PreProcessor/Minify.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Asset\PreProcessor; + +use Magento\Framework\Code\Minifier\AdapterInterface; +use Magento\Framework\View\Asset\Minification; +use Magento\Framework\View\Asset\PreProcessor; +use Magento\Framework\View\Asset\PreProcessorInterface; + +/** + * Assets minification pre-processor + */ +class Minify implements PreProcessorInterface +{ + /** + * @var AdapterInterface + */ + protected $adapter; + + /** + * @var Minification + */ + protected $minification; + + /** + * @param AdapterInterface $adapter + * @param Minification $minification + */ + public function __construct(AdapterInterface $adapter, Minification $minification) + { + $this->adapter = $adapter; + $this->minification = $minification; + } + + /** + * Transform content and/or content type for the specified preprocessing chain object + * + * @param PreProcessor\Chain $chain + * @return void + */ + public function process(PreProcessor\Chain $chain) + { + if ( + $this->minification->isEnabled(pathinfo($chain->getTargetAssetPath(), PATHINFO_EXTENSION)) && + $this->minification->isMinifiedFilename($chain->getTargetAssetPath()) && + !$this->minification->isMinifiedFilename($chain->getOrigAssetPath()) + ) { + $content = $this->adapter->minify($chain->getContent()); + $chain->setContent($content); + } + } +} diff --git a/lib/internal/Magento/Framework/View/Asset/RemoteFactory.php b/lib/internal/Magento/Framework/View/Asset/RemoteFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..854fdbc5114c228e31d56161bd27d55b007956fc --- /dev/null +++ b/lib/internal/Magento/Framework/View/Asset/RemoteFactory.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Asset; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Factory class for \Magento\Framework\View\Asset\Remote + */ +class RemoteFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return \Magento\Framework\View\Asset\Remote + */ + public function create(array $data = []) + { + return $this->objectManager->create(Remote::class, $data); + } +} diff --git a/lib/internal/Magento/Framework/View/Asset/Repository.php b/lib/internal/Magento/Framework/View/Asset/Repository.php index 4b6801310a3758ad679dba0cefa1128d7c24e47d..d227c5856e0bd68b70aa789dbe0e93442a827480 100644 --- a/lib/internal/Magento/Framework/View/Asset/Repository.php +++ b/lib/internal/Magento/Framework/View/Asset/Repository.php @@ -56,25 +56,56 @@ class Repository */ private $defaults = null; + /** + * @var FileFactory + */ + private $fileFactory; + + /** + * @var File\FallbackContextFactory + */ + private $fallbackContextFactory; + + /** + * @var File\ContextFactory + */ + private $contextFactory; + /** + * @var RemoteFactory + */ + private $remoteFactory; + /** * @param \Magento\Framework\UrlInterface $baseUrl * @param \Magento\Framework\View\DesignInterface $design * @param \Magento\Framework\View\Design\Theme\ListInterface $themeList * @param \Magento\Framework\View\Asset\Source $assetSource * @param \Magento\Framework\App\Request\Http $request + * @param FileFactory $fileFactory + * @param File\FallbackContextFactory $fallbackContextFactory + * @param File\ContextFactory $contextFactory + * @param RemoteFactory $remoteFactory */ public function __construct( \Magento\Framework\UrlInterface $baseUrl, \Magento\Framework\View\DesignInterface $design, \Magento\Framework\View\Design\Theme\ListInterface $themeList, \Magento\Framework\View\Asset\Source $assetSource, - \Magento\Framework\App\Request\Http $request + \Magento\Framework\App\Request\Http $request, + FileFactory $fileFactory, + File\FallbackContextFactory $fallbackContextFactory, + File\ContextFactory $contextFactory, + RemoteFactory $remoteFactory ) { $this->baseUrl = $baseUrl; $this->design = $design; $this->themeList = $themeList; $this->assetSource = $assetSource; $this->request = $request; + $this->fileFactory = $fileFactory; + $this->fallbackContextFactory = $fallbackContextFactory; + $this->contextFactory = $contextFactory; + $this->remoteFactory = $remoteFactory; } /** @@ -160,12 +191,14 @@ class Repository $themePath, $params['locale'] ); - return new File( - $this->assetSource, - $context, - $filePath, - $module, - $this->assetSource->getContentType($filePath) + return $this->fileFactory->create( + [ + 'source' => $this->assetSource, + 'context' => $context, + 'filePath' => $filePath, + 'module' => $module, + 'contentType' => $this->assetSource->getContentType($filePath) + ] ); } @@ -208,12 +241,14 @@ class Repository $id = implode('|', [$baseDirType, $urlType, $secureKey, $area, $themePath, $locale]); if (!isset($this->fallbackContext[$id])) { $url = $this->baseUrl->getBaseUrl(['_type' => $urlType, '_secure' => $isSecure]); - $this->fallbackContext[$id] = new \Magento\Framework\View\Asset\File\FallbackContext( - $url, - $area, - $themePath, - $locale, - $isSecure + $this->fallbackContext[$id] = $this->fallbackContextFactory->create( + [ + 'baseUrl' => $url, + 'areaType' => $area, + 'themePath' => $themePath, + 'localeCode' => $locale, + 'isSecure' => $isSecure + ] ); } return $this->fallbackContext[$id]; @@ -232,12 +267,14 @@ class Repository if (!$module) { $module = $similarTo->getModule(); } - return new File( - $this->assetSource, - $similarTo->getContext(), - $filePath, - $module, - $this->assetSource->getContentType($filePath) + return $this->fileFactory->create( + [ + 'source' => $this->assetSource, + 'context' => $similarTo->getContext(), + 'filePath' => $filePath, + 'module' => $module, + 'contentType' => $this->assetSource->getContentType($filePath) + ] ); } @@ -261,7 +298,15 @@ class Repository ) { $context = $this->getFileContext($baseDirType, $baseUrlType, $dirPath); $contentType = $this->assetSource->getContentType($filePath); - return new File($this->assetSource, $context, $filePath, '', $contentType); + return $this->fileFactory->create( + [ + 'source' => $this->assetSource, + 'context' => $context, + 'filePath' => $filePath, + 'module' => '', + 'contentType' => $contentType + ] + ); } /** @@ -279,7 +324,9 @@ class Repository $id = implode('|', [$baseDirType, $urlType, $dirPath]); if (!isset($this->fileContext[$id])) { $url = $this->baseUrl->getBaseUrl(['_type' => $urlType]); - $this->fileContext[$id] = new \Magento\Framework\View\Asset\File\Context($url, $baseDirType, $dirPath); + $this->fileContext[$id] = $this->contextFactory->create( + ['baseUrl' => $url, 'baseDirType' => $baseDirType, 'contextPath' => $dirPath] + ); } return $this->fileContext[$id]; } @@ -307,10 +354,11 @@ class Repository * @param string $url * @param string $contentType * @return Remote + * @codeCoverageIgnore */ public function createRemoteAsset($url, $contentType) { - return new Remote($url, $contentType); + return $this->remoteFactory->create(['url' => $url, 'contentType' => $contentType]); } /** diff --git a/lib/internal/Magento/Framework/View/Asset/Source.php b/lib/internal/Magento/Framework/View/Asset/Source.php index 0137d64d7b66239f8658dbc199d7c5740c723685..f3518c2fc3022994c9e14f9280908b5ad01d669b 100644 --- a/lib/internal/Magento/Framework/View/Asset/Source.php +++ b/lib/internal/Magento/Framework/View/Asset/Source.php @@ -22,11 +22,6 @@ class Source */ private $filesystem; - /** - * @var \Magento\Framework\View\Asset\PreProcessor\Cache - */ - protected $cache; - /** * @var \Magento\Framework\Filesystem\Directory\ReadInterface */ @@ -58,7 +53,6 @@ class Source private $chainFactory; /** - * @param PreProcessor\Cache $cache * @param \Magento\Framework\Filesystem $filesystem * @param PreProcessor\Pool $preProcessorPool * @param \Magento\Framework\View\Design\FileResolution\Fallback\StaticFile $fallback @@ -66,14 +60,12 @@ class Source * @param ChainFactoryInterface $chainFactory */ public function __construct( - PreProcessor\Cache $cache, \Magento\Framework\Filesystem $filesystem, PreProcessor\Pool $preProcessorPool, \Magento\Framework\View\Design\FileResolution\Fallback\StaticFile $fallback, \Magento\Framework\View\Design\Theme\ListInterface $themeList, ChainFactoryInterface $chainFactory ) { - $this->cache = $cache; $this->filesystem = $filesystem; $this->rootDir = $filesystem->getDirectoryRead(DirectoryList::ROOT); $this->varDir = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR); @@ -122,7 +114,7 @@ class Source * - directory code where the file is supposed to be found * - relative path to the file * - * Automatically caches the obtained successful results or returns false if source file was not found + * returns false if source file was not found * * @param LocalInterface $asset * @return array|bool @@ -130,17 +122,8 @@ class Source private function preProcess(LocalInterface $asset) { $sourceFile = $this->findSourceFile($asset); - if ($sourceFile !== false) { - $path = $this->rootDir->getRelativePath($sourceFile); - } else { - // No original file, the resulting file may be generated by a pre-processor - $path = false; - } - $cacheId = $path . ':' . $asset->getPath(); - $cached = $this->cache->load($cacheId); - if ($cached) { - return unserialize($cached); - } + $dirCode = DirectoryList::ROOT; + $path = $this->rootDir->getRelativePath($sourceFile); $chain = $this->createChain($asset, $path); $this->preProcessorPool->process($chain); @@ -152,7 +135,6 @@ class Source $this->varDir->writeFile($path, $chain->getContent()); } $result = [$dirCode, $path]; - $this->cache->save(serialize($result), $cacheId); return $result; } diff --git a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Cache.php b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Cache.php deleted file mode 100644 index b68048f05c1c2641aa0b143ee1378be843257f11..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Cache.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\View\Design\FileResolution\Fallback; - -class Cache extends \Magento\Framework\Cache\Frontend\Decorator\TagScope -{ - /** - * Cache type code unique among all cache types - */ - const TYPE_IDENTIFIER = 'view_files_fallback'; - - /** - * Cache tag used to distinguish the cache type from all other cache - */ - const CACHE_TAG = 'VIEW_FILES_FALLBACK'; - - /** - * @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/Design/FileResolution/Fallback/CacheData/Flat.php b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/CacheData/Flat.php deleted file mode 100644 index f221a84dd78ef57dec894e12aa47549847dae7dc..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/CacheData/Flat.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\View\Design\FileResolution\Fallback\CacheData; - -use Magento\Framework\View\Design\FileResolution\Fallback; - -class Flat implements Fallback\CacheDataInterface -{ - /** - * @var Fallback\Cache - */ - private $cache; - - /** - * @param Fallback\Cache $cache - */ - public function __construct(Fallback\Cache $cache) - { - $this->cache = $cache; - } - - /** - * {@inheritdoc} - */ - public function getFromCache($type, $file, $area, $themePath, $locale, $module) - { - $cacheId = $this->getCacheId($type, $file, $area, $themePath, $locale, $module); - return $this->cache->load($cacheId); - } - - /** - * {@inheritdoc} - */ - public function saveToCache($value, $type, $file, $area, $themePath, $locale, $module) - { - $cacheId = $this->getCacheId($type, $file, $area, $themePath, $locale, $module); - return $this->cache->save($value, $cacheId); - } - - /** - * Generate cache ID - * - * @param string $type - * @param string $file - * @param string $area - * @param string $themePath - * @param string $locale - * @param string $module - * @return string - */ - protected function getCacheId($type, $file, $area, $themePath, $locale, $module) - { - return sprintf( - "type:%s|area:%s|theme:%s|locale:%s|module:%s|file:%s", - $type, - $area, - $themePath, - $locale, - $module, - $file - ); - } -} diff --git a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/CacheData/Grouped.php b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/CacheData/Grouped.php deleted file mode 100644 index f53376f99f4064cf364d9c1ccbd898acf8600ebb..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/CacheData/Grouped.php +++ /dev/null @@ -1,125 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\View\Design\FileResolution\Fallback\CacheData; - -use Magento\Framework\View\Design\FileResolution\Fallback; - -class Grouped implements Fallback\CacheDataInterface -{ - /** - * @var Fallback\Cache - */ - private $cache; - - /** - * @var string[] - */ - private $isDirty = []; - - /** - * @var array - */ - private $cacheSections = []; - - /** - * @param Fallback\Cache $cache - */ - public function __construct(Fallback\Cache $cache) - { - $this->cache = $cache; - } - - /** - * {@inheritdoc} - */ - public function getFromCache($type, $file, $area, $themePath, $locale, $module) - { - $sectionId = $this->getCacheSectionId($type, $area, $themePath, $locale); - $this->loadSection($sectionId); - $recordId = $this->getCacheRecordId($file, $module); - if (!isset($this->cacheSections[$sectionId][$recordId])) { - $this->cacheSections[$sectionId][$recordId] = false; - } - return $this->cacheSections[$sectionId][$recordId]; - } - - /** - * {@inheritdoc} - */ - public function saveToCache($value, $type, $file, $area, $themePath, $locale, $module) - { - $sectionId = $this->getCacheSectionId($type, $area, $themePath, $locale); - $this->loadSection($sectionId); - $recordId = $this->getCacheRecordId($file, $module); - if (!isset($this->cacheSections[$sectionId][$recordId]) - || $this->cacheSections[$sectionId][$recordId] !== $value) { - $this->isDirty[$sectionId] = $sectionId; - $this->cacheSections[$sectionId][$recordId] = $value; - } - return true; - } - - /** - * @param string $sectionId - * @return void - */ - private function loadSection($sectionId) - { - if (!isset($this->cacheSections[$sectionId])) { - $value = $this->cache->load($sectionId); - if ($value) { - $this->cacheSections[$sectionId] = json_decode($value, true); - } else { - $this->cacheSections[$sectionId] = []; - } - } - } - - /** - * Generate section ID - * - * @param string $type - * @param string $area - * @param string $themePath - * @param string $locale - * - * @return string - */ - protected function getCacheSectionId($type, $area, $themePath, $locale) - { - return sprintf( - "type:%s|area:%s|theme:%s|locale:%s", - $type, - $area, - $themePath, - $locale - ); - } - - /** - * Generate record ID - * - * @param string $file - * @param string $module - * @return string - */ - protected function getCacheRecordId($file, $module) - { - return sprintf("module:%s|file:%s", $module, $file); - } - - /** - * Save cache - */ - public function __destruct() - { - foreach ($this->isDirty as $sectionId) { - $value = json_encode($this->cacheSections[$sectionId]); - $this->cache->save($value, $sectionId); - } - } -} diff --git a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/CacheDataInterface.php b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/CacheDataInterface.php deleted file mode 100644 index 31982b9da6e6f99fa4aca88f162a2c7d9a4c5be8..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/CacheDataInterface.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\View\Design\FileResolution\Fallback; - -interface CacheDataInterface -{ - /** - * Retrieve cached value by file name and parameters - * - * @param string $type - * @param string $file - * @param string $area - * @param string $themePath - * @param string $locale - * @param string $module - * @return string - */ - public function getFromCache($type, $file, $area, $themePath, $locale, $module); - - /** - * Save value to cache as unique to file name and parameters - * - * @param string $value - * @param string $type - * @param string $file - * @param string $area - * @param string $themePath - * @param string $locale - * @param string $module - * @return bool - */ - public function saveToCache($value, $type, $file, $area, $themePath, $locale, $module); -} diff --git a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Alternative.php b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Alternative.php index a7bb4b7e2e041c2d8f24fb31d4688553fa863325..f943656b1cd92a2a0da9803d84a129a3593b3c6e 100644 --- a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Alternative.php +++ b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Alternative.php @@ -25,14 +25,11 @@ class Alternative extends Simple * * @param Filesystem $filesystem * @param \Magento\Framework\View\Design\Fallback\RulePool $rulePool - * @param Fallback\CacheDataInterface $cache * @param array $alternativeExtensions - * @throws \InvalidArgumentException */ public function __construct( Filesystem $filesystem, \Magento\Framework\View\Design\Fallback\RulePool $rulePool, - Fallback\CacheDataInterface $cache, array $alternativeExtensions ) { foreach ($alternativeExtensions as $extension => $newExtensions) { @@ -44,7 +41,7 @@ class Alternative extends Simple } } $this->alternativeExtensions = $alternativeExtensions; - parent::__construct($filesystem, $rulePool, $cache); + parent::__construct($filesystem, $rulePool); } /** diff --git a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Minification.php b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Minification.php new file mode 100644 index 0000000000000000000000000000000000000000..277342b01bbcf627d22c8ed962b2cb121db7fb95 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Minification.php @@ -0,0 +1,60 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Design\FileResolution\Fallback\Resolver; + +use Magento\Framework\View\Asset\Minification as AssetMinification; +use Magento\Framework\View\Design\FileResolution\Fallback\ResolverInterface; +use Magento\Framework\View\Design\ThemeInterface; + +/** + * Resolver for minified asset, when minified is requested but not found + */ +class Minification implements ResolverInterface +{ + /** + * @var ResolverInterface + */ + protected $fallback; + + /** + * @var array + */ + protected $extensions; + + /** + * @var AssetMinification + */ + private $minification; + + /** + * @param ResolverInterface $fallback + * @param AssetMinification $minification + */ + public function __construct(ResolverInterface $fallback, AssetMinification $minification) + { + $this->fallback = $fallback; + $this->minification = $minification; + } + /** + * Get path of file after using fallback rules + * + * @param string $type + * @param string $file + * @param string|null $area + * @param ThemeInterface|null $theme + * @param string|null $locale + * @param string|null $module + * @return string|false + */ + public function resolve($type, $file, $area = null, ThemeInterface $theme = null, $locale = null, $module = null) + { + $path = $this->fallback->resolve($type, $file, $area, $theme, $locale, $module); + if (!$path && $file != ($newFile = $this->minification->removeMinifiedSign($file))) { + $path = $this->fallback->resolve($type, $newFile, $area, $theme, $locale, $module); + } + return $path; + } +} diff --git a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Simple.php b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Simple.php index 12c9195c179da84d743067a49373f362cdc91a56..89f5f45fd1ba3d07bcb823889c316e13cf2dae8d 100644 --- a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Simple.php +++ b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/Resolver/Simple.php @@ -36,13 +36,11 @@ class Simple implements Fallback\ResolverInterface * * @param Filesystem $filesystem * @param RulePool $rulePool - * @param Fallback\CacheDataInterface $cache */ - public function __construct(Filesystem $filesystem, RulePool $rulePool, Fallback\CacheDataInterface $cache) + public function __construct(Filesystem $filesystem, RulePool $rulePool) { $this->rootDirectory = $filesystem->getDirectoryRead(DirectoryList::ROOT); $this->rulePool = $rulePool; - $this->cache = $cache; } /** @@ -51,25 +49,18 @@ class Simple implements Fallback\ResolverInterface public function resolve($type, $file, $area = null, ThemeInterface $theme = null, $locale = null, $module = null) { self::assertFilePathFormat($file); - $themePath = $theme ? $theme->getThemePath() : ''; - $path = $this->cache->getFromCache($type, $file, $area, $themePath, $locale, $module); - if (false !== $path) { - $path = $path ? $this->rootDirectory->getAbsolutePath($path) : false; - } else { - $params = ['area' => $area, 'theme' => $theme, 'locale' => $locale]; - foreach ($params as $key => $param) { - if ($param === null) { - unset($params[$key]); - } - } - if (!empty($module)) { - list($params['namespace'], $params['module']) = explode('_', $module, 2); - } - $path = $this->resolveFile($this->rulePool->getRule($type), $file, $params); - $cachedValue = $path ? $this->rootDirectory->getRelativePath($path) : ''; - $this->cache->saveToCache($cachedValue, $type, $file, $area, $themePath, $locale, $module); + $params = ['area' => $area, 'theme' => $theme, 'locale' => $locale]; + foreach ($params as $key => $param) { + if ($param === null) { + unset($params[$key]); + } } + if (!empty($module)) { + list($params['namespace'], $params['module']) = explode('_', $module, 2); + } + $path = $this->resolveFile($this->rulePool->getRule($type), $file, $params); + return $path; } diff --git a/lib/internal/Magento/Framework/View/Page/Config/Renderer.php b/lib/internal/Magento/Framework/View/Page/Config/Renderer.php index 0f3b7cdf09f8d87cfc17acb8591a5e146a86bc34..590ad0369e25cb80dacb3f65fce4b6082639e539 100644 --- a/lib/internal/Magento/Framework/View/Page/Config/Renderer.php +++ b/lib/internal/Magento/Framework/View/Page/Config/Renderer.php @@ -25,11 +25,6 @@ class Renderer implements RendererInterface */ protected $pageConfig; - /** - * @var \Magento\Framework\View\Asset\MinifyService - */ - protected $assetMinifyService; - /** * @var \Magento\Framework\View\Asset\MergeService */ @@ -57,7 +52,6 @@ class Renderer implements RendererInterface /** * @param \Magento\Framework\View\Page\Config $pageConfig - * @param \Magento\Framework\View\Asset\MinifyService $assetMinifyService * @param \Magento\Framework\View\Asset\MergeService $assetMergeService * @param \Magento\Framework\UrlInterface $urlBuilder * @param \Magento\Framework\Escaper $escaper @@ -66,7 +60,6 @@ class Renderer implements RendererInterface */ public function __construct( Config $pageConfig, - \Magento\Framework\View\Asset\MinifyService $assetMinifyService, \Magento\Framework\View\Asset\MergeService $assetMergeService, \Magento\Framework\UrlInterface $urlBuilder, \Magento\Framework\Escaper $escaper, @@ -74,7 +67,6 @@ class Renderer implements RendererInterface \Psr\Log\LoggerInterface $logger ) { $this->pageConfig = $pageConfig; - $this->assetMinifyService = $assetMinifyService; $this->assetMergeService = $assetMergeService; $this->urlBuilder = $urlBuilder; $this->escaper = $escaper; @@ -240,8 +232,7 @@ class Renderer implements RendererInterface */ protected function renderAssetGroup(\Magento\Framework\View\Asset\PropertyGroup $group) { - $groupAssets = $this->assetMinifyService->getAssets($group->getAll()); - $groupAssets = $this->processMerge($groupAssets, $group); + $groupAssets = $this->processMerge($group->getAll(), $group); $attributes = $this->getGroupAttributes($group); $attributes = $this->addDefaultAttributes( diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/Bundle/ManagerTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/Bundle/ManagerTest.php index a6a5c9eeab3932abdfefa91d8d42a478721fa8d3..30d80e64d0ac96796e7c301a42913b19d8f630ed 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/Bundle/ManagerTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/Bundle/ManagerTest.php @@ -27,6 +27,9 @@ class ManagerTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Framework\View\Asset\LocalInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $asset; + /** @var \Magento\Framework\View\Asset\Minification|\PHPUnit_Framework_MockObject_MockObject */ + private $minificationMock; + public function setUp() { $this->filesystem = $this->getMockBuilder('Magento\Framework\Filesystem') @@ -52,7 +55,17 @@ class ManagerTest extends \PHPUnit_Framework_TestCase ['getContentType'] ); - $this->manager = new Manager($this->filesystem, $this->bundle, $this->bundleConfig, $this->assetConfig); + $this->minificationMock = $this->getMockBuilder('Magento\Framework\View\Asset\Minification') + ->disableOriginalConstructor() + ->getMock(); + + $this->manager = new Manager( + $this->filesystem, + $this->bundle, + $this->bundleConfig, + $this->assetConfig, + $this->minificationMock + ); } public function testAddAssetWithInvalidType() @@ -97,9 +110,6 @@ class ManagerTest extends \PHPUnit_Framework_TestCase $this->asset->expects($this->atLeastOnce()) ->method('getFilePath') ->willReturn('file/path.js'); - $this->assetConfig->expects($this->once()) - ->method('isAssetMinification') - ->willReturn(false); $this->asset->expects($this->atLeastOnce()) ->method('getContext') ->willReturn($context); @@ -136,9 +146,6 @@ class ManagerTest extends \PHPUnit_Framework_TestCase $this->asset->expects($this->atLeastOnce()) ->method('getFilePath') ->willReturn('file/path.js'); - $this->assetConfig->expects($this->once()) - ->method('isAssetMinification') - ->willReturn(false); $this->asset->expects($this->atLeastOnce()) ->method('getContext') ->willReturn($context); @@ -175,9 +182,6 @@ class ManagerTest extends \PHPUnit_Framework_TestCase $this->asset->expects($this->atLeastOnce()) ->method('getFilePath') ->willReturn('file/path.js'); - $this->assetConfig->expects($this->once()) - ->method('isAssetMinification') - ->willReturn(false); $this->asset->expects($this->atLeastOnce()) ->method('getContext') ->willReturn($context); diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/BundleTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/BundleTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d49267b46619172e4c2b12269a7eac408bfad89f --- /dev/null +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/BundleTest.php @@ -0,0 +1,124 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\View\Test\Unit\Asset; + +use Magento\Framework\View\Asset\Bundle; + +/** + * Unit test for Magento\Framework\View\Asset\Bundle + */ +class BundleTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Framework\View\Asset\Bundle + */ + protected $bundle; + + /** + * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject + */ + protected $filesystemMock; + + /** + * @var \Magento\Framework\View\Asset\Bundle\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $bundleConfigMock; + + /** + * @var \Magento\Framework\View\Asset\Minification|\PHPUnit_Framework_MockObject_MockObject + */ + protected $minificationMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + $this->filesystemMock = $this->getMockBuilder('Magento\Framework\Filesystem') + ->disableOriginalConstructor() + ->getMock(); + $this->bundleConfigMock = $this->getMockBuilder('Magento\Framework\View\Asset\Bundle\ConfigInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->minificationMock = $this->getMockBuilder('Magento\Framework\View\Asset\Minification') + ->disableOriginalConstructor() + ->getMock(); + + $this->bundle = new Bundle( + $this->filesystemMock, + $this->bundleConfigMock, + $this->minificationMock + ); + } + + /** + * @return void + * @covers \Magento\Framework\View\Asset\Bundle::getAssetKey + * @covers \Magento\Framework\View\Asset\Bundle::save + */ + public function testMinSuffix() + { + $this->minificationMock + ->expects($this->any()) + ->method('addMinifiedSign') + ->withConsecutive( + ['onefile.js'], + ['/js/bundle/bundle0.js'] + ) + ->willReturnOnConsecutiveCalls( + 'onefile.min.js', + '/js/bundle/bundle0.min.js' + ); + + $contextMock = $this->getMockBuilder('Magento\Framework\View\Asset\File\FallbackContext') + ->disableOriginalConstructor() + ->getMock(); + $contextMock + ->expects($this->any()) + ->method('getAreaCode') + ->willReturn('area'); + $contextMock + ->expects($this->any()) + ->method('getThemePath') + ->willReturn('theme-path'); + $contextMock + ->expects($this->any()) + ->method('getLocale') + ->willReturn('locale'); + + $assetMock = $this->getMockBuilder('Magento\Framework\View\Asset\LocalInterface') + ->setMethods(['getContentType', 'getContext']) + ->getMockForAbstractClass(); + $assetMock + ->expects($this->any()) + ->method('getContext') + ->willReturn($contextMock); + $assetMock + ->expects($this->any()) + ->method('getContentType') + ->willReturn('js'); + $assetMock + ->expects($this->any()) + ->method('getFilePath') + ->willReturn('onefile.js'); + + $writeMock = $this->getMockBuilder('Magento\Framework\Filesystem\Directory\WriteInterface') + ->getMockForAbstractClass(); + $writeMock + ->expects($this->once()) + ->method('writeFile') + ->with('/js/bundle/bundle0.min.js', $this->stringContains('onefile.min.js')); + + $this->filesystemMock + ->expects($this->any()) + ->method('getDirectoryWrite') + ->willReturn($writeMock); + + $this->bundle->addAsset($assetMock); + $this->bundle->flush(); + } +} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/ConfigTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/ConfigTest.php index 891818edefe9c22d1c7d930d28fbc36c4e855775..e4c9febb485357471ca69f8317ddb3985fff3bc2 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/ConfigTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/ConfigTest.php @@ -1,17 +1,18 @@ <?php /** - * Tests Magento\Framework\View\Asset\Config - * * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -// @codingStandardsIgnoreFile - namespace Magento\Framework\View\Test\Unit\Asset; -use \Magento\Framework\View\Asset\Config; +use Magento\Framework\App\State; +use Magento\Framework\View\Asset\Config; +use Magento\Store\Model\ScopeInterface; +/** + * Tests Magento\Framework\View\Asset\Config + */ class ConfigTest extends \Magento\Framework\TestFramework\Unit\BaseTestCase { /** @@ -19,66 +20,54 @@ class ConfigTest extends \Magento\Framework\TestFramework\Unit\BaseTestCase */ private $scopeConfigMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\State + */ + private $appStateMock; + /** * @var \Magento\Framework\View\Asset\Config */ private $model; + /** + * {@inheritDoc} + */ public function setUp() { - parent::setUp(); - $this->scopeConfigMock = $this->basicMock('Magento\Framework\App\Config\ScopeConfigInterface'); - $this->model = $this->objectManager->getObject('Magento\Framework\View\Asset\Config', - ['scopeConfig' => $this->scopeConfigMock] - ); + $this->scopeConfigMock = $this->getMockBuilder('Magento\Framework\App\Config\ScopeConfigInterface') + ->getMockForAbstractClass(); + $this->appStateMock = $this->getMockBuilder('Magento\Framework\App\State') + ->disableOriginalConstructor() + ->getMock(); + $this->model = new Config($this->scopeConfigMock, $this->appStateMock); } /** + * @param bool $booleanData * @dataProvider booleanDataProvider + * @return void */ public function testIsMergeCssFiles($booleanData) { $this->scopeConfigMock->expects($this->once()) ->method('isSetFlag') - ->with(Config::XML_PATH_MERGE_CSS_FILES, \Magento\Store\Model\ScopeInterface::SCOPE_STORE) + ->with(Config::XML_PATH_MERGE_CSS_FILES, ScopeInterface::SCOPE_STORE) ->willReturn($booleanData); $this->assertSame($booleanData, $this->model->isMergeCssFiles()); } /** + * @param bool $booleanData * @dataProvider booleanDataProvider + * @return void */ public function testIsMergeJsFiles($booleanData) { $this->scopeConfigMock->expects($this->once()) ->method('isSetFlag') - ->with(Config::XML_PATH_MERGE_JS_FILES, \Magento\Store\Model\ScopeInterface::SCOPE_STORE) + ->with(Config::XML_PATH_MERGE_JS_FILES, ScopeInterface::SCOPE_STORE) ->willReturn($booleanData); $this->assertSame($booleanData, $this->model->isMergeJsFiles()); } - - public function testIsAssetMinification() - { - $contentType = 'content type'; - $this->scopeConfigMock->expects($this->once()) - ->method('isSetFlag') - ->with( - sprintf(Config::XML_PATH_MINIFICATION_ENABLED, $contentType), - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - )->willReturn(true); - $this->assertTrue($this->model->isAssetMinification($contentType)); - } - - public function testGetAssetMinificationAdapter() - { - $contentType = 'content type'; - $adapter = 'adapter'; - $this->scopeConfigMock->expects($this->once()) - ->method('getValue') - ->with( - sprintf(Config::XML_PATH_MINIFICATION_ADAPTER, $contentType), - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - )->willReturn($adapter); - $this->assertSame($adapter, $this->model->getAssetMinificationAdapter($contentType)); - } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/FileTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/FileTest.php index 7b9f17651227a1cb146c814efa20e6d0af40f569..128081901a5c97d0cee7f901429ac1cf6466feb5 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/FileTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/FileTest.php @@ -11,7 +11,7 @@ use \Magento\Framework\View\Asset\File; class FileTest extends \PHPUnit_Framework_TestCase { /** - * @var Source|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\View\Asset\Source|\PHPUnit_Framework_MockObject_MockObject */ private $source; @@ -20,6 +20,11 @@ class FileTest extends \PHPUnit_Framework_TestCase */ private $context; + /** + * @var \Magento\Framework\View\Asset\Minification|\PHPUnit_Framework_MockObject_MockObject + */ + private $minificationMock; + /** * @var File */ @@ -29,7 +34,23 @@ class FileTest extends \PHPUnit_Framework_TestCase { $this->source = $this->getMock('Magento\Framework\View\Asset\Source', [], [], '', false); $this->context = $this->getMockForAbstractClass('\Magento\Framework\View\Asset\ContextInterface'); - $this->object = new File($this->source, $this->context, 'dir/file.css', 'Magento_Module', 'css'); + $this->minificationMock = $this->getMockBuilder('Magento\Framework\View\Asset\Minification') + ->disableOriginalConstructor() + ->getMock(); + + $this->minificationMock + ->expects($this->any()) + ->method('addMinifiedSign') + ->willReturnArgument(0); + + $this->object = new File( + $this->source, + $this->context, + 'dir/file.css', + 'Magento_Module', + 'css', + $this->minificationMock + ); } public function testGetUrl() @@ -42,7 +63,7 @@ class FileTest extends \PHPUnit_Framework_TestCase public function testGetContentType() { $this->assertEquals('css', $this->object->getContentType()); - $object = new File($this->source, $this->context, '', '', 'type'); + $object = new File($this->source, $this->context, '', '', 'type', $this->minificationMock); $this->assertEquals('type', $object->getContentType()); } @@ -56,7 +77,7 @@ class FileTest extends \PHPUnit_Framework_TestCase public function testGetPath($contextPath, $module, $filePath, $expected) { $this->context->expects($this->once())->method('getPath')->will($this->returnValue($contextPath)); - $object = new File($this->source, $this->context, $filePath, $module, ''); + $object = new File($this->source, $this->context, $filePath, $module, '', $this->minificationMock); $this->assertEquals($expected, $object->getPath()); } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a5e1d4ca4389c491ce3272be720d1e603ccb26a6 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php @@ -0,0 +1,217 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\View\Test\Unit\Asset; + +use Magento\Framework\App\State; +use Magento\Framework\View\Asset\Minification; +use Magento\Store\Model\ScopeInterface; + +/** + * Unit test for Magento\Framework\View\Asset\Minification + */ +class MinificationTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Framework\View\Asset\Minification + */ + protected $minification; + + /** + * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $scopeConfigMock; + + /** + * @var \Magento\Framework\App\State|\PHPUnit_Framework_MockObject_MockObject + */ + protected $appStateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + $this->scopeConfigMock = $this->getMockBuilder('Magento\Framework\App\Config\ScopeConfigInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->appStateMock = $this->getMockBuilder('Magento\Framework\App\State') + ->disableOriginalConstructor() + ->getMock(); + + $this->minification = new Minification( + $this->scopeConfigMock, + $this->appStateMock + ); + } + + /** + * @return void + */ + public function testIsEnabled() + { + + } + + /** + * @param bool $configFlag + * @param string $appMode + * @param bool $result + * @dataProvider isEnabledDataProvider + * @return void + */ + public function testIsAssetMinification($configFlag, $appMode, $result) + { + $contentType = 'content type'; + $this->scopeConfigMock + ->expects($this->any()) + ->method('isSetFlag') + ->with( + sprintf(Minification::XML_PATH_MINIFICATION_ENABLED, $contentType), + ScopeInterface::SCOPE_STORE + ) + ->willReturn($configFlag); + $this->appStateMock + ->expects($this->any()) + ->method('getMode') + ->willReturn($appMode); + + $this->assertEquals($result, $this->minification->isEnabled($contentType)); + } + + /** + * @return array + */ + public function isEnabledDataProvider() + { + return [ + [false, State::MODE_DEFAULT, false], + [false, State::MODE_PRODUCTION, false], + [false, State::MODE_DEVELOPER, false], + [true, State::MODE_DEFAULT, true], + [true, State::MODE_PRODUCTION, true], + [true, State::MODE_DEVELOPER, false] + ]; + } + + /** + * @param string $filename + * @param bool $isEnabled + * @param string $expected + * @dataProvider addMinifiedSignDataProvider + */ + public function testAddMinifiedSign($filename, $isEnabled, $expected) + { + $this->scopeConfigMock + ->expects($this->any()) + ->method('isSetFlag') + ->willReturn($isEnabled); + $this->appStateMock + ->expects($this->any()) + ->method('getMode') + ->willReturn(State::MODE_DEFAULT); + + $this->assertEquals( + $expected, + $this->minification->addMinifiedSign($filename) + ); + } + + /** + * @return array + */ + public function addMinifiedSignDataProvider() + { + return [ + ['test.css', true, 'test.min.css'], + ['test.css', false, 'test.css'], + ['test.min.css', true, 'test.min.css'] + ]; + } + + /** + * @param string $filename + * @param bool $isEnabled + * @param string $expected + * @dataProvider removeMinifiedSignDataProvider + */ + public function testRemoveMinifiedSign($filename, $isEnabled, $expected) + { + $this->scopeConfigMock + ->expects($this->any()) + ->method('isSetFlag') + ->willReturn($isEnabled); + $this->appStateMock + ->expects($this->any()) + ->method('getMode') + ->willReturn(State::MODE_DEFAULT); + + $this->assertEquals( + $expected, + $this->minification->removeMinifiedSign($filename) + ); + } + + /** + * @return array + */ + public function removeMinifiedSignDataProvider() + { + return [ + ['test.css', true, 'test.css'], + ['test.min.css', true, 'test.css'], + ['test.min.css', false, 'test.min.css'] + ]; + } + + /** + * @param string $filename + * @param bool $result + * @return void + * @dataProvider isMinifiedFilenameDataProvider + */ + public function testIsMinifiedFilename($filename, $result) + { + $this->assertEquals( + $result, + $this->minification->isMinifiedFilename($filename) + ); + } + + /** + * @return array + */ + public function isMinifiedFilenameDataProvider() + { + return [ + ['test.min.css', true], + ['test.mincss', false], + ['testmin.css', false], + ['test.css', false], + ['test.min', false] + ]; + } + + /** + * @return void + */ + public function testGetExcludes() + { + $this->scopeConfigMock + ->expects($this->once()) + ->method('getValue') + ->with('dev/js/minify_exclude') + ->willReturn( + " /tiny_mce/ \n" . + " /tiny_mce2/ " + ); + + $expected = ['/tiny_mce/', '/tiny_mce2/']; + $this->assertEquals($expected, $this->minification->getExcludes('js')); + /** check cache: */ + $this->assertEquals($expected, $this->minification->getExcludes('js')); + } +} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/Minified/AbstractAssetTestCase.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/Minified/AbstractAssetTestCase.php deleted file mode 100644 index 67344819062e006acbe29bcf941e26e72b013e6b..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/Minified/AbstractAssetTestCase.php +++ /dev/null @@ -1,94 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Framework\View\Test\Unit\Asset\Minified; - -use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\Filesystem\DriverPool; - -class AbstractAssetTestCase extends \PHPUnit_Framework_TestCase -{ - /** - * @var \Magento\Framework\View\Asset\LocalInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $asset; - - /** - * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $logger; - - /** - * @var \Magento\Framework\Filesystem\Directory\ReadInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $staticViewDir; - - /** - * @var \Magento\Framework\Filesystem\Directory\ReadInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $rootDir; - - /** - * @var \Magento\Framework\Url|\PHPUnit_Framework_MockObject_MockObject - */ - protected $baseUrl; - - /** - * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject - */ - protected $filesystem; - - /** - * @var \Magento\Framework\Code\Minifier\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $adapter; - - protected function setUp() - { - $this->asset = $this->getMockForAbstractClass('\Magento\Framework\View\Asset\LocalInterface'); - $this->logger = $this->getMock('\Psr\Log\LoggerInterface', [], [], '', false); - $this->baseUrl = $this->getMock('\Magento\Framework\Url', [], [], '', false); - $this->staticViewDir = $this->getMockForAbstractClass( - '\Magento\Framework\Filesystem\Directory\WriteInterface' - ); - $this->rootDir = $this->getMockForAbstractClass('\Magento\Framework\Filesystem\Directory\ReadInterface'); - $this->filesystem = $this->getMock('\Magento\Framework\Filesystem', [], [], '', false); - $this->filesystem->expects($this->any()) - ->method('getDirectoryRead') - ->will($this->returnValueMap([ - [DirectoryList::STATIC_VIEW, DriverPool::FILE, $this->staticViewDir], - [DirectoryList::ROOT, DriverPool::FILE, $this->rootDir], - ])); - $this->filesystem->expects($this->any()) - ->method('getDirectoryWrite') - ->with(DirectoryList::STATIC_VIEW) - ->will($this->returnValue($this->staticViewDir)); - $this->adapter = $this->getMockForAbstractClass('Magento\Framework\Code\Minifier\AdapterInterface'); - } - - protected function prepareAttemptToMinifyMock($fileExists, $rootDirExpectations = true, $originalExists = true) - { - $this->asset->expects($this->atLeastOnce())->method('getPath')->will($this->returnValue('test/admin.js')); - $this->asset->expects($this->atLeastOnce()) - ->method('getSourceFile') - ->will($this->returnValue('/foo/bar/test/admin.js')); - if ($rootDirExpectations) { - $this->rootDir->expects($this->once()) - ->method('getRelativePath') - ->with('/foo/bar/test/admin.min.js') - ->will($this->returnValue('test/admin.min.js')); - $this->rootDir->expects($this->once()) - ->method('isExist') - ->with('test/admin.min.js') - ->will($this->returnValue(false)); - } - $this->baseUrl->expects($this->once())->method('getBaseUrl')->will($this->returnValue('http://example.com/')); - $this->staticViewDir - ->expects($this->exactly(2-intval($originalExists))) - ->method('isExist') - ->will($this->returnValue($fileExists)); - } -} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/Minified/ImmutablePathAssetTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/Minified/ImmutablePathAssetTest.php deleted file mode 100644 index def044ac71c7f4cf3f1391c41f864a611802abb4..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/Minified/ImmutablePathAssetTest.php +++ /dev/null @@ -1,61 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\View\Test\Unit\Asset\Minified; - -use Magento\Framework\View\Asset\Minified\ImmutablePathAsset; -use Magento\Framework\Object; - -class ImmutablePathAssetTest extends AbstractAssetTestCase -{ - /** - * @var ImmutablePathAsset - */ - protected $model; - - protected function setUp() - { - parent::setUp(); - - $this->model = new ImmutablePathAsset( - $this->asset, - $this->logger, - $this->filesystem, - $this->baseUrl, - $this->adapter - ); - } - - public function testImmutableFilePath() - { - $this->asset->expects($this->atLeastOnce())->method('getPath')->will($this->returnValue('test/admin.js')); - $this->asset->expects($this->atLeastOnce())->method('getFilePath')->will($this->returnValue('test/admin.js')); - $this->asset->expects($this->atLeastOnce()) - ->method('getSourceFile') - ->will($this->returnValue('/foo/bar/test/admin.js')); - if (true) { - $this->rootDir->expects($this->once()) - ->method('getRelativePath') - ->with('/foo/bar/test/admin.min.js') - ->will($this->returnValue('test/admin.min.js')); - $this->rootDir->expects($this->once()) - ->method('isExist') - ->with('test/admin.min.js') - ->will($this->returnValue(false)); - } - $this->baseUrl->expects($this->once())->method('getBaseUrl')->will($this->returnValue('http://example.com/')); - $this->staticViewDir - ->expects($this->exactly(2-intval(true))) - ->method('isExist') - ->will($this->returnValue(false)); - - $this->asset->method('getContext')->willReturn($this->baseUrl); - $this->asset->expects($this->once())->method('getContent')->will($this->returnValue('content')); - $this->adapter->expects($this->once())->method('minify')->with('content')->will($this->returnValue('mini')); - $this->staticViewDir->expects($this->once())->method('writeFile')->with($this->anything(), 'mini'); - $this->assertEquals('test/admin.js', $this->model->getFilePath()); - $this->assertEquals('http://example.com/test/admin.js', $this->model->getUrl()); - } -} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/Minified/MutablePathAssetTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/Minified/MutablePathAssetTest.php deleted file mode 100644 index df652279e5805a8c0999d0541bbcbaeacb11ba7b..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/Minified/MutablePathAssetTest.php +++ /dev/null @@ -1,217 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\View\Test\Unit\Asset\Minified; - -use \Magento\Framework\View\Asset\Minified\MutablePathAsset; -use \Magento\Framework\View\Asset\Minified\AbstractAsset; - -class MutablePathAssetTest extends AbstractAssetTestCase -{ - /** - * @var MutablePathAsset - */ - protected $_model; - - protected function setUp() - { - parent::setUp(); - - $this->_model = new MutablePathAsset( - $this->asset, - $this->logger, - $this->filesystem, - $this->baseUrl, - $this->adapter - ); - } - - /** - * @param string $method - * @param string $expected - * @dataProvider inMemoryDecoratorDataProvider - */ - public function testInMemoryDecorator($method, $expected) - { - $this->prepareRequestedAsMinifiedMock(); - $this->adapter->expects($this->never())->method('minify'); - $this->assertSame($expected, $this->_model->$method()); - $this->assertSame($expected, $this->_model->$method()); // invoke second time to test in-memory caching - } - - /** - * Prepare case when an asset is requested explicitly with ".min" suffix - * - * In this case the minification is not supposed to occur - */ - private function prepareRequestedAsMinifiedMock() - { - $this->asset->expects($this->any())->method('getPath')->will($this->returnValue('test/admin.min.js')); - $this->asset->expects($this->once())->method('getSourceFile')->will($this->returnValue('source_file')); - $this->asset->expects($this->once())->method('getFilePath')->will($this->returnValue('file_path')); - $this->asset->expects($this->once())->method('getContext')->will($this->returnValue('context')); - $this->asset->expects($this->once())->method('getUrl')->will($this->returnValue('url')); - } - - /** - * @return array - */ - public function inMemoryDecoratorDataProvider() - { - return [ - ['getUrl', 'url'], - ['getSourceFile', 'source_file'], - ['getPath', 'test/admin.min.js'], - ['getFilePath', 'file_path'], - ['getContext', 'context'], - ]; - } - - /** - * @param string $method - * @param string $expected - * @dataProvider assetDecoratorDataProvider - */ - public function testAssetDecorator($method, $expected) - { - $this->asset->expects($this->exactly(2))->method($method)->will($this->returnValue($expected)); - $this->assertSame($expected, $this->_model->$method()); - $this->assertSame($expected, $this->_model->$method()); // 2 times to ensure asset is invoked every time - } - - /** - * @return array - */ - public function assetDecoratorDataProvider() - { - return [ - ['getContentType', 'content_type'], - ['getModule', 'module'], - ]; - } - - public function testGetContent() - { - $this->prepareRequestedAsMinifiedMock(); - $this->adapter->expects($this->never())->method('minify'); - $this->staticViewDir->expects($this->exactly(2)) - ->method('readFile') - ->with('test/admin.min.js') - ->will($this->returnValue('content')); - $this->assertEquals('content', $this->_model->getContent()); - $this->assertEquals('content', $this->_model->getContent()); - } - - public function testHasPreminifiedFile() - { - $this->asset->expects($this->exactly(2))->method('getPath')->will($this->returnValue('test/admin.js')); - $this->asset->expects($this->atLeastOnce()) - ->method('getSourceFile') - ->will($this->returnValue('/foo/bar/test/admin.js')); - $this->asset->expects($this->once())->method('getFilePath')->will($this->returnValue('file_path')); - $this->asset->expects($this->once())->method('getContext')->will($this->returnValue('context')); - $this->asset->expects($this->once())->method('getUrl')->will($this->returnValue('url')); - $this->rootDir->expects($this->once()) - ->method('getRelativePath') - ->with('/foo/bar/test/admin.min.js') - ->will($this->returnValue('test/admin.min.js')); - $this->rootDir->expects($this->once()) - ->method('isExist') - ->with('test/admin.min.js') - ->will($this->returnValue(true)); - $this->adapter->expects($this->never())->method('minify'); - $this->assertEquals('test/admin.min.js', $this->_model->getPath()); - } - - public function testMinify() - { - $this->prepareAttemptToMinifyMock(false, true, true, 0); - $this->asset->expects($this->once())->method('getContent')->will($this->returnValue('content')); - $this->adapter->expects($this->once())->method('minify')->with('content')->will($this->returnValue('mini')); - $this->staticViewDir->expects($this->once())->method('writeFile')->with($this->anything(), 'mini'); - $this->assertStringMatchesFormat('%s_admin.min.js', $this->_model->getFilePath()); - } - - public function testMinificationFailed() - { - $this->prepareAttemptToMinifyMock(false, true, false); - $this->asset->expects($this->exactly(2))->method('getContent')->will($this->returnValue('content')); - $e = new \Exception('test'); - $this->adapter->expects($this->once())->method('minify')->with('content')->will($this->throwException($e)); - $this->logger->expects($this->once())->method('critical'); - $this->staticViewDir->expects($this->once())->method('writeFile'); - $this->asset->expects($this->once())->method('getFilePath')->will($this->returnValue('file_path')); - $this->asset->expects($this->once())->method('getContext')->will($this->returnValue('context')); - $this->asset->expects($this->once())->method('getUrl')->will($this->returnValue('url')); - $this->assertEquals('test/admin.js', $this->_model->getPath()); - } - - public function testShouldNotMinifyCozExists() - { - $this->prepareAttemptToMinifyMock(true, 0); - // IS_EXISTS is assumed by default, so nothing to mock here - $this->adapter->expects($this->never())->method('minify'); - $this->assertStringMatchesFormat('%s_admin.min.js', $this->_model->getFilePath()); - } - - /** - * @param int $mtimeOrig - * @param int $mtimeMinified - * @param bool $isMinifyExpected - * @dataProvider minifyMtimeDataProvider - */ - public function testMinifyMtime($mtimeOrig, $mtimeMinified, $isMinifyExpected) - { - $this->prepareAttemptToMinifyMock(true, false); - $model = new MutablePathAsset( - $this->asset, - $this->logger, - $this->filesystem, - $this->baseUrl, - $this->adapter, - AbstractAsset::MTIME - ); - $this->rootDir->expects($this->any()) - ->method('getRelativePath') - ->will($this->returnValueMap([ - ['/foo/bar/test/admin.min.js', 'test/admin.min.js'], - ['/foo/bar/test/admin.js', 'test/admin.js'], - ])); - $this->rootDir->expects($this->once()) - ->method('isExist') - ->with('test/admin.min.js') - ->will($this->returnValue(false)); - $this->rootDir->expects($this->once()) - ->method('stat') - ->with('test/admin.js') - ->will($this->returnValue(['mtime' => $mtimeOrig])); - $this->staticViewDir->expects($this->once()) - ->method('stat') - ->with($this->anything()) - ->will($this->returnValue(['mtime' => $mtimeMinified])); - if ($isMinifyExpected) { - $this->asset->expects($this->once())->method('getContent')->will($this->returnValue('content')); - $this->adapter->expects($this->once()) - ->method('minify') - ->with('content') - ->will($this->returnValue('mini')); - $this->staticViewDir->expects($this->once())->method('writeFile')->with($this->anything(), 'mini'); - } else { - $this->adapter->expects($this->never())->method('minify'); - } - $this->assertStringMatchesFormat('%s_admin.min.js', $model->getFilePath()); - } - - /** - * @return array - */ - public function minifyMtimeDataProvider() - { - return [ - [1, 2, true], - [3, 3, false], - ]; - } -} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinifyServiceTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinifyServiceTest.php deleted file mode 100644 index 2e31f4d67733e308603855cac3dc43dd3d7e7514..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinifyServiceTest.php +++ /dev/null @@ -1,174 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Framework\View\Test\Unit\Asset; - -use \Magento\Framework\View\Asset\MinifyService; -use \Magento\Framework\View\Asset\Minified\AbstractAsset; - -class MinifyServiceTest extends \PHPUnit_Framework_TestCase -{ - /** - * @var \Magento\Framework\View\Asset\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $_config; - - /** - * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $_objectManager; - - /** - * @var \Magento\Framework\View\Asset\MinifyService - */ - protected $_model; - - protected function setUp() - { - $this->_config = $this->getMock('Magento\Framework\View\Asset\ConfigInterface', [], [], '', false); - $this->_objectManager = $this->getMock('Magento\Framework\ObjectManagerInterface'); - $this->_model = new MinifyService($this->_config, $this->_objectManager); - } - - /** - * @param $appMode - * @param $expectedStrategy - * @dataProvider getAssetsDataProvider - */ - public function testGetAssets($appMode, $expectedStrategy) - { - $assetOne = $this->getMockForAbstractClass('Magento\Framework\View\Asset\LocalInterface'); - $assetOne->expects($this->any()) - ->method('getContentType') - ->will($this->returnValue('js')); - $resultOne = $this->getMock('Magento\Framework\View\Asset\Minified\MutablePathAsset', [], [], '', false); - $assetTwo = $this->getMockForAbstractClass('Magento\Framework\View\Asset\LocalInterface'); - $assetTwo->expects($this->any()) - ->method('getContentType') - ->will($this->returnValue('js')); - $resultTwo = $this->getMock('Magento\Framework\View\Asset\Minified\MutablePathAsset', [], [], '', false); - $this->_config->expects($this->once()) - ->method('isAssetMinification') - ->with('js') - ->will($this->returnValue(true)); - $minifier = $this->getMockForAbstractClass('Magento\Framework\Code\Minifier\AdapterInterface'); - $this->_config->expects($this->once()) - ->method('getAssetMinificationAdapter') - ->with('js') - ->will($this->returnValue('Magento\Framework\Code\Minifier\AdapterInterface')); - $this->_objectManager->expects($this->once()) - ->method('get') - ->with('Magento\Framework\Code\Minifier\AdapterInterface') - ->will($this->returnValue($minifier)); - $this->_objectManager->expects($this->exactly(2)) - ->method('create') - ->will($this->returnValueMap( - [ - [ - 'Magento\Framework\View\Asset\Minified\MutablePathAsset', - ['asset' => $assetOne, 'strategy' => $expectedStrategy, 'adapter' => $minifier], - $resultOne, - ], - [ - 'Magento\Framework\View\Asset\Minified\MutablePathAsset', - ['asset' => $assetTwo, 'strategy' => $expectedStrategy, 'adapter' => $minifier], - $resultTwo - ], - ] - )); - $model = new MinifyService($this->_config, $this->_objectManager, $appMode); - $result = $model->getAssets([$assetOne, $assetTwo]); - $this->assertArrayHasKey(0, $result); - $this->assertSame($resultOne, $result[0]); - $this->assertArrayHasKey(1, $result); - $this->assertSame($resultTwo, $result[1]); - } - - /** - * @return array - */ - public function getAssetsDataProvider() - { - return [ - 'production' => [ - \Magento\Framework\App\State::MODE_PRODUCTION, - AbstractAsset::FILE_EXISTS, - ], - 'default' => [ - \Magento\Framework\App\State::MODE_DEFAULT, - AbstractAsset::MTIME, - ], - 'developer' => [ - \Magento\Framework\App\State::MODE_DEVELOPER, - AbstractAsset::MTIME, - ], - ]; - } - - public function testGetAssetsDisabled() - { - $asset = $this->getMockForAbstractClass('Magento\Framework\View\Asset\LocalInterface'); - $asset->expects($this->once()) - ->method('getContentType') - ->will($this->returnValue('js')); - - $this->_config->expects($this->once()) - ->method('isAssetMinification') - ->with('js') - ->will($this->returnValue(false)); - $this->_config->expects($this->never()) - ->method('getAssetMinificationAdapter'); - - $minifiedAssets = $this->_model->getAssets([$asset]); - $this->assertCount(1, $minifiedAssets); - $this->assertSame($asset, $minifiedAssets[0]); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - * @expectedExceptionMessage Minification adapter is not specified for 'js' content type - */ - public function testGetAssetsNoAdapterDefined() - { - $asset = $this->getMockForAbstractClass('Magento\Framework\View\Asset\LocalInterface'); - $asset->expects($this->any()) - ->method('getContentType') - ->will($this->returnValue('js')); - - $this->_config->expects($this->once()) - ->method('isAssetMinification') - ->with('js') - ->will($this->returnValue(true)); - $this->_config->expects($this->once()) - ->method('getAssetMinificationAdapter') - ->with('js'); - - $this->_model->getAssets([$asset]); - } - - public function testGetAssetsInvalidAdapter() - { - $this->setExpectedException( - '\Magento\Framework\Exception\LocalizedException', - 'Invalid adapter: \'stdClass\'. Expected: \Magento\Framework\Code\Minifier\AdapterInterface' - ); - $asset = $this->getMockForAbstractClass('Magento\Framework\View\Asset\LocalInterface'); - $asset->expects($this->any()) - ->method('getContentType') - ->will($this->returnValue('js')); - $this->_config->expects($this->once()) - ->method('isAssetMinification') - ->with('js') - ->will($this->returnValue(true)); - $this->_config->expects($this->once()) - ->method('getAssetMinificationAdapter') - ->with('js') - ->will($this->returnValue('StdClass')); - $obj = new \StdClass(); - $this->_objectManager->expects($this->once())->method('get')->with('StdClass')->will($this->returnValue($obj)); - - $this->_model->getAssets([$asset]); - } -} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/ChainTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/ChainTest.php index e0c4e8b4d7003c5a88e7d6194e8117574be2bc9c..b5e0562c7b415784d14d3223792a19c2076b9316 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/ChainTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/ChainTest.php @@ -29,7 +29,7 @@ class ChainTest extends \PHPUnit_Framework_TestCase { $this->asset = $this->getMockForAbstractClass('\Magento\Framework\View\Asset\LocalInterface'); $this->asset->expects($this->once())->method('getContentType')->will($this->returnValue('assetType')); - $this->object = new Chain($this->asset, 'origContent', 'origType'); + $this->object = new Chain($this->asset, 'origContent', 'origType', 'origPath'); } public function testGetAsset() diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/MinifyTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/MinifyTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e1a6855872dfbff588900e31fa2355dd15076484 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/MinifyTest.php @@ -0,0 +1,121 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\View\Test\Unit\Asset\PreProcessor; + +use Magento\Framework\View\Asset\PreProcessor\Minify; + +/** + * Unit test for Magento\Framework\View\Asset\PreProcessor\Minify + */ +class MinifyTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Framework\View\Asset\PreProcessor\Minify + */ + protected $minify; + + /** + * @var \Magento\Framework\Code\Minifier\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $adapterMock; + + /** + * @var \Magento\Framework\View\Asset\Minification|\PHPUnit_Framework_MockObject_MockObject + */ + protected $minificationMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + $this->adapterMock = $this->getMockBuilder('Magento\Framework\Code\Minifier\AdapterInterface') + ->setMethods(['minify']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->minificationMock = $this->getMockBuilder('Magento\Framework\View\Asset\Minification') + ->disableOriginalConstructor() + ->getMock(); + + $this->minify = new Minify( + $this->adapterMock, + $this->minificationMock + ); + } + + /** + * @param string $targetPath + * @param string $originalPath + * @param int $minifyCalls + * @param int $setContentCalls + * @param bool $isEnabled + * @return void + * @dataProvider processDataProvider + */ + public function testProcess($targetPath, $originalPath, $minifyCalls, $setContentCalls, $isEnabled) + { + $chainMock = $this->getMockBuilder('Magento\Framework\View\Asset\PreProcessor\Chain') + ->disableOriginalConstructor() + ->getMock(); + $chainMock + ->expects($this->any()) + ->method('getTargetAssetPath') + ->willReturn($targetPath); + $chainMock + ->expects($this->exactly($setContentCalls)) + ->method('setContent') + ->with('minified content'); + $chainMock + ->expects($this->any()) + ->method('getContent') + ->willReturn('original content'); + $chainMock + ->expects($this->any()) + ->method('getOrigAssetPath') + ->willReturn($originalPath); + + $this->adapterMock + ->expects($this->exactly($minifyCalls)) + ->method('minify') + ->with('original content') + ->willReturn('minified content'); + + $this->minificationMock + ->expects($this->any()) + ->method('isEnabled') + ->willReturnMap([['css', $isEnabled]]); + + $this->minificationMock + ->expects($this->any()) + ->method('isMinifiedFilename') + ->willReturnMap( + [ + ['test.min.css', true], + ['test.jpeg', false], + ['test.css', false] + ] + ); + + $this->minify->process($chainMock); + } + + /** + * @return array + */ + public function processDataProvider() + { + return [ + ['test.min.css', 'test.css', 1, 1, true], + ['test.min.css', 'test.min.css', 0, 0, true], + ['test.jpeg', 'test.jpeg', 0, 0, true], + ['test.css', 'test.css', 0, 0, true], + ['test.jpeg', 'test.jpeg', 0, 0, true], + ['test.css', 'test.css', 0, 0, true], + ['test.css', 'test.css', 0, 0, false] + ]; + } +} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/RepositoryTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/RepositoryTest.php index 60a2d297e4b5ba5a56bff218941ed1ea2fa7884c..1e22d37bb68169cb3cfcf804a6ffb743db4437ed 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/RepositoryTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/RepositoryTest.php @@ -4,226 +4,305 @@ * See COPYING.txt for license details. */ -// @codingStandardsIgnoreFile - namespace Magento\Framework\View\Test\Unit\Asset; -use \Magento\Framework\View\Asset\Repository; +use Magento\Framework\View\Asset\Repository; +/** + * Unit test for Magento\Framework\View\Asset\Repository + */ class RepositoryTest extends \PHPUnit_Framework_TestCase { + /** + * @var \Magento\Framework\View\Asset\Repository + */ + private $repository; + /** * @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject */ - private $baseUrl; + private $urlMock; /** * @var \Magento\Framework\View\DesignInterface|\PHPUnit_Framework_MockObject_MockObject */ - private $design; + private $designMock; /** * @var \Magento\Framework\View\Design\Theme\ListInterface|\PHPUnit_Framework_MockObject_MockObject */ - private $themeList; + private $listMock; /** * @var \Magento\Framework\View\Asset\Source|\PHPUnit_Framework_MockObject_MockObject */ - private $source; + private $sourceMock; /** - * @var \Magento\Framework\View\Design\ThemeInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject */ - private $theme; + private $httpMock; /** - * @var Repository + * @var \Magento\Framework\View\Asset\FileFactory|\PHPUnit_Framework_MockObject_MockObject */ - private $object; + private $fileFactoryMock; /** - * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\View\Asset\File\FallbackContextFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $requestMock; + private $fallbackFactoryMock; + /** + * @var \Magento\Framework\View\Asset\File\ContextFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $contextFactoryMock; + + /** + * @var \Magento\Framework\View\Asset\RemoteFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $remoteFactoryMock; + + /** + * {@inheritDoc} + */ protected function setUp() { - $this->themeList = $this->getMockForAbstractClass('\Magento\Framework\View\Design\Theme\ListInterface'); - $this->source = $this->getMock( - 'Magento\Framework\View\Asset\Source', - ['getFile', 'getContent'], - [], - '', - false - ); - $this->baseUrl = $this->getMockForAbstractClass('Magento\Framework\UrlInterface'); - $this->design = $this->getMockForAbstractClass('Magento\Framework\View\DesignInterface'); - $this->theme = $this->getMockForAbstractClass('Magento\Framework\View\Design\ThemeInterface'); - $this->requestMock = $this->getMockBuilder('Magento\Framework\App\Request\Http') + $this->urlMock = $this->getMockBuilder('Magento\Framework\UrlInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->designMock = $this->getMockBuilder('Magento\Framework\View\DesignInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->listMock = $this->getMockBuilder('Magento\Framework\View\Design\Theme\ListInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->sourceMock = $this->getMockBuilder('Magento\Framework\View\Asset\Source') + ->disableOriginalConstructor() + ->getMock(); + $this->httpMock = $this->getMockBuilder('Magento\Framework\App\Request\Http') + ->disableOriginalConstructor() + ->getMock(); + $this->fileFactoryMock = $this->getMockBuilder('Magento\Framework\View\Asset\FileFactory') + ->disableOriginalConstructor() + ->getMock(); + $this->fallbackFactoryMock = $this->getMockBuilder('Magento\Framework\View\Asset\File\FallbackContextFactory') + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->contextFactoryMock = $this->getMockBuilder('Magento\Framework\View\Asset\File\ContextFactory') + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->remoteFactoryMock = $this->getMockBuilder('Magento\Framework\View\Asset\RemoteFactory') + ->setMethods(['create']) ->disableOriginalConstructor() ->getMock(); - $this->object = new Repository( - $this->baseUrl, - $this->design, - $this->themeList, - $this->source, - $this->requestMock + + $this->repository = new Repository( + $this->urlMock, + $this->designMock, + $this->listMock, + $this->sourceMock, + $this->httpMock, + $this->fileFactoryMock, + $this->fallbackFactoryMock, + $this->contextFactoryMock, + $this->remoteFactoryMock ); } /** * @expectedException \UnexpectedValueException * @expectedExceptionMessage Could not find theme 'nonexistent_theme' for area 'area' + * @return void */ public function testUpdateDesignParamsWrongTheme() { $params = ['area' => 'area', 'theme' => 'nonexistent_theme']; - $this->themeList->expects($this->once()) + $this->listMock->expects($this->once()) ->method('getThemeByFullPath') ->with('area/nonexistent_theme') ->will($this->returnValue(null)); - $this->object->updateDesignParams($params); - } - - public function testCreateAsset() - { - $this->mockDesign(); - $this->baseUrl->expects($this->once()) - ->method('getBaseUrl') - ->will($this->returnValue('http://example.com/static/')); - $asset = $this->object->createAsset('test/file.js'); - $this->assertInstanceOf('\Magento\Framework\View\Asset\File', $asset); - $this->assertEquals('area/theme/locale/test/file.js', $asset->getPath()); - $this->assertEquals('test/file.js', $asset->getFilePath()); - $this->assertEquals('js', $asset->getContentType()); - $this->assertInstanceOf('\Magento\Framework\View\Asset\File\FallbackContext', $asset->getContext()); - $this->assertEquals('', $asset->getModule()); - $this->assertEquals('http://example.com/static/area/theme/locale/test/file.js', $asset->getUrl()); - - $this->source->expects($this->once())->method('getFile')->with($asset)->will($this->returnValue('source')); - $this->source->expects($this->once())->method('getContent')->with($asset)->will($this->returnValue('content')); - $this->assertEquals('source', $asset->getSourceFile()); - $this->assertEquals('content', $asset->getContent()); - - $anotherAsset = $this->object->createAsset('another/file.id'); - $this->assertSame($anotherAsset->getContext(), $asset->getContext()); - } - - public function testCreateAssetModular() - { - $this->mockDesign(); - $asset = $this->object->createAsset('Module_Name::test/file.js'); - $this->assertEquals('Module_Name', $asset->getModule()); - $this->assertEquals('test/file.js', $asset->getFilePath()); - } - - public function testGetStaticViewFileContext() - { - $this->mockDesign(); - $context = $this->object->getStaticViewFileContext(); - $this->assertInstanceOf('\Magento\Framework\View\Asset\ContextInterface', $context); - $this->assertSame($context, $this->object->getStaticViewFileContext()); // to ensure in-memory caching - $asset = $this->object->createAsset('test/file.js'); - $this->assertSame($context, $asset->getContext()); // and once again to ensure in-memory caching for real + $this->repository->updateDesignParams($params); } /** - * @param string $fileId - * @param string $similarToModule - * @param string $expectedPath - * @param string $expectedType - * @param string $expectedModule - * @dataProvider createSimilarDataProvider + * @param array $params + * @param array $result + * @return void + * @dataProvider updateDesignParamsDataProvider */ - public function testCreateSimilar($fileId, $similarToModule, $expectedPath, $expectedType, $expectedModule) + public function testUpdateDesignParams($params, $result) { - $similarTo = $this->getMockForAbstractClass('\Magento\Framework\View\Asset\LocalInterface'); - $context = $this->getMockForAbstractClass('\Magento\Framework\View\Asset\ContextInterface'); - $similarTo->expects($this->once())->method('getContext')->will($this->returnValue($context)); - $similarTo->expects($this->any())->method('getModule')->will($this->returnValue($similarToModule)); - $asset = $this->object->createSimilar($fileId, $similarTo); - $this->assertInstanceOf('\Magento\Framework\View\Asset\File', $asset); - $this->assertSame($context, $asset->getContext()); - $this->assertEquals($expectedPath, $asset->getFilePath()); - $this->assertEquals($expectedType, $asset->getContentType()); - $this->assertEquals($expectedModule, $asset->getModule()); + $this->listMock + ->expects($this->any()) + ->method('getThemeByFullPath') + ->willReturn('ThemeID'); + + $this->repository->updateDesignParams($params); + $this->assertEquals($result, $params); } /** * @return array */ - public function createSimilarDataProvider() + public function updateDesignParamsDataProvider() { return [ - ['test/file.css', '', 'test/file.css', 'css', ''], - ['test/file.js', '', 'test/file.js', 'js', ''], - ['test/file.css', 'Module_Name', 'test/file.css', 'css', 'Module_Name'], - ['Module_Name::test/file.css', 'Module_Two', 'test/file.css', 'css', 'Module_Name'], + [ + ['area' => 'AREA'], + ['area' => 'AREA', 'themeModel' => '', 'module' => '', 'locale' => '']], + [ + ['themeId' => 'ThemeID'], + ['area' => '', 'themeId' => 'ThemeID', 'themeModel' => 'ThemeID', 'module' => '', 'locale' => ''] + ] ]; } /** - * @param string $filePath - * @param string $dirPath - * @param string $baseUrlType - * @param string $expectedType - * @param string $expectedUrl - * @dataProvider createArbitraryDataProvider + * @return void */ - public function testCreateArbitrary($filePath, $dirPath, $baseUrlType, $expectedType, $expectedUrl) + public function testCreateAsset() { - $this->baseUrl->expects($this->once()) - ->method('getBaseUrl') - ->will($this->returnValueMap([ - [['_type' => 'static'], 'http://example.com/static/'], - [['_type' => 'media'], 'http://example.com/media/'], - ])); - $dirType = 'dirType'; - $asset = $this->object->createArbitrary($filePath, $dirPath, $dirType, $baseUrlType); - $this->assertInstanceOf('\Magento\Framework\View\Asset\File', $asset); - $this->assertEquals($expectedType, $asset->getContentType()); - $this->assertEquals($expectedUrl, $asset->getUrl()); - $this->assertEquals($dirType, $asset->getContext()->getBaseDirType()); - - $anotherAsset = $this->object->createArbitrary('another/path.js', $dirPath, $dirType, $baseUrlType); - $this->assertSame($anotherAsset->getContext(), $asset->getContext()); + $this->listMock + ->expects($this->any()) + ->method('getThemeByFullPath') + ->willReturnArgument(0); + + $fallbackContextMock = $this->getMockBuilder('Magento\Framework\View\Asset\File\FallbackContex') + ->disableOriginalConstructor() + ->getMock(); + $this->fallbackFactoryMock + ->expects($this->once()) + ->method('create') + ->with( + [ + 'baseUrl' => '', + 'areaType' => '', + 'themePath' => 'Default', + 'localeCode' => '', + 'isSecure' => '', + ] + ) + ->willReturn($fallbackContextMock); + + $assetMock = $this->getMockBuilder('Magento\Framework\View\Asset\File') + ->disableOriginalConstructor() + ->getMock(); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with( + [ + 'source' => $this->sourceMock, + 'context' => $fallbackContextMock, + 'filePath' => 'test/file.js', + 'module' => 'Test', + 'contentType' => '' + ] + ) + ->willReturn($assetMock); + + $this->assertEquals( + $assetMock, + $this->repository->createAsset('test/file.js', ['module' => 'Test', 'theme' => 'Default']) + ); } /** - * @return array + * @return void */ - public function createArbitraryDataProvider() + public function testGetStaticViewFileContext() { - return [ - ['test/example.js', 'dir/path', 'static', 'js', 'http://example.com/static/dir/path/test/example.js'], - ['test/example.css', '', 'media', 'css', 'http://example.com/media/test/example.css'], - ['img/logo.gif', 'uploaded', 'media', 'gif', 'http://example.com/media/uploaded/img/logo.gif'], - ]; + $themeMock = $this->getMock('Magento\Framework\View\Design\ThemeInterface', [], [], '', false); + $this->designMock + ->expects($this->any()) + ->method('getDesignParams') + ->willReturn( + [ + 'themeModel' => $themeMock, + 'area' => 'area', + 'locale' => 'locale' + ] + ); + $this->listMock + ->expects($this->any()) + ->method('getThemeByFullPath') + ->willReturnArgument(0); + $this->httpMock + ->expects($this->any()) + ->method('isSecure') + ->willReturn(false); + + $fallbackContextMock = $this->getMockBuilder('Magento\Framework\View\Asset\File\FallbackContex') + ->disableOriginalConstructor() + ->getMock(); + $this->fallbackFactoryMock + ->expects($this->once()) + ->method('create') + ->with( + [ + 'baseUrl' => '', + 'areaType' => 'area', + 'themePath' => '', + 'localeCode' => 'locale', + 'isSecure' => '', + ] + ) + ->willReturn($fallbackContextMock); + + $this->assertEquals( + $fallbackContextMock, + $this->repository->getStaticViewFileContext() + ); } /** - * @param string $fileId - * @param string $relFilePath - * @param string $relModule - * @param string $expFilePath - * @param string $expType - * @param string $expModule + * @param string $filePath + * @param string $resultFilePath + * @param string $module + * @return void * @dataProvider createRelatedDataProvider */ - public function testCreateRelated($fileId, $relFilePath, $relModule, $expFilePath, $expType, $expModule) + public function testCreateRelated($filePath, $resultFilePath, $module) { - $relativeTo = $this->getMockForAbstractClass('\Magento\Framework\View\Asset\LocalInterface'); - $context = $this->getMockForAbstractClass('\Magento\Framework\View\Asset\ContextInterface'); - $relativeTo->expects($this->once())->method('getContext')->will($this->returnValue($context)); - $relativeTo->expects($this->any())->method('getModule')->will($this->returnValue($relModule)); - $relativeTo->expects($this->any())->method('getFilePath')->will($this->returnValue($relFilePath)); - $asset = $this->object->createRelated($fileId, $relativeTo); - $this->assertInstanceOf('\Magento\Framework\View\Asset\File', $asset); - $this->assertSame($context, $asset->getContext()); - $this->assertEquals($expFilePath, $asset->getFilePath()); - $this->assertEquals($expType, $asset->getContentType()); - $this->assertEquals($expModule, $asset->getModule()); + $originalContextMock = $this->getMockBuilder('Magento\Framework\View\Asset\ContextInterface') + ->disableOriginalConstructor() + ->getMock(); + + $originalAssetMock = $this->getMockBuilder('Magento\Framework\View\Asset\File') + ->disableOriginalConstructor() + ->setMethods(['getModule', 'getContext']) + ->getMock(); + $originalAssetMock + ->expects($this->any()) + ->method('getContext') + ->willReturn($originalContextMock); + + $assetMock = $this->getMockBuilder('Magento\Framework\View\Asset\File') + ->disableOriginalConstructor() + ->getMock(); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with( + [ + 'source' => $this->sourceMock, + 'context' => $originalContextMock, + 'filePath' => $resultFilePath, + 'module' => $module, + 'contentType' => '' + ] + ) + ->willReturn($assetMock); + + $this->assertEquals( + $assetMock, + $this->repository->createRelated($filePath, $originalAssetMock) + ); } /** @@ -232,98 +311,119 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase public function createRelatedDataProvider() { return [ - ['test/file.ext', 'rel/file.ext2', '', 'rel/test/file.ext', 'ext', ''], - ['test/file.ext', 'rel/file.ext2', 'Module_Name', 'rel/test/file.ext', 'ext', 'Module_Name'], - ['Module_One::test/file.ext', 'rel/file.ext2', 'Module_Two', 'test/file.ext', 'ext', 'Module_One'], - ['Module_Name::test/file.ext', '', '', 'test/file.ext', 'ext', 'Module_Name'], + ['test/file.js', '/test/file.js', ''], + ['test::file.js', 'file.js', 'test'], ]; } - public function testCreateRemoteAsset() + /** + * @return void + */ + public function testCreateArbitrary() { - $asset = $this->object->createRemoteAsset('url', 'type'); - $this->assertInstanceOf('\Magento\Framework\View\Asset\Remote', $asset); - $this->assertEquals('url', $asset->getUrl()); - $this->assertEquals('type', $asset->getContentType()); - } + $contextMock = $this->getMockBuilder('Magento\Framework\View\Asset\ContextInterface') + ->disableOriginalConstructor() + ->getMock(); + + $this->contextFactoryMock + ->expects($this->once()) + ->method('create') + ->with( + [ + 'baseUrl' => '', + 'baseDirType' => 'dirType', + 'contextPath' => 'dir/path' + ] + ) + ->willReturn($contextMock); + + $assetMock = $this->getMockBuilder('Magento\Framework\View\Asset\File') + ->disableOriginalConstructor() + ->getMock(); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with( + [ + 'source' => $this->sourceMock, + 'context' => $contextMock, + 'filePath' => 'test/file.js', + 'module' => '', + 'contentType' => '' + ] + ) + ->willReturn($assetMock); - public function testGetUrl() - { - $this->mockDesign(); - $this->baseUrl->expects($this->once()) - ->method('getBaseUrl') - ->will($this->returnValue('http://example.com/static/')); - $result = $this->object->getUrl('Module_Name::img/product/placeholder.png'); $this->assertEquals( - 'http://example.com/static/area/theme/locale/Module_Name/img/product/placeholder.png', - $result + $assetMock, + $this->repository->createArbitrary('test/file.js', 'dir/path', 'dirType', 'static') ); } - public function testGetUrlWithParams() + /** + * @return void + */ + public function testCreateRemoteAsset() { - $defaultTheme = $this->getMockForAbstractClass('Magento\Framework\View\Design\ThemeInterface'); - $defaults = [ - 'area' => 'area', - 'themeModel' => $defaultTheme, - 'locale' => 'locale', - ]; - $this->design->expects($this->atLeastOnce())->method('getDesignParams')->will($this->returnValue($defaults)); - $this->design->expects($this->once()) - ->method('getConfigurationDesignTheme') - ->with('custom_area') - ->will($this->returnValue(false)); - $this->design->expects($this->any()) - ->method('getThemePath') - ->with($this->theme) - ->will($this->returnValue('custom_theme')); - $this->baseUrl->expects($this->once()) - ->method('getBaseUrl') - ->will($this->returnValue('http://example.com/static/')); - $params = [ - 'area' => 'custom_area', - 'locale' => 'en_US', - 'module' => 'This_Shall_Not_Be_Used', - ]; - $result = $this->object->getUrlWithParams('Module_Name::file.ext', $params); - $this->assertEquals('http://example.com/static/custom_area/custom_theme/en_US/Module_Name/file.ext', $result); } - private function mockDesign() + /** + * @return void + */ + public function testGetUrl() { - $params = [ - 'area' => 'area', - 'themeModel' => $this->theme, - 'locale' => 'locale', - ]; - $this->design->expects($this->atLeastOnce())->method('getDesignParams')->will($this->returnValue($params)); - $this->design->expects($this->any()) - ->method('getConfigurationDesignTheme') - ->with('area') - ->will($this->returnValue($this->theme)); - $this->design->expects($this->any()) - ->method('getThemePath') - ->with($this->theme) - ->will($this->returnValue('theme')); - $this->themeList->expects($this->any())->method('getThemeByFullPath')->will($this->returnValue($this->theme)); + $themeMock = $this->getMock('Magento\Framework\View\Design\ThemeInterface', [], [], '', false); + $this->designMock + ->expects($this->any()) + ->method('getDesignParams') + ->willReturn( + [ + 'themeModel' => $themeMock, + 'area' => 'area', + 'locale' => 'locale' + ] + ); + + $assetMock = $this->getMockBuilder('Magento\Framework\View\Asset\File') + ->disableOriginalConstructor() + ->getMock(); + $assetMock + ->expects($this->any()) + ->method('getUrl') + ->willReturn('some url'); + + $this->fileFactoryMock + ->expects($this->exactly(2)) + ->method('create') + ->with( + [ + 'source' => $this->sourceMock, + 'context' => '', + 'filePath' => 'test/file.js', + 'module' => '', + 'contentType' => '' + ] + ) + ->willReturn($assetMock); + + $this->assertEquals( + 'some url', + $this->repository->getUrl('test/file.js') + ); + $this->assertEquals( + 'some url', + $this->repository->getUrlWithParams('test/file.js', []) + ); } /** * @expectedException \Magento\Framework\Exception\LocalizedException * @expectedExceptionMessage Scope separator "::" cannot be used without scope identifier. + * @return void */ public function testExtractModuleException() { - Repository::extractModule('::no_scope.ext'); - } - - public function testExtractModule() - { - $this->assertEquals(['Module_One', 'File'], Repository::extractModule('Module_One::File')); - $this->assertEquals(['', 'File'], Repository::extractModule('File')); - $this->assertEquals( - ['Module_One', 'File::SomethingElse'], - Repository::extractModule('Module_One::File::SomethingElse') - ); + $this->repository->extractModule('::asdsad'); } -} +} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php index 4db38ebb9c55a2e78dd179a4e8ff94d25b3c1620..6901f2d06062e08ca7ab1cea51cbd9caa6b8a00c 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php @@ -39,11 +39,6 @@ class SourceTest extends \PHPUnit_Framework_TestCase */ private $staticDirRead; - /** - * @var \Magento\Framework\View\Asset\PreProcessor\Cache|\PHPUnit_Framework_MockObject_MockObject - */ - private $cache; - /** * @var \Magento\Framework\View\Asset\PreProcessor\Pool|\PHPUnit_Framework_MockObject_MockObject */ @@ -76,9 +71,6 @@ class SourceTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->cache = $this->getMock( - 'Magento\Framework\View\Asset\PreProcessor\Cache', [], [], '', false - ); $this->preProcessorPool = $this->getMock( 'Magento\Framework\View\Asset\PreProcessor\Pool', [], [], '', false ); @@ -107,39 +99,10 @@ class SourceTest extends \PHPUnit_Framework_TestCase $this->initFilesystem(); $this->object = new Source( - $this->cache, - $this->filesystem, - $this->preProcessorPool, - $this->viewFileResolution, - $themeList, - $this->chainFactory + $this->filesystem, $this->preProcessorPool, $this->viewFileResolution, $themeList, $this->chainFactory ); } - public function testGetFileCached() - { - $root = '/root/some/file.ext'; - $expected = '/var/some/file.ext'; - $filePath = 'some/file.ext'; - $this->viewFileResolution->expects($this->once()) - ->method('getFile') - ->with('frontend', $this->theme, 'en_US', $filePath, 'Magento_Module') - ->will($this->returnValue($root)); - $this->rootDirRead->expects($this->once()) - ->method('getRelativePath') - ->with($root) - ->will($this->returnValue($filePath)); - $this->cache->expects($this->once()) - ->method('load') - ->with("some/file.ext:{$filePath}") - ->will($this->returnValue(serialize([DirectoryList::VAR_DIR, $filePath]))); - - $this->varDir->expects($this->once())->method('getAbsolutePath') - ->with($filePath) - ->will($this->returnValue($expected)); - $this->assertSame($expected, $this->object->getFile($this->getAsset())); - } - /** * @param $origFile * @param $origPath @@ -151,7 +114,6 @@ class SourceTest extends \PHPUnit_Framework_TestCase public function testGetFile($origFile, $origPath, $origContent, $isMaterialization) { $filePath = 'some/file.ext'; - $cacheValue = "{$origPath}:{$filePath}"; $this->viewFileResolution->expects($this->once()) ->method('getFile') ->with('frontend', $this->theme, 'en_US', $filePath, 'Magento_Module') @@ -160,9 +122,6 @@ class SourceTest extends \PHPUnit_Framework_TestCase ->method('getRelativePath') ->with($origFile) ->will($this->returnValue($origPath)); - $this->cache->expects($this->once()) - ->method('load') - ->will($this->returnValue(false)); $this->rootDirRead->expects($this->once()) ->method('readFile') ->with($origPath) @@ -186,20 +145,11 @@ class SourceTest extends \PHPUnit_Framework_TestCase $this->varDir->expects($this->once()) ->method('writeFile') ->with('view_preprocessed/source/some/file.ext', 'processed'); - $this->cache->expects($this->once()) - ->method('save') - ->with( - serialize([DirectoryList::VAR_DIR, 'view_preprocessed/source/some/file.ext']), - $cacheValue - ); $this->varDir->expects($this->once()) ->method('getAbsolutePath') ->with('view_preprocessed/source/some/file.ext')->will($this->returnValue('result')); } else { $this->varDir->expects($this->never())->method('writeFile'); - $this->cache->expects($this->once()) - ->method('save') - ->with(serialize([DirectoryList::ROOT, 'source/some/file.ext']), $cacheValue); $this->rootDirRead->expects($this->once()) ->method('getAbsolutePath') ->with('source/some/file.ext') diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/CacheData/FlatTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/CacheData/FlatTest.php deleted file mode 100644 index f3d577e22c89e7873c1d05883a92640c7224362d..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/CacheData/FlatTest.php +++ /dev/null @@ -1,136 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -// @codingStandardsIgnoreFile - -namespace Magento\Framework\View\Test\Unit\Design\FileResolution\Fallback\CacheData; - -use \Magento\Framework\View\Design\FileResolution\Fallback\CacheData\Flat; - -class FlatTest extends \PHPUnit_Framework_TestCase -{ - /** - * @var \Magento\Framework\View\Design\FileResolution\Fallback\Cache|\PHPUnit_Framework_MockObject_MockObject - */ - private $cache; - - /** - * @var \Magento\Framework\View\Design\ThemeInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $theme; - - /** - * @var Flat - */ - private $object; - - protected function setUp() - { - $this->cache = $this->getMock( - '\Magento\Framework\View\Design\FileResolution\Fallback\Cache', [], [], '', false - ); - - $this->theme = $this->getMockForAbstractClass('\Magento\Framework\View\Design\ThemeInterface'); - - $this->object = new \Magento\Framework\View\Design\FileResolution\Fallback\CacheData\Flat($this->cache); - } - - /** - * @param string $area - * @param string $themePath - * @param string $locale - * @param string $module - * @param string $expectedId - * @param string $expectedValue - * - * @dataProvider cacheDataProvider - */ - public function testGetFromCache($area, $themePath, $locale, $module, $expectedId, $expectedValue) - { - if (isset($params['theme'])) { - $this->theme->expects($this->any()) - ->method('getThemePath') - ->will($this->returnValue($params['theme'])); - $params['theme'] = $this->theme; - } else { - $this->theme->expects($this->never()) - ->method('getThemePath'); - } - - $this->cache->expects($this->once()) - ->method('load') - ->with($expectedId) - ->will($this->returnValue($expectedValue)); - - $actual = $this->object->getFromCache('file', 'file.ext', $area, $themePath, $locale, $module); - $this->assertSame($expectedValue, $actual); - } - - /** - * @param string $area - * @param string $themePath - * @param string $locale - * @param string $module - * @param string $expectedId - * @param string $savedValue - * - * @dataProvider cacheDataProvider - */ - public function testSaveToCache($area, $themePath, $locale, $module, $expectedId, $savedValue) - { - if (isset($params['theme'])) { - $this->theme->expects($this->any()) - ->method('getThemePath') - ->will($this->returnValue($params['theme'])); - $params['theme'] = $this->theme; - } else { - $this->theme->expects($this->never()) - ->method('getThemePath'); - } - - $this->cache->expects($this->once()) - ->method('save') - ->with($savedValue, $expectedId) - ->will($this->returnValue(true)); - - $actual = $this->object->saveToCache($savedValue, 'file', 'file.ext', $area, $themePath, $locale, $module); - $this->assertTrue($actual); - } - - /** - * @return array - */ - public function cacheDataProvider() - { - return [ - 'all params' => [ - 'frontend', 'magento_theme', 'en_US', 'Magento_Module', - 'type:file|area:frontend|theme:magento_theme|locale:en_US|module:Magento_Module|file:file.ext', - 'one/file.ext', - ], - 'no area' => [ - null, 'magento_theme', 'en_US', 'Magento_Module', - 'type:file|area:|theme:magento_theme|locale:en_US|module:Magento_Module|file:file.ext', - 'two/file.ext', - ], - 'no theme' => [ - 'frontend', null, 'en_US', 'Magento_Module', - 'type:file|area:frontend|theme:|locale:en_US|module:Magento_Module|file:file.ext', - 'three/file.ext', - ], - 'no locale' => [ - 'frontend', 'magento_theme', null, 'Magento_Module', - 'type:file|area:frontend|theme:magento_theme|locale:|module:Magento_Module|file:file.ext', - 'four/file.ext', - ], - 'no module' => [ - 'frontend', 'magento_theme', 'en_US', null, - 'type:file|area:frontend|theme:magento_theme|locale:en_US|module:|file:file.ext', - 'five/file.ext', - ], - ]; - } -} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/CacheData/GroupedTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/CacheData/GroupedTest.php deleted file mode 100644 index e233a9b0e3abf56c79492495997140a4439ffa5b..0000000000000000000000000000000000000000 --- a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/CacheData/GroupedTest.php +++ /dev/null @@ -1,200 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -// @codingStandardsIgnoreFile - -namespace Magento\Framework\View\Test\Unit\Design\FileResolution\Fallback\CacheData; - -use \Magento\Framework\View\Design\FileResolution\Fallback\CacheData\Grouped; - -class GroupedTest extends \PHPUnit_Framework_TestCase -{ - /** - * @var \Magento\Framework\View\Design\FileResolution\Fallback\Cache|\PHPUnit_Framework_MockObject_MockObject - */ - private $cache; - - /** - * @var \Magento\Framework\View\Design\ThemeInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $theme; - - /** - * @var Grouped - */ - private $object; - - protected function setUp() - { - $this->cache = $this->getMock( - '\Magento\Framework\View\Design\FileResolution\Fallback\Cache', [], [], '', false - ); - - $this->theme = $this->getMockForAbstractClass('\Magento\Framework\View\Design\ThemeInterface'); - - $this->object = new \Magento\Framework\View\Design\FileResolution\Fallback\CacheData\Grouped($this->cache); - } - - /** - * @param string $area - * @param string $themePath - * @param string $locale - * @param string $module - * @param array $files - * - * @dataProvider getFromCacheDataProvider - */ - public function testGetFromCache($area, $themePath, $locale, $module, array $files) - { - if (isset($params['theme'])) { - $this->theme->expects($this->any()) - ->method('getThemePath') - ->will($this->returnValue($params['theme'])); - $params['theme'] = $this->theme; - } else { - $this->theme->expects($this->never()) - ->method('getThemePath'); - } - - $cachedSections = [ - 'type:file|area:frontend|theme:magento_theme|locale:en_US' => [ - 'module:Magento_Module|file:file.ext' => 'one/file.ext', - 'module:Magento_Module|file:other_file.ext' => 'one/other_file.ext', - 'module:|file:file.ext' => 'two/file.ext', - 'module:|file:other_file.ext' => 'two/other_file.ext', - ], - 'type:file|area:frontend|theme:magento_theme|locale:' => [ - 'module:Magento_Module|file:file.ext' => 'three/file.ext', - 'module:Magento_Module|file:other_file.ext' => 'four/other_file.ext', - ], - 'type:file|area:frontend|theme:|locale:en_US' => [ - 'module:Magento_Module|file:file.ext' => 'five/file.ext', - 'module:Magento_Module|file:other_file.ext' => 'five/other_file.ext', - ], - 'type:file|area:|theme:magento_theme|locale:en_US' => [ - 'module:Magento_Module|file:file.ext' => 'seven/file.ext', - 'module:Magento_Module|file:other_file.ext' => 'other_file.ext', - ], - ]; - - $this->cache->expects($this->once()) - ->method('load') - ->will($this->returnCallback(function ($sectionId) use ($cachedSections) { - if (!isset($cachedSections[$sectionId])) { - return false; - } - return json_encode($cachedSections[$sectionId]); - })); - - foreach ($files as $requested => $expected) { - $actual = $this->object->getFromCache('file', $requested, $area, $themePath, $locale, $module); - $this->assertSame($expected, $actual); - } - } - - /** - * @return array - */ - public function getFromCacheDataProvider() - { - return [ - 'all params' => [ - 'frontend', 'magento_theme', 'en_US', 'Magento_Module', - ['file.ext' => 'one/file.ext', 'other_file.ext' => 'one/other_file.ext'], - ], - 'no area' => [ - null, 'magento_theme', 'en_US', 'Magento_Module', - ['file.ext' => 'seven/file.ext', 'other_file.ext' => 'other_file.ext'], - ], - 'no theme' => [ - 'frontend', null, 'en_US', 'Magento_Module', - ['file.ext' => 'five/file.ext', 'other_file.ext' => 'five/other_file.ext'], - ], - 'no locale' => [ - 'frontend', 'magento_theme', null, 'Magento_Module', - ['file.ext' => 'three/file.ext', 'other_file.ext' => 'four/other_file.ext'], - ], - 'no module' => [ - 'frontend', 'magento_theme', 'en_US', null, - ['file.ext' => 'two/file.ext', 'other_file.ext' => 'two/other_file.ext'], - ], - ]; - } - - /** - * Verify that one and only one attempt to load cache is done even in case of cache absence - */ - public function testGetFromCacheNothing() - { - $this->cache->expects($this->once()) - ->method('load'); - $this->assertFalse($this->object->getFromCache('type', 'file.ext', - 'frontend', 'magento_theme', 'en_US', 'Magento_Module')); - $this->assertFalse($this->object->getFromCache('type', 'file.ext', - 'frontend', 'magento_theme', 'en_US', 'Magento_Module')); - } - - /** - * Ensure that cache is saved once and only once per section - */ - public function testSaveToCache() - { - $this->cache->expects($this->exactly(2)) - ->method('save') - ->will($this->returnValueMap([ - [ - json_encode([ - 'module:Magento_Module|file:file.ext' => 'some/file.ext', - 'module:Magento_Module|file:other_file.ext' => 'some/other_file.ext', - ]), - 'type:file|area:frontend|theme:|locale:en_US', - true, - ], - [ - json_encode(['module:Magento_Module|file:file.ext' => 'some/other/file.ext']), - 'type:view|area:backend|theme:|locale:en_US', - true, - ], - ])); - - $this->object->saveToCache('some/file.ext', 'file', 'file.ext', - 'frontend', 'magento_theme', 'en_US', 'Magento_Module'); - $this->object->saveToCache('some/other_file.ext', 'file', 'other_file.ext', - 'frontend', 'magento_theme', 'en_US', 'Magento_Module'); - $this->object->saveToCache('some/other/file.ext', 'view', 'file.ext', - 'backend', 'magento_theme', 'en_US', 'Magento_Module'); - - $this->object = null; - } - - /** - * Verify that no attempt to save cache is done, when nothing is updated - */ - public function testSaveToCacheNothing() - { - $this->cache->expects($this->never()) - ->method('save'); - $this->object = null; - } - - /** - * Ensure that same data is not saved again - */ - public function testSaveToCacheNotDirty() - { - $this->cache->expects($this->never()) - ->method('save'); - $this->cache->expects($this->once()) - ->method('load') - ->with('type:file|area:frontend|theme:magento_theme|locale:en_US') - ->will($this->returnValue(json_encode(['module:Magento_Module|file:file.ext' => 'some/file.ext']))); - - $this->object->saveToCache('some/file.ext', 'file', 'file.ext', - 'frontend', 'magento_theme', 'en_US', 'Magento_Module'); - - $this->object = null; - } -} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/AlternativeTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/AlternativeTest.php index c7535bcafa118024c052c4bed6cbc5f8e504755a..2dbaa2e6c60668b0c5be4fbfef55d593116f8393 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/AlternativeTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/AlternativeTest.php @@ -48,13 +48,7 @@ class AlternativeTest extends \PHPUnit_Framework_TestCase ->method('getRule') ->with('type') ->will($this->returnValue($this->rule)); - $cache = $this->getMockForAbstractClass( - 'Magento\Framework\View\Design\FileResolution\Fallback\CacheDataInterface' - ); - $cache->expects($this->any()) - ->method('getFromCache') - ->will($this->returnValue(false)); - $this->object = new Alternative($filesystem, $rulePool, $cache, ['css' => ['less']]); + $this->object = new Alternative($filesystem, $rulePool, ['css' => ['less']]); } /** @@ -69,10 +63,7 @@ class AlternativeTest extends \PHPUnit_Framework_TestCase $filesystem = $this->getMock('Magento\Framework\Filesystem', [], [], '', false); $rulePool = $this->getMock('Magento\Framework\View\Design\Fallback\RulePool', [], [], '', false); - $cache = $this->getMockForAbstractClass( - 'Magento\Framework\View\Design\FileResolution\Fallback\CacheDataInterface' - ); - new Alternative($filesystem, $rulePool, $cache, $alternativeExtensions); + new Alternative($filesystem, $rulePool, $alternativeExtensions); } /** diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/MinificationTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/MinificationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..87368463845b035a39d88e6be8b652523b2989c8 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/MinificationTest.php @@ -0,0 +1,101 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\View\Test\Unit\Design\FileResolution\Fallback\Resolver; + +use Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Minification; +use Magento\Framework\View\Design\FileResolution\Fallback\ResolverInterface; + +/** + * Unit test for Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Minification + */ +class MinificationTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Minification + */ + protected $minification; + + /** + * @var ResolverInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $resolverMock; + + /** + * @var \Magento\Framework\View\Asset\Minification|\PHPUnit_Framework_MockObject_MockObject + */ + protected $assetMinificationMock; + /** + * {@inheritDoc} + */ + protected function setUp() + { + $this->resolverMock = $this + ->getMockBuilder('Magento\Framework\View\Design\FileResolution\Fallback\ResolverInterface') + ->disableOriginalConstructor() + ->getMock(); + + $this->assetMinificationMock = $this->getMockBuilder('Magento\Framework\View\Asset\Minification') + ->disableOriginalConstructor() + ->getMock(); + + $this->minification = new Minification( + $this->resolverMock, + $this->assetMinificationMock + ); + } + + /** + * @param bool $isEnabled + * @param string $requested + * @param string $alternative + * @param string $expected + * @param string $resolvedOriginal + * @param string $resolvedAlternative + * @return void + * @dataProvider resolveDataProvider + */ + public function testResolve( + $isEnabled, + $requested, + $alternative, + $expected, + $resolvedOriginal, + $resolvedAlternative + ) { + $this->assetMinificationMock + ->expects($this->any()) + ->method('isEnabled') + ->willReturnMap([['css', $isEnabled]]); + $this->assetMinificationMock + ->expects($this->any()) + ->method('removeMinifiedSign') + ->with($requested) + ->willReturn($alternative); + + $this->resolverMock + ->expects($this->any()) + ->method('resolve') + ->withConsecutive( + ['', $requested, null, null, null, null], + ['', $alternative, null, null, null, null] + ) + ->willReturnOnConsecutiveCalls($resolvedOriginal, $resolvedAlternative); + + $this->assertEquals($expected, $this->minification->resolve('', $requested)); + } + + /** + * @return array + */ + public function resolveDataProvider() + { + return [ + [true, 'file.min.css', 'file.css', 'found.css', false, 'found.css'], + [false, 'file.min.css', 'file.min.css', false, false, 'found.css'] + ]; + } +} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/SimpleTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/SimpleTest.php index 1c3ce3d36f93f702ae43223409c3a6b77d30c20c..35f55d4d69ae5c184cc7b4cab18d8d414d4482df 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/SimpleTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/Resolver/SimpleTest.php @@ -24,11 +24,6 @@ class SimpleTest extends \PHPUnit_Framework_TestCase */ private $rule; - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - private $cache; - /** * @var \Magento\Framework\View\Design\FileResolution\Fallback\Resolver\Simple */ @@ -53,15 +48,11 @@ class SimpleTest extends \PHPUnit_Framework_TestCase ->method('getRule') ->with('type') ->will($this->returnValue($this->rule)); - $this->cache = $this->getMockForAbstractClass( - 'Magento\Framework\View\Design\FileResolution\Fallback\CacheDataInterface' - ); - $this->object = new Simple($filesystem, $rulePool, $this->cache); + + $this->object = new Simple($filesystem, $rulePool); } /** - * Cache is empty - * * @param string $area * @param string $themePath * @param string $locale @@ -78,10 +69,6 @@ class SimpleTest extends \PHPUnit_Framework_TestCase $expectedParams['theme'] = $this->getMockForTheme($expectedParams['theme']); } - $this->cache->expects($this->once()) - ->method('getFromCache') - ->with('type', 'file.ext', $area, $themePath, $locale, $module) - ->will($this->returnValue(false)); $this->directory->expects($this->never()) ->method('getAbsolutePath'); $this->rule->expects($this->once()) @@ -92,10 +79,7 @@ class SimpleTest extends \PHPUnit_Framework_TestCase ->method('isExist') ->with($expectedPath) ->will($this->returnValue(true)); - $this->cache->expects($this->once()) - ->method('saveToCache') - ->with($expectedPath, 'type', 'file.ext', $area, $themePath, $locale, $module); - $actualPath = $this->object->resolve( + $actualPath = $this->object->resolve( 'type', 'file.ext', $area, $theme, $locale, $module ); $this->assertSame($expectedPath, $actualPath); @@ -166,16 +150,10 @@ class SimpleTest extends \PHPUnit_Framework_TestCase public function testResolveNoPatterns() { - $this->cache->expects($this->once()) - ->method('getFromCache') - ->with('type', 'file.ext', 'frontend', 'magento_theme', 'en_US', 'Magento_Module') - ->will($this->returnValue(false)); $this->rule->expects($this->once()) ->method('getPatternDirs') ->will($this->returnValue([])); - $this->cache->expects($this->once()) - ->method('saveToCache') - ->with('', 'type', 'file.ext', 'frontend', 'magento_theme', 'en_US', 'Magento_Module'); + $this->assertFalse( $this->object->resolve( 'type', 'file.ext', 'frontend', $this->getMockForTheme('magento_theme'), 'en_US', 'Magento_Module' @@ -185,19 +163,12 @@ class SimpleTest extends \PHPUnit_Framework_TestCase public function testResolveNonexistentFile() { - $this->cache->expects($this->once()) - ->method('getFromCache') - ->with('type', 'file.ext', 'frontend', 'magento_theme', 'en_US', 'Magento_Module') - ->will($this->returnValue(false)); $this->rule->expects($this->once()) ->method('getPatternDirs') ->will($this->returnValue(['some/dir'])); $this->directory->expects($this->once()) ->method('isExist') ->will($this->returnValue(false)); - $this->cache->expects($this->once()) - ->method('saveToCache') - ->with('', 'type', 'file.ext', 'frontend', 'magento_theme', 'en_US', 'Magento_Module'); $this->assertFalse( $this->object->resolve( 'type', 'file.ext', 'frontend', $this->getMockForTheme('magento_theme'), 'en_US', 'Magento_Module' @@ -205,28 +176,6 @@ class SimpleTest extends \PHPUnit_Framework_TestCase ); } - public function testResolveFromCache() - { - $expectedPath = '/some/dir/file.ext'; - - $this->cache->expects($this->once()) - ->method('getFromCache') - ->with('type', 'file.ext', 'frontend', 'magento_theme', 'en_US', 'Magento_Module') - ->will($this->returnValue($expectedPath)); - $this->directory->expects($this->once()) - ->method('getAbsolutePath') - ->with($expectedPath) - ->will($this->returnValue($expectedPath)); - $this->rule->expects($this->never()) - ->method('getPatternDirs'); - $this->cache->expects($this->never()) - ->method('saveToCache'); - $actualPath = $this->object->resolve( - 'type', 'file.ext', 'frontend', $this->getMockForTheme('magento_theme'), 'en_US', 'Magento_Module' - ); - $this->assertSame($expectedPath, $actualPath); - } - /** * @param string $themePath * @return \Magento\Framework\View\Design\ThemeInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/RendererTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/RendererTest.php index 2917b75f726441b8b1b9f1e0e643c02ea19f3f12..cd938b2bce90086d33788ac06d609ff8955894f5 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/RendererTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/RendererTest.php @@ -28,11 +28,6 @@ class RendererTest extends \PHPUnit_Framework_TestCase */ protected $pageConfigMock; - /** - * @var \Magento\Framework\View\Asset\MinifyService|\PHPUnit_Framework_MockObject_MockObject - */ - protected $assetMinifyServiceMock; - /** * @var \Magento\Framework\View\Asset\AssetInterface|\PHPUnit_Framework_MockObject_MockObject */ @@ -84,11 +79,6 @@ class RendererTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); - $this->assetMinifyServiceMock = $this->getMockBuilder('Magento\Framework\View\Asset\MinifyService') - ->setMethods(['getAssets']) - ->disableOriginalConstructor() - ->getMock(); - $this->assetMergeServiceMock = $this->getMockBuilder('Magento\Framework\View\Asset\MergeService') ->disableOriginalConstructor() ->getMock(); @@ -126,7 +116,6 @@ class RendererTest extends \PHPUnit_Framework_TestCase 'Magento\Framework\View\Page\Config\Renderer', [ 'pageConfig' => $this->pageConfigMock, - 'assetMinifyService' => $this->assetMinifyServiceMock, 'assetMergeService' => $this->assetMergeServiceMock, 'urlBuilder' => $this->urlBuilderMock, 'escaper' => $this->escaperMock, @@ -318,10 +307,6 @@ class RendererTest extends \PHPUnit_Framework_TestCase ->method('getGroups') ->willReturn([$groupMockOne, $groupMockTwo]); - $this->assetMinifyServiceMock->expects($this->exactly(2)) - ->method('getAssets') - ->willReturnArgument(0); - $this->assetMergeServiceMock->expects($this->exactly(1)) ->method('getMergedAssets') ->willReturnArgument(0); diff --git a/lib/internal/Magento/Framework/Xml/Security.php b/lib/internal/Magento/Framework/Xml/Security.php new file mode 100644 index 0000000000000000000000000000000000000000..1fade0a2aec7e0a48389168536a452559f1f0222 --- /dev/null +++ b/lib/internal/Magento/Framework/Xml/Security.php @@ -0,0 +1,95 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Xml; + +use DOMDocument; +use Magento\Framework\Phrase; + +/** + * Class Security + */ +class Security +{ + /** + * Heuristic scan to detect entity in XML + * + * @param string $xmlContent + * @return bool + */ + private function heuristicScan($xmlContent) + { + return strpos($xmlContent, '<!ENTITY') !== false; + } + + /** + * Return true if PHP is running with PHP-FPM + * + * @return bool + */ + private function isPhpFpm() + { + return substr(php_sapi_name(), 0, 3) === 'fpm'; + } + + /** + * Security check loaded XML document + * + * @param string $xmlContent + * @return bool + * + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + */ + public function scan($xmlContent) + { + /** + * If running with PHP-FPM we perform an heuristic scan + * We cannot use libxml_disable_entity_loader because of this bug + * @see https://bugs.php.net/bug.php?id=64938 + */ + if ($this->isPhpFpm()) { + return $this->heuristicScan($xmlContent); + } + + $document = new DOMDocument(); + + $loadEntities = libxml_disable_entity_loader(true); + $useInternalXmlErrors = libxml_use_internal_errors(true); + + /** + * Load XML with network access disabled (LIBXML_NONET) + * error disabled with @ for PHP-FPM scenario + */ + set_error_handler( + function ($errno, $errstr) { + if (substr_count($errstr, 'DOMDocument::loadXML()') > 0) { + return true; + } + return false; + }, + E_WARNING + ); + + $result = (bool)$document->loadXml($xmlContent, LIBXML_NONET); + restore_error_handler(); + // Entity load to previous setting + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($useInternalXmlErrors); + + if (!$result) { + return false; + } + + foreach ($document->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + if ($child->entities->length > 0) { + return false; + } + } + } + + return true; + } +} diff --git a/lib/internal/Magento/Framework/Xml/Test/Unit/SecurityTest.php b/lib/internal/Magento/Framework/Xml/Test/Unit/SecurityTest.php new file mode 100644 index 0000000000000000000000000000000000000000..afa5c86c1b44e74527614487e8c15cc6a6072cf0 --- /dev/null +++ b/lib/internal/Magento/Framework/Xml/Test/Unit/SecurityTest.php @@ -0,0 +1,81 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Xml\Test\Unit; + +use Magento\Framework\Xml\Security; + +/** + * Class SecurityTest + * + * Test for class \Magento\Framework\Xml\Security + */ +class SecurityTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var Security + */ + protected $security; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->security = new Security(); + } + + /** + * Run test scan method + * + * @param string $xmlContent + * @param bool $expectedResult + * + * @dataProvider dataProviderTestScan + */ + public function testScan($xmlContent, $expectedResult) + { + $this->assertEquals($expectedResult, $this->security->scan($xmlContent)); + } + + /** + * Data provider for testScan + * + * @return array + */ + public function dataProviderTestScan() + { + return [ + [ + 'xmlContent' => '<?xml version="1.0"?><test></test>', + 'expectedResult' => true + ], + [ + 'xmlContent' => '<!DOCTYPE note SYSTEM "Note.dtd"><?xml version="1.0"?><test></test>', + 'expectedResult' => false + ], + [ + 'xmlContent' => '<?xml version="1.0"?> + <!DOCTYPE test [ + <!ENTITY value "value"> + <!ENTITY value1 "&value;&value;&value;&value;&value;&value;&value;&value;&value;&value;"> + <!ENTITY value2 "&value1;&value1;&value1;&value1;&value1;&value1;&value1;&value1;&value1;&value1;"> + ]> + <test>&value2;</test>', + 'expectedResult' => false + ], + [ + 'xmlContent' => '<!DOCTYPE html><?xml version="1.0"?><test></test>', + 'expectedResult' => false + ], + [ + 'xmlContent' => '', + 'expectedResult' => false + ] + ]; + } +} diff --git a/lib/web/mage/validation.js b/lib/web/mage/validation.js index 78cc93607e66e6b1052a2590e28305a118c4253d..98240eb8cfa40797c4efd0e6c222397857ddb7bd 100644 --- a/lib/web/mage/validation.js +++ b/lib/web/mage/validation.js @@ -22,16 +22,16 @@ /** * Check if string is empty with trim * @param {string} value - */ - isEmpty: function(value) { - return (value === '' || value === undefined || (value == null) || (value.length === 0) || /^\s+$/.test(value)); + */ + isEmpty: function (value) { + return (value === '' || value === undefined || (value == null) || (value.length === 0) || /^\s+$/.test(value)); }, /** * Check if string is empty no trim * @param {string} value - */ - isEmptyNoTrim: function(value) { + */ + isEmptyNoTrim: function (value) { return (value === '' || (value == null) || (value.length === 0)); }, @@ -43,16 +43,16 @@ * @param {string} to * @returns {boolean} */ - isBetween: function(value, from, to){ + isBetween: function (value, from, to) { return ($.mage.isEmpty(from) || value >= $.mage.parseNumber(from)) && - ($.mage.isEmpty(to) || value <= $.mage.parseNumber(to)); + ($.mage.isEmpty(to) || value <= $.mage.parseNumber(to)); }, /** * Parse price string * @param {string} value - */ - parseNumber: function(value) { + */ + parseNumber: function (value) { if (typeof value !== 'string') { return parseFloat(value); } @@ -75,7 +75,7 @@ * @param value Value being stripped. * @return {*} */ - stripHtml: function(value) { + stripHtml: function (value) { return value.replace(/<.[^<>]*?>/g, ' ').replace(/ | /gi, ' ') .replace(/[0-9.(),;:!?%#$'"_+=\/-]*/g, ''); } @@ -85,7 +85,7 @@ $.validator.addMethod = function (name, method, message, dontSkip) { $.validator.methods[name] = method; $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name]; - + if (method.length < 3 || dontSkip) { $.validator.addClassRules(name, $.validator.normalizeRule(name)); } @@ -146,63 +146,63 @@ */ var rules = { "max-words": [ - function(value, element, params) { + function (value, element, params) { return this.optional(element) || $.mage.stripHtml(value).match(/\b\w+\b/g).length < params; }, 'Please enter {0} words or less.' ], "min-words": [ - function(value, element, params) { + function (value, element, params) { return this.optional(element) || $.mage.stripHtml(value).match(/\b\w+\b/g).length >= params; }, 'Please enter at least {0} words.' ], "range-words": [ - function(value, element, params) { + function (value, element, params) { return this.optional(element) || $.mage.stripHtml(value).match(/\b\w+\b/g).length >= params[0] && - value.match(/bw+b/g).length < params[1]; + value.match(/bw+b/g).length < params[1]; }, 'Please enter between {0} and {1} words.' ], "letters-with-basic-punc": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^[a-z\-.,()'\"\s]+$/i.test(value); }, 'Letters or punctuation only please' ], "alphanumeric": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^\w+$/i.test(value); }, 'Letters, numbers, spaces or underscores only please' ], "letters-only": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^[a-z]+$/i.test(value); }, 'Letters only please' ], "no-whitespace": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^\S+$/i.test(value); }, 'No white space please' ], "zip-range": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^90[2-5]-\d{2}-\d{4}$/.test(value); }, 'Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx' ], "integer": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^-?\d+$/.test(value); }, 'A positive or negative non-decimal number please' ], "vinUS": [ - function(v) { + function (v) { if (v.length !== 17) { return false; } @@ -245,7 +245,7 @@ 'The specified vehicle identification number (VIN) is invalid.' ], "dateITA": [ - function(value, element) { + function (value, element) { var check = false; var re = /^\d{1,2}\/\d{1,2}\/\d{4}$/; if (re.test(value)) { @@ -268,25 +268,25 @@ 'Please enter a correct date' ], "dateNL": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^\d\d?[\.\/-]\d\d?[\.\/-]\d\d\d?\d?$/.test(value); }, 'Vul hier een geldige datum in.' ], "time": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^([01]\d|2[0-3])(:[0-5]\d){0,2}$/.test(value); }, 'Please enter a valid time, between 00:00 and 23:59' ], "time12h": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AP]M))$/i.test(value); }, 'Please enter a valid time, between 00:00 am and 12:00 pm' ], "phoneUS": [ - function(phone_number, element) { + function (phone_number, element) { phone_number = phone_number.replace(/\s+/g, ""); return this.optional(element) || phone_number.length > 9 && phone_number.match(/^(1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/); @@ -294,39 +294,39 @@ 'Please specify a valid phone number' ], "phoneUK": [ - function(phone_number, element) { + function (phone_number, element) { return this.optional(element) || phone_number.length > 9 && phone_number.match(/^(\(?(0|\+44)[1-9]{1}\d{1,4}?\)?\s?\d{3,4}\s?\d{3,4})$/); }, 'Please specify a valid phone number' ], "mobileUK": [ - function(phone_number, element) { + function (phone_number, element) { return this.optional(element) || phone_number.length > 9 && phone_number.match(/^((0|\+44)7(5|6|7|8|9){1}\d{2}\s?\d{6})$/); }, 'Please specify a valid mobile number' ], "stripped-min-length": [ - function(value, element, param) { + function (value, element, param) { return $(value).text().length >= param; }, 'Please enter at least {0} characters' ], "email2": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value); }, $.validator.messages.email ], "url2": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value); }, $.validator.messages.url ], "credit-card-types": [ - function(value, element, param) { + function (value, element, param) { if (/[^0-9-]+/.test(value)) { return false; } @@ -393,25 +393,25 @@ 'Please enter a valid credit card number.' ], "ipv4": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i.test(value); }, 'Please enter a valid IP v4 address.' ], "ipv6": [ - function(value, element) { + function (value, element) { return this.optional(element) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value); }, 'Please enter a valid IP v6 address.' ], "pattern": [ - function(value, element, param) { + function (value, element, param) { return this.optional(element) || param.test(value); }, 'Invalid format.' ], "allow-container-className": [ - function(element) { + function (element) { if (element.type === 'radio' || element.type === 'checkbox') { return $(element).hasClass('change-container-classname'); } @@ -419,73 +419,73 @@ '' ], "validate-no-html-tags": [ - function(value) { + function (value) { return !/<(\/)?\w+/.test(value); }, 'HTML tags are not allowed.' ], "validate-select": [ - function(value) { + function (value) { return ((value !== "none") && (value != null) && (value.length !== 0)); }, 'Please select an option.' ], "validate-no-empty": [ - function(value) { + function (value) { return !$.mage.isEmpty(value); }, 'Empty Value.' ], "validate-alphanum-with-spaces": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z0-9 ]+$/.test(v); }, 'Please use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.' ], "validate-data": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^[A-Za-z]+[A-Za-z0-9_]+$/.test(v); }, 'Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.' ], "validate-street": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^[ \w]{3,}([A-Za-z]\.)?([ \w]*\#\d+)?(\r\n| )[ \w]{3,}/.test(v); }, 'Please use only letters (a-z or A-Z), numbers (0-9), spaces and "#" in this field.' ], "validate-phoneStrict": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v); }, 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.' ], "validate-phoneLax": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^((\d[\-. ]?)?((\(\d{3}\))|\d{3}))?[\-. ]?\d{3}[\-. ]?\d{4}$/.test(v); }, 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.' ], "validate-fax": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v); }, 'Please enter a valid fax number (Ex: 123-456-7890).' ], "validate-email": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*@([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*\.(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]){2,})$/i.test(v); }, 'Please enter a valid email address (Ex: johndoe@domain.com).' ], "validate-emailSender": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^[\S ]+$/.test(v); }, 'Please enter a valid email address (Ex: johndoe@domain.com).' ], "validate-password": [ - function(v) { + function (v) { if (v == null) { return false; } @@ -499,7 +499,7 @@ 'Please enter 6 or more characters. Leading or trailing spaces will be ignored.' ], "validate-admin-password": [ - function(v) { + function (v) { if (v == null) { return false; } @@ -519,7 +519,7 @@ 'Please enter 7 or more characters, using both numeric and alphabetic.' ], "validate-url": [ - function(v) { + function (v) { if ($.mage.isEmptyNoTrim(v)) { return true; } @@ -530,35 +530,35 @@ 'Please enter a valid URL. Protocol is required (http://, https:// or ftp://).' ], "validate-clean-url": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i.test(v) || /^(www)((\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i.test(v); }, 'Please enter a valid URL. For example http://www.example.com or www.example.com.' ], "validate-xml-identifier": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^[A-Z][A-Z0-9_\/-]*$/i.test(v); }, 'Please enter a valid XML-identifier (Ex: something_1, block5, id-4).' ], "validate-ssn": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^\d{3}-?\d{2}-?\d{4}$/.test(v); }, 'Please enter a valid social security number (Ex: 123-45-6789).' ], "validate-zip-us": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /(^\d{5}$)|(^\d{5}-\d{4}$)/.test(v); }, 'Please enter a valid zip code (Ex: 90602 or 90602-1234).' ], "validate-date-au": [ - function(v) { + function (v) { if ($.mage.isEmptyNoTrim(v)) { return true; } @@ -575,14 +575,14 @@ 'Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.' ], "validate-currency-dollar": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/.test(v); }, 'Please enter a valid $ amount. For example $100.00.' ], "validate-not-negative-number": [ - function(v) { + function (v) { if ($.mage.isEmptyNoTrim(v)) { return true; } @@ -594,7 +594,7 @@ ], // validate-not-negative-number should be replaced in all places with this one and then removed "validate-zero-or-greater": [ - function(v) { + function (v) { if ($.mage.isEmptyNoTrim(v)) { return true; } @@ -605,7 +605,7 @@ 'Please enter a number 0 or greater in this field.' ], "validate-greater-than-zero": [ - function(v) { + function (v) { if ($.mage.isEmptyNoTrim(v)) { return true; } @@ -615,7 +615,7 @@ 'Please enter a number greater than 0 in this field.' ], "validate-css-length": [ - function(v) { + function (v) { if (v !== '') { return (/^[0-9]*\.*[0-9]+(px|pc|pt|ex|em|mm|cm|in|%)?$/).test(v); } @@ -625,19 +625,19 @@ ], /** @description Additional methods */ "validate-number": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || (!isNaN($.mage.parseNumber(v)) && /^\s*-?\d*(\.\d*)?\s*$/.test(v)); }, 'Please enter a valid number in this field.' ], "required-number": [ - function(v){ + function (v) { return !!v.length; }, 'Please enter a valid number in this field.' ], "validate-number-range": [ - function(v, elm, param) { + function (v, elm, param) { if ($.mage.isEmptyNoTrim(v)) { return true; } @@ -658,7 +658,7 @@ if (m) { result = result && $.mage.isBetween(numValue, m[1], m[2]); } - } else if (elm && elm.className ) { + } else if (elm && elm.className) { classes = elm.className.split(" "); ii = classes.length; @@ -678,13 +678,13 @@ true ], "validate-digits": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || !/[^\d]/.test(v); }, 'Please enter a valid number in this field.' ], "validate-digits-range": [ - function(v, elm, param) { + function (v, elm, param) { if ($.mage.isEmptyNoTrim(v)) { return true; } @@ -699,13 +699,13 @@ result = true, range, m, classes, ii; range = param; - + if (typeof range === 'object') { m = dataAttrRange.exec(range); if (m) { result = result && $.mage.isBetween(numValue, m[1], m[2]); } - } else if (elm && elm.className ) { + } else if (elm && elm.className) { classes = elm.className.split(" "); ii = classes.length; @@ -725,7 +725,7 @@ true ], 'validate-range': [ - function(v, elm) { + function (v, elm) { var minValue, maxValue; if ($.mage.isEmptyNoTrim(v)) { return true; @@ -756,8 +756,8 @@ var minValidRange = $.mage.parseNumber(validRange[1]); var maxValidRange = $.mage.parseNumber(validRange[2]); result = result && - (isNaN(minValidRange) || minValue >= minValidRange) && - (isNaN(maxValidRange) || maxValue <= maxValidRange); + (isNaN(minValidRange) || minValue >= minValidRange) && + (isNaN(maxValidRange) || maxValue <= maxValidRange); } } return result; @@ -765,39 +765,39 @@ 'The value is not within the specified range.' ], "validate-alpha": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z]+$/.test(v); }, 'Please use letters only (a-z or A-Z) in this field.' ], "validate-code": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^[a-z]+[a-z0-9_]+$/.test(v); }, 'Please use only letters (a-z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.' ], "validate-alphanum": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z0-9]+$/.test(v); }, 'Please use only letters (a-z or A-Z) or numbers (0-9) in this field. No spaces or other characters are allowed.' ], "validate-date": [ - function(v) { + function (v) { var test = new Date(v); return $.mage.isEmptyNoTrim(v) || !isNaN(test); - },'Please enter a valid date.' + }, 'Please enter a valid date.' ], "validate-date-range": [ - function(v, elm) { + function (v, elm) { var m = /\bdate-range-(\w+)-(\w+)\b/.exec(elm.className); if (!m || m[2] === 'to' || $.mage.isEmptyNoTrim(v)) { return true; } var currentYear = new Date().getFullYear() + ''; - var normalizedTime = function(v) { + var normalizedTime = function (v) { v = v.split(/[.\/]/); if (v[2] && v[2].length < 4) { v[2] = currentYear.substr(0, v[2].length) + v[2]; @@ -812,7 +812,7 @@ 'Make sure the To Date is later than or the same as the From Date.' ], "validate-cpassword": [ - function() { + function () { var conf = $('#confirmation').length > 0 ? $('#confirmation') : $($('.validate-cpassword')[0]); var pass = false; if ($('#password')) { @@ -833,7 +833,7 @@ 'Please make sure your passwords match.' ], "validate-identifier": [ - function(v) { + function (v) { return $.mage.isEmptyNoTrim(v) || /^[a-z0-9][a-z0-9_\/-]+(\.[a-z0-9_-]+)?$/.test(v); }, 'Please enter a valid URL Key (Ex: "example-page", "example-page.html" or "anotherlevel/example-page").' @@ -843,29 +843,29 @@ // @TODO: Cleanup return Validation.get('IsEmpty').test(v) || /(^[A-z0-9]{2,10}([\s]{0,1}|[\-]{0,1})[A-z0-9]{2,10}$)/.test(v); }*/ - function() { + function () { return true; }, 'Please enter a valid zip code.' ], "validate-one-required": [ - function(v, elm) { + function (v, elm) { var p = $(elm).parent(); var options = p.find('input'); - return options.map(function(elm) { - return $(elm).val(); - }).length > 0; + return options.map(function (elm) { + return $(elm).val(); + }).length > 0; }, 'Please select one of the options above.' ], "validate-state": [ - function(v) { + function (v) { return (v !== 0 || v === ''); }, 'Please select State/Province.' ], "required-file": [ - function(v, elm) { + function (v, elm) { var result = !$.mage.isEmptyNoTrim(v); if (!result) { var ovId = $(elm).attr('id') + '_value'; @@ -878,9 +878,9 @@ 'Please select a file.' ], "validate-ajax-error": [ - function(v, element) { + function (v, element) { element = $(element); - element.on('change.ajaxError', function() { + element.on('change.ajaxError', function () { element.removeClass('validate-ajax-error'); element.off('change.ajaxError'); }); @@ -889,7 +889,7 @@ '' ], "validate-optional-datetime": [ - function(v, elm, param) { + function (v, elm, param) { var dateTimeParts = $('.datetime-picker[id^="options_' + param + '"]'), hasWithValue = false, hasWithNoValue = false, pattern = /day_part$/i; @@ -907,7 +907,7 @@ 'The field isn\'t complete.' ], "validate-required-datetime": [ - function(v, elm, param) { + function (v, elm, param) { var dateTimeParts = $('.datetime-picker[id^="options_' + param + '"]'); for (var i = 0; i < dateTimeParts.length; i++) { if (dateTimeParts[i].value === "") { @@ -919,43 +919,43 @@ 'This is a required field.' ], "validate-one-required-by-name": [ - function(v, elm, selector) { - var name = elm.name.replace(/([\\"])/g, '\\$1'), - container = this.currentForm, - selector = selector === true ? 'input[name="' + name + '"]:checked' : selector; - + function (v, elm, selector) { + var name = elm.name.replace(/([\\"])/g, '\\$1'), + container = this.currentForm, + selector = selector === true ? 'input[name="' + name + '"]:checked' : selector; + return !!container.querySelectorAll(selector).length; }, 'Please select one of the options.' ], "less-than-equals-to": [ - function(value, element, params) { + function (value, element, params) { if ($.isNumeric($(params).val()) && $.isNumeric(value)) { this.lteToVal = $(params).val(); return parseFloat(value) <= parseFloat($(params).val()); } return true; }, - function() { + function () { var message = $.mage.__('Please enter a value less than or equal to %s.'); return message.replace('%s', this.lteToVal); } ], "greater-than-equals-to": [ - function(value, element, params) { + function (value, element, params) { if ($.isNumeric($(params).val()) && $.isNumeric(value)) { this.gteToVal = $(params).val(); return parseFloat(value) >= parseFloat($(params).val()); } return true; }, - function() { + function () { var message = $.mage.__('Please enter a value greater than or equal to %s.'); return message.replace('%s', this.gteToVal); } ], "validate-emails": [ - function(value) { + function (value) { if ($.mage.isEmpty(value)) { return true; } @@ -978,7 +978,7 @@ * @param params - selector for credit card number * @return {boolean} */ - function(value, element, params) { + function (value, element, params) { if (value && params && creditCartTypes[value]) { return creditCartTypes[value][0].test($(params).val().replace(/\s+/g, '')); } @@ -991,7 +991,7 @@ * @param value - credit card number * @return {boolean} */ - function(value) { + function (value) { if (value) { return validateCreditCard(value); } @@ -1006,7 +1006,7 @@ * @param params - selector for credit card type * @return {boolean} */ - function(value, element, params) { + function (value, element, params) { if (value && params) { var ccType = $(params).val(); value = value.replace(/\s/g, '').replace(/\-/g, ''); @@ -1027,7 +1027,7 @@ * @param params - year selector * @return {Boolean} */ - function(value, element, params) { + function (value, element, params) { var isValid = false; if (value && params) { var month = value, @@ -1048,7 +1048,7 @@ * @param params - credit card type selector * @return {*} */ - function(value, element, params) { + function (value, element, params) { if (value && params) { var ccType = $(params).val(); if (creditCartTypes[ccType] && creditCartTypes[ccType][0]) { @@ -1064,19 +1064,19 @@ * @param value - input field value * @return {*} */ - function(value) { + function (value) { return value; }, 'Please enter issue number or start date for switch/solo card type.' ], "validate-length": [ - function(v, elm) { + function (v, elm) { var reMax = new RegExp(/^maximum-length-[0-9]+$/), reMin = new RegExp(/^minimum-length-[0-9]+$/), validator = this, result = true, length = 0; - $.each(elm.className.split(' '), function(index, name) { + $.each(elm.className.split(' '), function (index, name) { if (name.match(reMax) && result) { length = name.split('-')[2]; validator.attrLength = length; @@ -1088,18 +1088,18 @@ } }); return result; - }, function() { + }, function () { return $.mage.__("Maximum length of this field must be equal or less than %1 symbols.") .replace('%1', this.attrLength); } ], 'required-entry': [ - function(value) { + function (value) { return !$.mage.isEmpty(value); }, $.mage.__('This is a required field.') ], 'not-negative-amount': [ - function(v) { + function (v) { if (v.length) return (/^\s*\d+([,.]\d+)*\s*%?\s*$/).test(v); else @@ -1108,7 +1108,7 @@ 'Please enter positive number in this field.' ], 'validate-per-page-value-list': [ - function(v) { + function (v) { var isValid = !$.mage.isEmpty(v); var values = v.split(','); for (var i = 0; i < values.length; i++) { @@ -1121,7 +1121,7 @@ 'Please enter a valid value, ex: 10,20,30' ], 'validate-per-page-value': [ - function(v, elm) { + function (v, elm) { if ($.mage.isEmpty(v)) { return false; } @@ -1131,10 +1131,9 @@ 'Please enter a valid value from list' ], 'validate-new-password': [ - function(v) { + function (v) { - if ($.validator.methods['validate-password'] && - !$.validator.methods['validate-password'](v)) { + if ($.validator.methods['validate-password'] && !$.validator.methods['validate-password'](v)) { return false; } if ($.mage.isEmpty(v) && v !== '') { @@ -1168,6 +1167,19 @@ }, 'This is a required field.' ], + 'required-if-all-sku-empty': [ + function (value, element, params) { + var valid = false; + + $('input[' + params + '=true]').each(function () { + if ($(this).val() !== '') { + valid = true; + } + }); + + return valid; + }, 'Enter valid SKU key' + ], 'required-if-specified': [ function (value, element, params) { var valid = true; @@ -1194,9 +1206,9 @@ 'This is a required field.' ], 'required-number-if-specified': [ - function (value, element, params) { - var valid = true, - dependent = $(params), + function (value, element, params) { + var valid = true, + dependent = $(params), depeValue; if (dependent.length) { @@ -1219,8 +1231,8 @@ // validate quantity var isMinAllowedValid = typeof params.minAllowed === 'undefined' || (qty >= $.mage.parseNumber(params.minAllowed)); - var isMaxAllowedValid = typeof params.maxAllowed === 'undefined' || (qty <= $.mage.parseNumber(params.maxAllowed)); - var isQtyIncrementsValid = typeof params.qtyIncrements === 'undefined' || (qty % $.mage.parseNumber(params.qtyIncrements) === 0); + var isMaxAllowedValid = typeof params.maxAllowed === 'undefined' || (qty <= $.mage.parseNumber(params.maxAllowed)); + var isQtyIncrementsValid = typeof params.qtyIncrements === 'undefined' || (qty % $.mage.parseNumber(params.qtyIncrements) === 0); return isMaxAllowedValid && isMinAllowedValid && isQtyIncrementsValid && qty > 0; }, @@ -1228,7 +1240,7 @@ ] }; - $.each(rules, function(i, rule) { + $.each(rules, function (i, rule) { rule.unshift(i); $.validator.addMethod.apply($.validator, rule); }); @@ -1254,7 +1266,7 @@ var showLabel = $.validator.prototype.showLabel; $.extend(true, $.validator.prototype, { - showLabel: function(element, message) { + showLabel: function (element, message) { showLabel.call(this, element, message); // ARIA (adding aria-invalid & aria-describedby) @@ -1262,7 +1274,7 @@ elem = $(element); if (!label.attr('id')) { - label.attr('id', this.idOrName(element)+'-error'); + label.attr('id', this.idOrName(element) + '-error'); } elem.attr('aria-invalid', 'true') .attr('aria-describedby', label.attr('id')); @@ -1274,7 +1286,7 @@ * @param {Element||String} element - DOM element or selector * @return {Boolean} validation result */ - $.validator.validateElement = function(element) { + $.validator.validateElement = function (element) { element = $(element); var form = element.get(0).form, validator = form ? $(form).data('validator') : null; @@ -1284,7 +1296,7 @@ } else { var valid = true, classes = element.prop('class').split(' '); - $.each(classes, $.proxy(function(i, className) { + $.each(classes, $.proxy(function (i, className) { if (this.methods[className] && !this.methods[className](element.val(), element.get(0))) { valid = false; return valid; @@ -1303,7 +1315,7 @@ ignoreTitle: true, errorClass: 'mage-error', errorElement: 'div', - errorPlacement: function(error, element) { + errorPlacement: function (error, element) { var errorPlacement = element; // logic for date-picker error placement if (element.hasClass('hasDatepicker')) { @@ -1325,16 +1337,16 @@ * Check if form pass validation rules without submit * @return boolean */ - isValid: function() { + isValid: function () { return this.element.valid(); }, /** * Remove validation error messages */ - clearError: function() { + clearError: function () { if (arguments.length) { - $.each(arguments, $.proxy(function(index, item) { + $.each(arguments, $.proxy(function (index, item) { this.validate.prepareElement(item); this.validate.hideErrors(); }, this)); @@ -1346,7 +1358,7 @@ * Validation creation * @protected */ - _create: function() { + _create: function () { this.validate = this.element.validate(this.options); // ARIA (adding aria-required attribute) @@ -1362,7 +1374,7 @@ * Validation listening * @protected */ - _listenFormValidate: function() { + _listenFormValidate: function () { $('form').on('invalid-form.validate', function (event, validation) { var firstActive = $(validation.errorList[0].element || []), lastActive = $(validation.findLastActive() || validation.errorList.length && validation.errorList[0].element || []); @@ -1378,7 +1390,7 @@ // ARIA (removing aria attributes if success) var successList = validation.successList; if (successList.length) { - $.each(successList, function() { + $.each(successList, function () { $(this) .removeAttr('aria-describedby') .removeAttr('aria-invalid'); diff --git a/package.json b/package.json index c2f3cb1eaaf9edd5e19767c82f75782f022f1373..d65941df608b479bd6f769eae99ca0dc84166fd5 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,14 @@ "name": "Magento2", "author": "Magento, an eBay Inc. company", "description": "Magento2 node modules dependencies for local development", - "version": "0.74.0-beta7", + "version": "1.0.0-beta", "repository": { "type": "git", "url": "https://github.com/magento/magento2.git" }, "homepage": "http://magento.com/", "devDependencies": { + "glob": "^5.0.14", "grunt": "^0.4.5", "grunt-autoprefixer": "^2.0.0", "grunt-banner": "^0.4.0", @@ -19,15 +20,19 @@ "grunt-contrib-jasmine": "^0.8.1", "grunt-contrib-less": "^0.12.0", "grunt-contrib-watch": "^0.6.1", + "grunt-eslint": "^16.0.0", "grunt-exec": "^0.4.6", + "grunt-jscs": "^1.8.0", "grunt-replace": "^0.9.2", "grunt-styledocco": "^0.1.4", "grunt-template-jasmine-requirejs": "^0.2.3", "grunt-text-replace": "^0.4.0", "imagemin-svgo": "^4.0.1", + "jscs-jsdoc": "^1.1.0", "load-grunt-config": "^0.16.0", "morgan": "^1.5.0", "node-minify": "^1.0.1", + "path": "^0.11.14", "serve-static": "^1.7.1", "strip-json-comments": "^1.0.2", "time-grunt": "^1.0.0", diff --git a/setup/pub/magento/setup/web-configuration.js b/setup/pub/magento/setup/web-configuration.js index 79170d6cbf1f3d8adac23d12e63ded7957ccf1e7..13ff2e05fe666c6a6bd90e62eb5e632f5bf83def 100644 --- a/setup/pub/magento/setup/web-configuration.js +++ b/setup/pub/magento/setup/web-configuration.js @@ -11,7 +11,7 @@ angular.module('web-configuration', ['ngStorage']) base_url: '', auto_base_url: '', actual_base_url: '', - admin: 'admin' + admin: '' }, https: { front: false, @@ -40,13 +40,13 @@ angular.module('web-configuration', ['ngStorage']) $scope.updateOnExpand = function(obj) { obj.expanded = !obj.expanded; - } + }; $scope.fillBaseURL = function() { if (angular.equals($scope.config.address.base_url, '')) { $scope.config.address.base_url = $scope.config.address.auto_base_url; } - } + }; $scope.$watch('config.address.base_url', function() { if (angular.equals($scope.config.address.base_url, '')) { @@ -74,11 +74,11 @@ angular.module('web-configuration', ['ngStorage']) $scope.showEncryptKey = function() { return angular.equals($scope.config.encrypt.type, 'user'); - } + }; $scope.showHttpsField = function() { return ($scope.config.https.front || $scope.config.https.admin); - } + }; $scope.addSlash = function() { if (angular.isUndefined($scope.config.address.base_url)) { @@ -107,7 +107,7 @@ angular.module('web-configuration', ['ngStorage']) $scope.$emit('validation-response', false); $scope.webconfig.submitted = true; } - } + }; // Update 'submitted' flag $scope.$watch(function() { return $scope.webconfig.$valid }, function(valid) { diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php index 7606a2e17bf0b902394ea8bb3c583d8ab22136c2..707c8ee9dae3296836b2a16a000298fded1c9359 100644 --- a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php +++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php @@ -14,12 +14,15 @@ use Magento\Setup\Model\ObjectManagerProvider; use Magento\Setup\Module\Di\App\Task\Manager; use Magento\Setup\Module\Di\App\Task\OperationFactory; use Magento\Setup\Module\Di\App\Task\OperationException; +use Magento\Setup\Module\Di\App\Task\OperationInterface; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Command to run compile in single-tenant mode + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DiCompileCommand extends Command { @@ -104,39 +107,10 @@ class DiCompileCommand extends Command ]; $this->configureObjectManager($output); - $operations = [ - OperationFactory::REPOSITORY_GENERATOR => [ - 'path' => $compiledPathsList['application'], - 'filePatterns' => ['di' => '/\/etc\/([a-zA-Z_]*\/di|di)\.xml$/'] - ], - OperationFactory::DATA_ATTRIBUTES_GENERATOR => [ - 'path' => $compiledPathsList['application'], - 'filePatterns' => $dataAttributesIncludePattern - ], - OperationFactory::APPLICATION_CODE_GENERATOR => [ - $compiledPathsList['application'], - $compiledPathsList['library'], - $compiledPathsList['generated_helpers'], - ], - OperationFactory::INTERCEPTION => [ - 'intercepted_paths' => [ - $compiledPathsList['application'], - $compiledPathsList['library'], - $compiledPathsList['generated_helpers'], - ], - 'path_to_store' => $compiledPathsList['generated_helpers'], - ], - OperationFactory::AREA_CONFIG_GENERATOR => [ - $compiledPathsList['application'], - $compiledPathsList['library'], - $compiledPathsList['generated_helpers'], - ], - OperationFactory::INTERCEPTION_CACHE => [ - $compiledPathsList['application'], - $compiledPathsList['library'], - $compiledPathsList['generated_helpers'], - ] - ]; + $operations = $this->getOperationsConfiguration( + $compiledPathsList, + $dataAttributesIncludePattern + ); try { $this->cleanupFilesystem( @@ -152,7 +126,34 @@ class DiCompileCommand extends Command $arguments ); } - $this->taskManager->process(); + + /** @var ProgressBar $progressBar */ + $progressBar = $this->objectManager->create( + 'Symfony\Component\Console\Helper\ProgressBar', + [ + 'output' => $output, + 'max' => count($operations) + ] + ); + $progressBar->setFormat( + '<info>%message%</info> %current%/%max% [%bar%] %percent:3s%% %elapsed% %memory:6s%' + ); + $output->writeln('<info>Compilation was started.</info>'); + $progressBar->start(); + $progressBar->display(); + + $this->taskManager->process( + function (OperationInterface $operation) use ($progressBar) { + $progressBar->setMessage($operation->getName() . '...'); + $progressBar->display(); + }, + function (OperationInterface $operation) use ($progressBar) { + $progressBar->advance(); + } + ); + + $progressBar->finish(); + $output->writeln(''); $output->writeln('<info>Generated code and dependency injection configuration successfully.</info>'); } catch (OperationException $e) { $output->writeln('<error>' . $e->getMessage() . '</error>'); @@ -222,4 +223,52 @@ class DiCompileCommand extends Command ] ); } + + /** + * Returns operations configuration + * + * @param array $compiledPathsList + * @param array $dataAttributesIncludePattern + * @return array + */ + private function getOperationsConfiguration( + array $compiledPathsList, + array $dataAttributesIncludePattern + ) { + $operations = [ + OperationFactory::REPOSITORY_GENERATOR => [ + 'path' => $compiledPathsList['application'], + 'filePatterns' => ['di' => '/\/etc\/([a-zA-Z_]*\/di|di)\.xml$/'] + ], + OperationFactory::DATA_ATTRIBUTES_GENERATOR => [ + 'path' => $compiledPathsList['application'], + 'filePatterns' => $dataAttributesIncludePattern + ], + OperationFactory::APPLICATION_CODE_GENERATOR => [ + $compiledPathsList['application'], + $compiledPathsList['library'], + $compiledPathsList['generated_helpers'], + ], + OperationFactory::INTERCEPTION => [ + 'intercepted_paths' => [ + $compiledPathsList['application'], + $compiledPathsList['library'], + $compiledPathsList['generated_helpers'], + ], + 'path_to_store' => $compiledPathsList['generated_helpers'], + ], + OperationFactory::AREA_CONFIG_GENERATOR => [ + $compiledPathsList['application'], + $compiledPathsList['library'], + $compiledPathsList['generated_helpers'], + ], + OperationFactory::INTERCEPTION_CACHE => [ + $compiledPathsList['application'], + $compiledPathsList['library'], + $compiledPathsList['generated_helpers'], + ] + ]; + + return $operations; + } } diff --git a/setup/src/Magento/Setup/Console/Command/InfoAdminUriCommand.php b/setup/src/Magento/Setup/Console/Command/InfoAdminUriCommand.php new file mode 100644 index 0000000000000000000000000000000000000000..5bdc0333121f23cd7def4ca976792d07102e94b5 --- /dev/null +++ b/setup/src/Magento/Setup/Console/Command/InfoAdminUriCommand.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Console\Command; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Command\Command; +use \Magento\Backend\Setup\ConfigOptionsList as BackendConfigOptionsList; + +class InfoAdminUriCommand extends Command +{ + /** + * @var \Magento\Framework\App\DeploymentConfig + */ + private $deploymentConfig; + + /** + * Constructor + * + * @param \Magento\Framework\App\DeploymentConfig $deploymentConfig + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function __construct(\Magento\Framework\App\DeploymentConfig $deploymentConfig) + { + $this->deploymentConfig = $deploymentConfig; + parent::__construct(); + } + + /** + * Initialization of the command + * + * @return void + */ + protected function configure() + { + $this->setName('info:adminuri') + ->setDescription('Displays the Magento Admin URI'); + parent::configure(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $output->writeln( + "\nAdmin URI: /" + . $this->deploymentConfig->get(BackendConfigOptionsList::CONFIG_PATH_BACKEND_FRONTNAME) + . "\n" + ); + } +} diff --git a/setup/src/Magento/Setup/Console/CommandList.php b/setup/src/Magento/Setup/Console/CommandList.php index 590e2c9789a1c257a13a796fd4b34087c2b4998b..a977de25c51534108d115a3817f70eddd6255fa0 100644 --- a/setup/src/Magento/Setup/Console/CommandList.php +++ b/setup/src/Magento/Setup/Console/CommandList.php @@ -53,6 +53,7 @@ class CommandList 'Magento\Setup\Console\Command\GenerateFixturesCommand', 'Magento\Setup\Console\Command\I18nCollectPhrasesCommand', 'Magento\Setup\Console\Command\I18nPackCommand', + 'Magento\Setup\Console\Command\InfoAdminUriCommand', 'Magento\Setup\Console\Command\InfoBackupsListCommand', 'Magento\Setup\Console\Command\InfoCurrencyListCommand', 'Magento\Setup\Console\Command\InfoLanguageListCommand', diff --git a/setup/src/Magento/Setup/Controller/WebConfiguration.php b/setup/src/Magento/Setup/Controller/WebConfiguration.php index 7ffcb4e6120a2ccd7e623bebeab800c746db7e42..1197a234c0ad9858e588106ddaa541cbefab104a 100644 --- a/setup/src/Magento/Setup/Controller/WebConfiguration.php +++ b/setup/src/Magento/Setup/Controller/WebConfiguration.php @@ -19,7 +19,12 @@ class WebConfiguration extends AbstractActionController public function indexAction() { $setupInfo = new SetupInfo($_SERVER); - $view = new ViewModel(['autoBaseUrl' => $setupInfo->getProjectUrl()]); + $view = new ViewModel( + [ + 'autoBaseUrl' => $setupInfo->getProjectUrl(), + 'autoAdminPath' => $setupInfo->getProjectAdminPath() + ] + ); $view->setTerminal(true); return $view; } diff --git a/setup/src/Magento/Setup/Model/ConfigModel.php b/setup/src/Magento/Setup/Model/ConfigModel.php index f812279bd6a3cbd61c8475c2a08f8509ed8ca68b..5f481a0f5db806f44097a196028f65455ff7cf90 100644 --- a/setup/src/Magento/Setup/Model/ConfigModel.php +++ b/setup/src/Magento/Setup/Model/ConfigModel.php @@ -153,7 +153,7 @@ class ConfigModel return $errors; } - + /** * Check permissions of directories that are expected to be writable for installation * @@ -164,7 +164,7 @@ class ConfigModel { $results = $this->filePermissions->getMissingWritableDirectoriesForInstallation(); if ($results) { - $errorMsg = "Missing writing permissions to the following directories: '" . implode("', '", $results) . "'"; + $errorMsg = "Missing write permissions to the following directories: '" . implode("', '", $results) . "'"; throw new \Exception($errorMsg); } } diff --git a/setup/src/Magento/Setup/Model/Deployer.php b/setup/src/Magento/Setup/Model/Deployer.php index dfd2b05952f6ec38423e12ee8ed796cf50483ce4..8ab1b0da5742ea147a971f11d90b805cef8fa019 100644 --- a/setup/src/Magento/Setup/Model/Deployer.php +++ b/setup/src/Magento/Setup/Model/Deployer.php @@ -55,9 +55,6 @@ class Deployer /** @var \Magento\Framework\View\Template\Html\MinifierInterface */ private $htmlMinifier; - /** @var \Magento\Framework\View\Asset\MinifyService */ - protected $minifyService; - /** * @var ObjectManagerInterface */ @@ -72,7 +69,6 @@ class Deployer * @param Files $filesUtil * @param OutputInterface $output * @param Version\StorageInterface $versionStorage - * @param \Magento\Framework\View\Asset\MinifyService $minifyService * @param JsTranslationConfig $jsTranslationConfig * @param bool $isDryRun */ @@ -80,7 +76,6 @@ class Deployer Files $filesUtil, OutputInterface $output, Version\StorageInterface $versionStorage, - \Magento\Framework\View\Asset\MinifyService $minifyService, JsTranslationConfig $jsTranslationConfig, $isDryRun = false ) { @@ -88,7 +83,6 @@ class Deployer $this->output = $output; $this->versionStorage = $versionStorage; $this->isDryRun = $isDryRun; - $this->minifyService = $minifyService; $this->jsTranslationConfig = $jsTranslationConfig; $this->parentTheme = []; } @@ -275,7 +269,6 @@ class Deployer $requestedPath, ['area' => $area, 'theme' => $themePath, 'locale' => $locale, 'module' => $module] ); - $asset = $this->minifyService->getAssets([$asset], true)[0]; if ($this->output->isVeryVerbose()) { $this->output->writeln("\tDeploying the file to '{$asset->getPath()}'"); } else { diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php index b3cdd3ee191891466f70e8f8df4376b768c5825e..0e822e56f2dd5c84e307a63ff9baf474b65b6780 100644 --- a/setup/src/Magento/Setup/Model/Installer.php +++ b/setup/src/Magento/Setup/Model/Installer.php @@ -33,6 +33,7 @@ use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\App\State\CleanupFiles; use Magento\Setup\Console\Command\InstallCommand; use Magento\Setup\Validator\DbValidator; +use \Magento\Backend\Setup\ConfigOptionsList as BackendConfigOptionsList; /** * Class Installer contains the logic to install Magento application. @@ -300,6 +301,10 @@ class Installer } $this->log->logSuccess('Magento installation complete.'); + $this->log->logSuccess( + 'Magento Admin URI: /' + . $this->deploymentConfig->get(BackendConfigOptionsList::CONFIG_PATH_BACKEND_FRONTNAME) + ); if ($this->progress->getCurrent() != $this->progress->getTotal()) { throw new \LogicException('Installation progress did not finish properly.'); @@ -394,7 +399,7 @@ class Installer { $results = $this->filePermissions->getMissingWritableDirectoriesForInstallation(); if ($results) { - $errorMsg = "Missing writing permissions to the following directories: '" . implode("' '", $results) . "'"; + $errorMsg = "Missing write permissions to the following directories: '" . implode("' '", $results) . "'"; throw new \Exception($errorMsg); } } diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/Manager.php b/setup/src/Magento/Setup/Module/Di/App/Task/Manager.php index 7e4171c0873d2bef4bbd23ad558980c051e55622..e981497eb73bee1fae0182c2b990000023694ec4 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/Manager.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/Manager.php @@ -20,8 +20,9 @@ class Manager /** * @param OperationFactory $operationFactory */ - public function __construct(OperationFactory $operationFactory) - { + public function __construct( + OperationFactory $operationFactory + ) { $this->operationFactory = $operationFactory; } @@ -40,13 +41,23 @@ class Manager /** * Processes list of operations * + * @param callable $beforeCallback + * @param callable $afterCallback * @return void */ - public function process() + public function process(\Closure $beforeCallback = null, \Closure $afterCallback = null) { /** @var OperationInterface $operation */ foreach ($this->operationsList as $operation) { + if (is_callable($beforeCallback)) { + $beforeCallback($operation); + } + $operation->doOperation(); + + if (is_callable($afterCallback)) { + $afterCallback($operation); + } } $this->operationsList = []; } diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ApplicationCodeGenerator.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ApplicationCodeGenerator.php index 1228703ab08fd6e99af5e1c5e18715a4d3783e91..82c13934833e18508cc61e4e20704d8d51703f97 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ApplicationCodeGenerator.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ApplicationCodeGenerator.php @@ -45,4 +45,14 @@ class ApplicationCodeGenerator implements OperationInterface $this->classesScanner->getList($path); } } + + /** + * Returns operation name + * + * @return string + */ + public function getName() + { + return 'Application code generator'; + } } diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php index f129e56dc8d8c67afa7d971393fb60d987585df5..79c985af01d71c24b94c065115ff068122b80a54 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php @@ -106,4 +106,14 @@ class Area implements OperationInterface } return $definitions; } + + /** + * Returns operation name + * + * @return string + */ + public function getName() + { + return 'Area configuration aggregation'; + } } diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Interception.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Interception.php index 6d5d9ae3502a806f22bb4c58e04ed2105b2755aa..bfd3cfcf5e09d8abede8986852b85cbb24d3571f 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Interception.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Interception.php @@ -94,4 +94,14 @@ class Interception implements OperationInterface $configuration = $this->interceptionConfigurationBuilder->getInterceptionConfiguration($classesList); $generator->generateList($configuration); } + + /** + * Returns operation name + * + * @return string + */ + public function getName() + { + return 'Interceptors generation'; + } } diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/InterceptionCache.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/InterceptionCache.php index b37f329ebfc78a57a6ce41b0e63358a7b04c411d..e99a15a9130620ec4d45e5f00e4ea83d515d30ae 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/InterceptionCache.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/InterceptionCache.php @@ -57,4 +57,14 @@ class InterceptionCache implements OperationInterface $this->configInterface->initialize($definitions); } + + /** + * Returns operation name + * + * @return string + */ + public function getName() + { + return 'Interception cache generation'; + } } diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/RepositoryGenerator.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/RepositoryGenerator.php index 41e9e80e5fe4e04628af960d4bf2b25f1eb89936..22c57aea87fedd77b04b9fee03b2df78c18aa45e 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/RepositoryGenerator.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/RepositoryGenerator.php @@ -70,4 +70,14 @@ class RepositoryGenerator implements OperationInterface class_exists($entityName); } } + + /** + * Returns operation name + * + * @return string + */ + public function getName() + { + return 'Repositories code generation'; + } } diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ServiceDataAttributesGenerator.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ServiceDataAttributesGenerator.php index 3e8ee94b8bd28a6dffd8cd363fe4a22fd494ef28..46b75bf10efeffef190264e3ff7fdfa37fe3492e 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ServiceDataAttributesGenerator.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ServiceDataAttributesGenerator.php @@ -64,4 +64,14 @@ class ServiceDataAttributesGenerator implements OperationInterface class_exists($entityName); } } + + /** + * Returns operation name + * + * @return string + */ + public function getName() + { + return 'Service data attributes generation'; + } } diff --git a/setup/src/Magento/Setup/Module/Di/App/Task/OperationInterface.php b/setup/src/Magento/Setup/Module/Di/App/Task/OperationInterface.php index 0ce7cd3344c4684d5455a0c2044c8f254468862e..46bbce3d7ec591737d3e3c60ee1cf35a2b757f7b 100644 --- a/setup/src/Magento/Setup/Module/Di/App/Task/OperationInterface.php +++ b/setup/src/Magento/Setup/Module/Di/App/Task/OperationInterface.php @@ -13,4 +13,11 @@ interface OperationInterface * @return void */ public function doOperation(); + + /** + * Returns operation name + * + * @return string + */ + public function getName(); } diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/PreferencesResolving.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/PreferencesResolving.php index 9d58a69cd6ebf5fea3a41f70bf0f1f9ffa1cb0f4..6c7dc8b6d47195e807ac875b4bc1ba3cdb28db9c 100644 --- a/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/PreferencesResolving.php +++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/PreferencesResolving.php @@ -18,7 +18,7 @@ class PreferencesResolving implements ModificationInterface */ public function modify(array $config) { - if (!isset($config['arguments']) || !isset($config['preferences'])) { + if (!isset($config['arguments'], $config['preferences'])) { return $config; } @@ -42,7 +42,7 @@ class PreferencesResolving implements ModificationInterface foreach ($argument as $key => &$value) { if (in_array($key, ['_i_', '_ins_'])) { - $value = isset($preferences[$value]) ? $preferences[$value] : $value; + $value = $this->resolvePreferenceRecursive($value, $preferences); continue; } @@ -50,6 +50,20 @@ class PreferencesResolving implements ModificationInterface $this->resolvePreferences($value, $preferences); } } - return; + } + + /** + * Resolves preference recursively + * + * @param string $value + * @param array $preferences + * + * @return string + */ + private function resolvePreferenceRecursive(&$value, &$preferences) + { + return isset($preferences[$value]) + ? $this->resolvePreferenceRecursive($preferences[$value], $preferences) + : $value; } } diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationChain.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationChain.php index 666ee682c05cd71232cb68432d4584eac26a02b4..e8b316562485239ea54b71f70abfc0e28aac42ed 100644 --- a/setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationChain.php +++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationChain.php @@ -29,7 +29,6 @@ class ModificationChain implements ModificationInterface $this->modificationsList = $modificationsList; } - /** * Modifies input config * 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 450c74b14fb9bf372b4eb35131ca06d8e67b806c..2b9381b4783a495e0a179e6221734c0ac34e5895 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php @@ -90,14 +90,25 @@ class DiCompileCommandTest extends \PHPUnit_Framework_TestCase $this->filesystem->expects($this->atLeastOnce())->method('getDirectoryWrite')->willReturn($writeDirectory); $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(true); + $progressBar = $this->getMockBuilder( + 'Symfony\Component\Console\Helper\ProgressBar' + ) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManager->expects($this->once())->method('configure'); + $this->objectManager + ->expects($this->once()) + ->method('create') + ->with('Symfony\Component\Console\Helper\ProgressBar') + ->willReturn($progressBar); $this->manager->expects($this->exactly(6))->method('addOperation'); $this->manager->expects($this->once())->method('process'); $tester = new CommandTester($this->command); $tester->execute([]); - $this->assertEquals( - 'Generated code and dependency injection configuration successfully.' . PHP_EOL, - $tester->getDisplay() + $this->assertContains( + 'Generated code and dependency injection configuration successfully.', + explode(PHP_EOL, $tester->getDisplay()) ); } } diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoAdminUriCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoAdminUriCommandTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3c38aae8a914388c93542466ee740966a57c8c82 --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoAdminUriCommandTest.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Setup\Test\Unit\Console\Command; + +use Magento\Setup\Console\Command\InfoAdminUriCommand; +use Symfony\Component\Console\Tester\CommandTester; +use Magento\Framework\Setup\BackendFrontnameGenerator; + +class InfoAdminUriCommandTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Framework\App\DeploymentConfig|\PHPUnit_Framework_MockObject_MockObject + */ + protected $deploymentConfig; + + protected function setup() + { + $this->deploymentConfig = $this->getMock('Magento\Framework\App\DeploymentConfig', [], [], '', false); + } + + public function testExecute() + { + $this->deploymentConfig->expects($this->once())->method('get')->willReturn('admin_qw12er'); + + $commandTester = new CommandTester(new InfoAdminUriCommand($this->deploymentConfig)); + $commandTester->execute([]); + + $regexp = '/' . BackendFrontnameGenerator::ADMIN_AREA_PATH_PREFIX + . '[a-z0-9]{1,' . BackendFrontnameGenerator::ADMIN_AREA_PATH_RANDOM_PART_LENGTH .'}/'; + + $this->assertRegExp($regexp, $commandTester->getDisplay(), 'Unexpected Backend Frontname pattern.'); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigModelTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigModelTest.php index 00a756da206f57a32f4315f799f214129bd1b941..66c1c46c8ed6220f2a6605a14a421f2c3a737d1c 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigModelTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigModelTest.php @@ -166,7 +166,7 @@ class ConfigModelTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Exception - * @expectedExceptionMessage Missing writing permissions to the following directories: '/a/ro/dir', '/media' + * @expectedExceptionMessage Missing write permissions to the following directories: '/a/ro/dir', '/media' */ public function testWritePermissionErrors() { diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php index 1028606309a13b89848b4f42d4a6560774278493..295c572b9b55021b4b138333916afce2049abbcf 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php @@ -272,7 +272,7 @@ class InstallerTest extends \PHPUnit_Framework_TestCase $this->logger->expects($this->at(31))->method('log')->with('Current status:'); $this->logger->expects($this->at(34))->method('log')->with('Disabling Maintenance Mode:'); $this->logger->expects($this->at(36))->method('log')->with('Post installation file permissions check...'); - $this->logger->expects($this->once())->method('logSuccess')->with('Magento installation complete.'); + $this->logger->expects($this->at(38))->method('logSuccess')->with('Magento installation complete.'); $this->object->install($request); } @@ -287,7 +287,7 @@ class InstallerTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Exception - * @expectedExceptionMessage Missing writing permissions to the following directories: 'foo' 'bar' + * @expectedExceptionMessage Missing write permissions to the following directories: 'foo' 'bar' */ public function testCheckInstallationFilePermissionsError() { diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/PreferencesResolvingTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/PreferencesResolvingTest.php index c73ff5109d07ad3047aa7c01cd2cd3dc225a1504..b2e02078082a0865a7a7acfee7fd89e180f667e9 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/PreferencesResolvingTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/PreferencesResolvingTest.php @@ -57,6 +57,9 @@ class PreferencesResolvingTest extends \PHPUnit_Framework_TestCase 'value_null' => [ '_vn_' => true, ], + 'virtual_preferece' => [ + '_i_' => 'Type\DependencyInterface2' + ] ], 'ComplexClass' => [ 'type_dependency_configured' => [ @@ -123,6 +126,9 @@ class PreferencesResolvingTest extends \PHPUnit_Framework_TestCase 'value_null' => [ '_vn_' => true, ], + 'virtual_preferece' => [ + '_i_' => 'Type\DependencyVirtual3' + ] ], 'ComplexClass' => [ 'type_dependency_configured' => [ @@ -178,6 +184,9 @@ class PreferencesResolvingTest extends \PHPUnit_Framework_TestCase 'Type\Dependency\ConfiguredInterface' => 'Type\Dependency\Configured', 'Type\Dependency\Shared\ConfiguredInterface' => 'Type\Dependency\Shared\ConfiguredPreference', 'Type\Dependency\Shared\Configured' => 'Type\Dependency\Shared\ConfiguredPreference', + 'Type\DependencyInterface2' => 'Type\DependencyVirtual', + 'Type\DependencyVirtual' => 'Type\DependencyVirtual2', + 'Type\DependencyVirtual2' => 'Type\DependencyVirtual3' ]; } } diff --git a/setup/view/magento/setup/success.phtml b/setup/view/magento/setup/success.phtml index c75cacc1a28516be1606d480a1938a0483f4be91..d24a2492f23956840b0d72389cf9f3d737235684 100644 --- a/setup/view/magento/setup/success.phtml +++ b/setup/view/magento/setup/success.phtml @@ -38,6 +38,12 @@ <a href="{{url.admin}}" target="_blank">{{url.admin}}</a> </dd> + <div class="message message-notice"> + <span class="message-text"> + Be sure to bookmark your unique URL and record it offline. + </span> + </div> + <dt>Encryption Key:</dt> <dd>{{config.encrypt.key}}</dd> </dl> diff --git a/setup/view/magento/setup/web-configuration.phtml b/setup/view/magento/setup/web-configuration.phtml index 282c1068bc34f863eb7d9d5b959c977b92658d9c..d2c15d9426cc08d5a7f7fc64102969467611e63e 100644 --- a/setup/view/magento/setup/web-configuration.phtml +++ b/setup/view/magento/setup/web-configuration.phtml @@ -18,6 +18,10 @@ $hints = [ '<p>%s</p>', 'Key to encrypt sensitive data such as passwords and personally identifiable customer information in the Magento database. The encryption key is stored in [your Magento install dir]/app/etc/env.php' ), + 'admin' => sprintf( + '<p>%s</p>', + 'A unique URL helps keep store and customer info safer.' + ) ]; ?> @@ -99,7 +103,12 @@ $hints = [ name="admin" ng-model="config.address.admin" ng-class="{'invalid' : webconfig.admin.$invalid && webconfig.submitted }" + ng-init="config.address.admin = '<?php echo $this->autoAdminPath ?>';" required + tooltip-placement="right" + tooltip-html-unsafe="<?php echo $hints['admin']; ?>" + tooltip-trigger="focus" + tooltip-append-to-body="true" > <div class="error-container"> <span ng-show="webconfig.admin.$error.required">