diff --git a/.htaccess.sample b/.htaccess.sample index 8e6e702ced716..3c412725f2134 100644 --- a/.htaccess.sample +++ b/.htaccess.sample @@ -111,7 +111,8 @@ ############################################ ## enable rewrites - Options +FollowSymLinks + # The following line has better security but add some performance overhead - see https://httpd.apache.org/docs/2.4/en/misc/perf-tuning.html + Options -FollowSymLinks +SymLinksIfOwnerMatch RewriteEngine on ############################################ diff --git a/README.md b/README.md index 9b1aa1b7b3e28..eca00d852940a 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ Welcome to Magento 2 installation! We're glad you chose to install Magento 2, a cutting edge, feature-rich eCommerce solution that gets results. ## Magento system requirements -[Magento system requirements](http://devdocs.magento.com/magento-system-requirements.html) +[Magento system requirements](http://devdocs.magento.com/guides/v2.2/install-gde/system-requirements2.html) ## Install Magento To install Magento, see either: * [Magento DevBox](https://magento.com/tech-resources/download), the easiest way to get started with Magento. -* [Installation guide](http://devdocs.magento.com/guides/v2.0/install-gde/bk-install-guide.html) +* [Installation guide](http://devdocs.magento.com/guides/v2.2/install-gde/bk-install-guide.html)
Magento supports PHP 7.0.2, 7.0.4, and 7.0.6 or later. Please read
-
+
Magento System Requirements.
HTML;
diff --git a/app/code/Magento/AdminNotification/Model/Feed.php b/app/code/Magento/AdminNotification/Model/Feed.php
index 1766425fb19b1..d3b0b8501c864 100644
--- a/app/code/Magento/AdminNotification/Model/Feed.php
+++ b/app/code/Magento/AdminNotification/Model/Feed.php
@@ -214,9 +214,6 @@ public function getFeedData()
);
$curl->write(\Zend_Http_Client::GET, $this->getFeedUrl(), '1.0');
$data = $curl->read();
- if ($data === false) {
- return false;
- }
$data = preg_split('/^\r?$/m', $data, 2);
$data = trim($data[1]);
$curl->close();
diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php
index 23829d3725119..0e8acb37104e6 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php
@@ -394,7 +394,7 @@ protected function saveAndReplaceAdvancedPrices()
? $rowData[self::COL_TIER_PRICE] : 0,
'percentage_value' => $rowData[self::COL_TIER_PRICE_TYPE] === self::TIER_PRICE_TYPE_PERCENT
? $rowData[self::COL_TIER_PRICE] : null,
- 'website_id' => $this->getWebsiteId($rowData[self::COL_TIER_PRICE_WEBSITE])
+ 'website_id' => $this->getWebSiteId($rowData[self::COL_TIER_PRICE_WEBSITE])
];
}
}
diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/WebsiteTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/WebsiteTest.php
index 5111b4932d7a8..9a380ff75da24 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/WebsiteTest.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/WebsiteTest.php
@@ -27,7 +27,7 @@ class WebsiteTest extends \PHPUnit\Framework\TestCase
protected function setUp()
{
- $this->webSiteModel = $this->getMockBuilder(\Magento\Store\Model\WebSite::class)
+ $this->webSiteModel = $this->getMockBuilder(\Magento\Store\Model\Website::class)
->setMethods(['getBaseCurrency'])
->disableOriginalConstructor()
->getMock();
diff --git a/app/code/Magento/Backend/Block/System/Store/Edit/AbstractForm.php b/app/code/Magento/Backend/Block/System/Store/Edit/AbstractForm.php
index f19799d2e4939..034887c67d1ee 100644
--- a/app/code/Magento/Backend/Block/System/Store/Edit/AbstractForm.php
+++ b/app/code/Magento/Backend/Block/System/Store/Edit/AbstractForm.php
@@ -37,7 +37,7 @@ protected function _prepareForm()
['data' => ['id' => 'edit_form', 'action' => $this->getData('action'), 'method' => 'post']]
);
- $this->_prepareStoreFieldSet($form);
+ $this->_prepareStoreFieldset($form);
$form->addField(
'store_type',
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Noroute/Index.php b/app/code/Magento/Backend/Controller/Adminhtml/Noroute/Index.php
index e8251b5be6030..ce59d2fd48e5a 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Noroute/Index.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Noroute/Index.php
@@ -34,7 +34,7 @@ public function execute()
{
/** @var \Magento\Backend\Model\View\Result\Page $resultPage */
$resultPage = $this->resultPageFactory->create();
- $resultPage->setStatusHeader(404, '1.1', 'Forbidden');
+ $resultPage->setStatusHeader(404, '1.1', 'Not Found');
$resultPage->setHeader('Status', '404 File not found');
$resultPage->addHandle('adminhtml_noroute');
return $resultPage;
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php
index c9bce1cbf3888..421885a0c32a3 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php
@@ -54,9 +54,9 @@ public function execute()
$user = $this->_objectManager->create(\Magento\User\Model\User::class)->load($userId);
$user->setId($userId)
- ->setUsername($this->getRequest()->getParam('username', false))
- ->setFirstname($this->getRequest()->getParam('firstname', false))
- ->setLastname($this->getRequest()->getParam('lastname', false))
+ ->setUserName($this->getRequest()->getParam('username', false))
+ ->setFirstName($this->getRequest()->getParam('firstname', false))
+ ->setLastName($this->getRequest()->getParam('lastname', false))
->setEmail(strtolower($this->getRequest()->getParam('email', false)));
if ($this->_objectManager->get(\Magento\Framework\Validator\Locale::class)->isValid($interfaceLocale)) {
diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/ColumnSetTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/ColumnSetTest.php
index be171a8ed40bf..df242a4cf6129 100644
--- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/ColumnSetTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/ColumnSetTest.php
@@ -117,7 +117,7 @@ public function testSetFilterTypePropagatesFilterTypeToColumns()
public function testGetRowUrlIfUrlPathNotSet()
{
- $this->assertEquals('#', $this->_block->getRowUrl(new \StdClass()));
+ $this->assertEquals('#', $this->_block->getRowUrl(new \stdClass()));
}
public function testGetRowUrl()
diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/ColumnTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/ColumnTest.php
index da13af87b71ea..c5c56fd75fbe7 100644
--- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/ColumnTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/ColumnTest.php
@@ -351,7 +351,7 @@ public function testSetGetGrid()
$this->_block->setFilter('StdClass');
- $grid = new \StdClass();
+ $grid = new \stdClass();
$this->_block->setGrid($grid);
$this->assertEquals($grid, $this->_block->getGrid());
}
diff --git a/app/code/Magento/Backend/etc/adminhtml/system.xml b/app/code/Magento/Backend/etc/adminhtml/system.xml
index 92df39bd65ee4..04bfe76bce9e7 100644
--- a/app/code/Magento/Backend/etc/adminhtml/system.xml
+++ b/app/code/Magento/Backend/etc/adminhtml/system.xml
@@ -231,7 +231,7 @@
Test text For additional assistance, see
- PHP settings check help
.
The best way to resolve this is to install the correct missing extensions. The exact fix depends on our server, your host, and other system variables.
For additional assistance, contact your hosting provider.
@@ -477,7 +477,7 @@
@@ -39,7 +39,7 @@
href="= /* @escapeNotVerified */ $block->getUrl('adminhtml/system_account/index') ?>"
= /* @escapeNotVerified */ $block->getUiId('user', 'account', 'settings') ?>
title="= $block->escapeHtml(__('Account Setting')) ?>">
- = /* @escapeNotVerified */ __('Account Setting') ?> (= $block->escapeHtml($block->getUser()->getUsername()) ?>)
+ = /* @escapeNotVerified */ __('Account Setting') ?> (= $block->escapeHtml($block->getUser()->getUserName()) ?>)
diff --git a/app/code/Magento/Backend/view/adminhtml/templates/system/search.phtml b/app/code/Magento/Backend/view/adminhtml/templates/system/search.phtml
index a528133b2bc3a..b50183ced29b4 100644
--- a/app/code/Magento/Backend/view/adminhtml/templates/system/search.phtml
+++ b/app/code/Magento/Backend/view/adminhtml/templates/system/search.phtml
@@ -28,16 +28,16 @@
diff --git a/app/code/Magento/Tinymce3/view/base/web/tinymce3Adapter.js b/app/code/Magento/Tinymce3/view/base/web/tinymce3Adapter.js
index 08bbb95888d8d..fd5e9628fecdb 100644
--- a/app/code/Magento/Tinymce3/view/base/web/tinymce3Adapter.js
+++ b/app/code/Magento/Tinymce3/view/base/web/tinymce3Adapter.js
@@ -132,6 +132,10 @@ define([
ed.onInit.add(self.onEditorInit.bind(self));
+ ed.onInit.add(function (editor) {
+ varienGlobalEvents.fireEvent('wysiwygEditorInitialized', editor);
+ });
+
ed.onSubmit.add(function (edi, e) {
varienGlobalEvents.fireEvent('tinymceSubmit', e);
});
@@ -244,6 +248,13 @@ define([
return tinyMCE3.get(id);
},
+ /**
+ * @return {String|null}
+ */
+ getId: function () {
+ return this.id || (this.activeEditor() ? this.activeEditor().id : null) || tinyMceEditors.values()[0].id;
+ },
+
/**
* @return {Object}
*/
@@ -261,6 +272,35 @@ define([
this.activeEditor().execCommand('mceInsertContent', typeof ui !== 'undefined' ? ui : false, content);
},
+ /**
+ * Set the status of the toolbar to disabled or enabled (true for enabled, false for disabled)
+ * @param {Boolean} enabled
+ */
+ setToolbarStatus: function (enabled) {
+ _.each(this.activeEditor().controlManager.controls, function (property, index, controls) {
+ controls[property.id].setDisabled(!enabled);
+ });
+ },
+
+ /**
+ * Set the status of the editor and toolbar
+ *
+ * @param {Boolean} enabled
+ */
+ setEnabledStatus: function (enabled) {
+ if (this.activeEditor()) {
+ this.activeEditor().getBody().setAttribute('contenteditable', enabled);
+ this.activeEditor().readonly = !enabled;
+ this.setToolbarStatus(enabled);
+ }
+
+ if (enabled) {
+ this.getTextArea().removeProp('disabled');
+ } else {
+ this.getTextArea().prop('disabled', 'disabled');
+ }
+ },
+
/**
* Set caret location in WYSIWYG editor.
*
@@ -279,7 +319,7 @@ define([
storeId = this.config['store_id'] !== null ? this.config['store_id'] : 0,
frameDialog = jQuery(o.win.frameElement).parents('[role="dialog"]'),
wUrl = this.config['files_browser_window_url'] +
- 'target_element_id/' + this.id + '/' +
+ 'target_element_id/' + this.getId() + '/' +
'store/' + storeId + '/';
this.mediaBrowserOpener = o.win;
@@ -331,14 +371,14 @@ define([
* @return {jQuery|*|HTMLElement}
*/
getToggleButton: function () {
- return $('toggle' + this.id);
+ return $('toggle' + this.getId());
},
/**
* Get plugins button.
*/
getPluginButtons: function () {
- return $$('#buttons' + this.id + ' > button.plugin');
+ return jQuery('#buttons' + this.getId() + ' > button.plugin');
},
/**
@@ -350,11 +390,9 @@ define([
this.setup(mode);
- tinyMCE3.execCommand('mceAddControl', false, this.id);
+ tinyMCE3.execCommand('mceAddControl', false, this.getId());
- this.getPluginButtons().each(function (e) {
- e.hide();
- });
+ this.getPluginButtons().hide();
return this;
},
@@ -365,11 +403,9 @@ define([
turnOff: function () {
this.closePopups();
- tinyMCE3.execCommand('mceRemoveControl', false, this.id);
+ tinyMCE3.execCommand('mceRemoveControl', false, this.getId());
- this.getPluginButtons().each(function (e) {
- e.show();
- });
+ this.getPluginButtons().show();
return this;
},
@@ -380,8 +416,8 @@ define([
closePopups: function () {
if (typeof closeEditorPopup == 'function') {
// close all popups to avoid problems with updating parent content area
- closeEditorPopup('widget_window' + this.id);
- closeEditorPopup('browser_window' + this.id);
+ closeEditorPopup('widget_window' + this.getId());
+ closeEditorPopup('browser_window' + this.getId());
}
},
@@ -389,7 +425,7 @@ define([
* @return {Boolean}
*/
toggle: function () {
- if (!tinyMCE3.get(this.id)) {
+ if (!tinyMCE3.get(this.getId())) {
this.turnOn();
return true;
@@ -415,8 +451,8 @@ define([
* On form validation.
*/
onFormValidation: function () {
- if (tinyMCE3.get(this.id)) {
- $(this.id).value = tinyMCE3.get(this.id).getContent();
+ if (tinyMCE3.get(this.getId())) {
+ $(this.getId()).value = tinyMCE3.get(this.getId()).getContent();
}
},
@@ -444,25 +480,28 @@ define([
* @param {String} directive
*/
makeDirectiveUrl: function (directive) {
- return this.config['directives_url'].replace('directive', 'directive/___directive/' + directive);
+ return this.config['directives_url'].replace(/directive.*/, 'directive/___directive/' + directive);
},
/**
+ * Convert {{directive}} style attributes syntax to absolute URLs
* @param {Object} content
* @return {*}
*/
encodeDirectives: function (content) {
// collect all HTML tags with attributes that contain directives
- return content.gsub(/<([a-z0-9\-\_]+.+?)([a-z0-9\-\_]+=".*?\{\{.+?\}\}.*?".*?)>/i, function (match) {
- var attributesString = match[2];
+ return content.gsub(/<([a-z0-9\-\_]+[^>]+?)([a-z0-9\-\_]+=".*?\{\{.+?\}\}.*?".*?)>/i, function (match) {
+ var attributesString = match[2],
+ decodedDirectiveString;
// process tag attributes string
attributesString = attributesString.gsub(/([a-z0-9\-\_]+)="(.*?)(\{\{.+?\}\})(.*?)"/i, function (m) {
- return m[1] + '="' + m[2] + this.makeDirectiveUrl(Base64.mageEncode(m[3])) + m[4] + '"';
+ decodedDirectiveString = encodeURIComponent(Base64.mageEncode(m[3].replace(/"/g, '"')));
+
+ return m[1] + '="' + m[2] + this.makeDirectiveUrl(decodedDirectiveString) + m[4] + '"';
}.bind(this));
return '<' + match[1] + attributesString + '>';
-
}.bind(this));
},
@@ -493,16 +532,17 @@ define([
},
/**
+ * Convert absolute URLs to {{directive}} style attributes syntax
* @param {Object} content
* @return {*}
*/
decodeDirectives: function (content) {
// escape special chars in directives url to use it in regular expression
var url = this.makeDirectiveUrl('%directive%').replace(/([$^.?*!+:=()\[\]{}|\\])/g, '\\$1'),
- reg = new RegExp(url.replace('%directive%', '([a-zA-Z0-9,_-]+)'));
+ reg = new RegExp(url.replace('%directive%', '([a-zA-Z0-9%,_-]+)\/?'));
return content.gsub(reg, function (match) { //eslint-disable-line no-extra-bind
- return Base64.mageDecode(match[1]);
+ return Base64.mageDecode(decodeURIComponent(match[1])).replace(/"/g, '"');
});
},
@@ -548,7 +588,7 @@ define([
* Update text area.
*/
updateTextArea: function () {
- var editor = tinyMCE3.get(this.id),
+ var editor = tinyMCE3.get(this.getId()),
content;
if (!editor) {
@@ -558,7 +598,14 @@ define([
content = editor.getContent();
content = this.decodeContent(content);
- jQuery('#' + this.id).val(content).trigger('change');
+ this.getTextArea().val(content).trigger('change');
+ },
+
+ /**
+ * @return {Object} jQuery textarea element
+ */
+ getTextArea: function () {
+ return jQuery('#' + this.getId());
},
/**
diff --git a/app/code/Magento/Ui/Config/Converter/HtmlContent.php b/app/code/Magento/Ui/Config/Converter/HtmlContent.php
index f77b4a5285d5a..db874a302bd50 100644
--- a/app/code/Magento/Ui/Config/Converter/HtmlContent.php
+++ b/app/code/Magento/Ui/Config/Converter/HtmlContent.php
@@ -23,7 +23,7 @@ public function convert(\DOMNode $node, array $data)
if ($node->nodeType == XML_ELEMENT_NODE) {
$xml = '' . "\n"
. '
" + escapeText( document.title ) + "
" +
- "" +
- "" +
- "" +
- "";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- /*
- DEPRECATED: Use multiple tests instead of resetting inside a test.
- Use testStart or testDone for custom cleanup.
- This method will throw an error in 2.0, and will be removed in 2.1
- */
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- }
-
- // Consider: typeof null === object
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "" + message + "";
- output = message;
-
- output += " ";
-
- if ( actual !== expected ) {
- output += "Expected: " + expected + "
";
- output += "Result: " + actual + "
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Diff: " + QUnit.diff( expected, actual ) + "
";
- }
-
- output += "Source: " + escapeText( source ) + "
";
-
- if ( actual ) {
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( hasOwn.call( params, key ) ) {
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent,
- addClass: addClass,
- hasClass: hasClass,
- removeClass: removeClass
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, runtime }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( !defined.document || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, j, label, len, main, ol, toolbar, val, selection,
- urlConfigContainer, moduleFilter, userAgent,
- numModules = 0,
- moduleNames = [],
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- if ( !val.value || typeof val.value === "string" ) {
- urlConfigHtml += "";
- } else {
- urlConfigHtml += "";
- }
- }
- for ( i in config.modules ) {
- if ( config.modules.hasOwnProperty( i ) ) {
- moduleNames.push(i);
- }
- }
- numModules = moduleNames.length;
- moduleNames.sort( function( a, b ) {
- return a.localeCompare( b );
- });
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = id( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = id( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigContainer = document.createElement("span");
- urlConfigContainer.innerHTML = urlConfigHtml;
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change" for checkboxes
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigContainer.getElementsByTagName("input"), "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ?
- target.defaultValue || true :
- undefined;
- window.location = QUnit.url( params );
- });
- addEvents( urlConfigContainer.getElementsByTagName("select"), "change", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.options[ target.selectedIndex ].value || undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( "span" );
- moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url({
- module: ( selectedModule === "" ) ? undefined : selectedModule,
- // Remove any existing filters
- filter: undefined,
- testNumber: undefined
- });
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-if ( defined.document ) {
- addEvent( window, "load", QUnit.load );
-}
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will suppress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not suppressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- delete config.previousModule;
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds. ";
- }
-
- if ( source ) {
- details.source = source;
- output += "Result: " + escapeText( actual ) + "
";
- }
-
- output += "Source: " + escapeText( source ) + "
",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && defined.document && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( config.scrolltop && window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = ( test.module + ": " + test.testName ).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber.length > 0 ) {
- if ( inArray( test.testNumber, config.testNumber ) < 0 ) {
- return false;
- }
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case "'":
- return "'";
- case "\"":
- return """;
- case "<":
- return "<";
- case ">":
- return ">";
- case "&":
- return "&";
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- if ( hasOwn.call( window, key ) ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( hasOwn.call( b, prop ) ) {
- // Avoid "Member not found" error in IE8 caused by messing with window.constructor
- if ( !( prop === "constructor" && a === window ) ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
- } else {
- a[ prop ] = b[ prop ];
- }
- }
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- if ( elem.addEventListener ) {
-
- // Standards-based browsers
- elem.addEventListener( type, fn, false );
- } else if ( elem.attachEvent ) {
-
- // support: IE <9
- elem.attachEvent( "on" + type, fn );
- } else {
-
- // Caller must ensure support for event listeners is present
- throw new Error( "addEvent() was called in a context without event listener support" );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not necessarily
- elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
-}
-
-function id( name ) {
- return defined.document && document.getElementById && document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if (
- // Emit moduleStart when we're switching from one module to another
- this.module !== config.previousModule ||
- // They could be equal (both undefined) but if the previousModule property doesn't
- // yet exist it means this is the first test in a suite that isn't wrapped in a
- // module, in which case we'll just emit a moduleStart event for 'undefined'.
- // Without this, reporters can get testStart before moduleStart which is a problem.
- !hasOwn.call( config, "previousModule" )
- ) {
- if ( hasOwn.call( config, "previousModule" ) ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- /*jshint camelcase:false */
-
-
- /**
- * Expose the current test environment.
- *
- * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead.
- */
- QUnit.current_testEnvironment = this.testEnvironment;
-
- /*jshint camelcase:true */
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- runtime: this.runtime,
- // DEPRECATED: this property will be removed in 2.0.0, use runtime instead
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Assert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-assert = QUnit.assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
- msg = msg || ( result ? "okay" : "failed" );
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = "" + escapeText( msg ) + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( !message && typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
-
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
-
- // expected is an Error object
- } else if ( expected instanceof Error ) {
- ok = actual instanceof Error &&
- actual.name === expected.name &&
- actual.message === expected.message;
-
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
-
- // expected is a string
- } else if ( QUnit.objectType( expected ) === "string" ) {
- ok = expected === errorString( actual );
-
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
-
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, "No exception was thrown." );
- }
- }
-};
-
-/**
- * @deprecated since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit.constructor.prototype, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.constructor.prototype.raises = function() {
- QUnit.push( false, false, false, "QUnit.raises has been deprecated since 2012 (fad3c1ea), use QUnit.throws instead" );
-};
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.constructor.prototype.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.constructor.prototype.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé Source: " +
- escapeText( source ) +
- "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this.depth + ( extra || 0 ) ).join(chr);
- },
- up: function( a ) {
- this.depth += a || 1;
- },
- down: function( a ) {
- this.depth -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- depth: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- /*jshint forin:false */
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( hasOwn.call( ns, i ) ) {
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// For browser, export only select globals
-if ( typeof window !== "undefined" ) {
- extend( window, QUnit.constructor.prototype );
- window.QUnit = QUnit;
-}
-
-// For CommonJS environments, export everything
-if ( typeof module !== "undefined" && module.exports ) {
- module.exports = QUnit;
-}
-
-
-// Get a reference to the global object, like window in browsers
-}( (function() {
- return this;
-})() ));
diff --git a/dev/tests/js/JsTestDriver/framework/requirejs-util.js b/dev/tests/js/JsTestDriver/framework/requirejs-util.js
deleted file mode 100644
index b9d6b833d36af..0000000000000
--- a/dev/tests/js/JsTestDriver/framework/requirejs-util.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-(function ($, window) {
- "use strict";
-
- // List of define() calls with arguments and call stack
- var defineCalls = [];
-
- // Get current call stack, including script path information
- var getFileStack = function() {
- try {
- throw new Error();
- } catch (e) {
- if (!e.stack) {
- throw new Error('The browser needs to support Error.stack property');
- }
- return e.stack;
- }
- };
-
- // Intercept RequireJS define() calls, which are performed by AMD scripts upon loading
- window.define = function () {
- var stack = getFileStack();
- defineCalls.push({
- stack: stack,
- args: arguments
- });
- };
-
- window.require = function(dependencies, callback){
- return callback && callback();
- };
-
- // Exposed interface
- var requirejsUtil = {
- getDefineArgsInScript: function (scriptPath) {
- var result;
- for (var i = 0; i < defineCalls.length; i++) {
- if (defineCalls[i].stack.indexOf(scriptPath) >= 0) {
- result = defineCalls[i].args;
- break;
- }
- }
- return result;
- }
- };
-
- window.jsunit = window.jsunit || {};
- $.extend(window.jsunit, {requirejsUtil: requirejsUtil});
-})(jQuery, window);
diff --git a/dev/tests/js/JsTestDriver/framework/stub.js b/dev/tests/js/JsTestDriver/framework/stub.js
deleted file mode 100644
index c966ab578cac8..0000000000000
--- a/dev/tests/js/JsTestDriver/framework/stub.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-(function ($, window) {
- "use strict";
-
- function wrapMethod(object, property, method, copyProperties) {
- if (!object) {
- throw new TypeError("Should wrap property of object");
- }
-
- if (typeof method != "function") {
- throw new TypeError("Method wrapper should be function");
- }
-
- var wrappedMethod = object[property],
- error;
-
- if ($.type(wrappedMethod) !== 'function') {
- error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
- property + " as function");
- }
-
- if (wrappedMethod.restore) {
- error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
- }
-
- if (error) {
- if (wrappedMethod._stack) {
- error.stack += '\n--------------\n' + wrappedMethod._stack;
- }
- throw error;
- }
-
- // IE 8 does not support hasOwnProperty.
- var owned = object.hasOwnProperty ?
- object.hasOwnProperty(property) :
- Object.prototype.hasOwnProperty.call(object, property);
-
- object[property] = method;
- method.displayName = property;
- // Stack trace which can be used to find what line of code the original method was created on.
- method._stack = (new Error('Stack Trace for original')).stack;
-
- method.restore = function () {
- if (!owned) {
- delete object[property];
- }
- if (object[property] === method) {
- object[property] = wrappedMethod;
- }
- };
-
- if (copyProperties) {
- for (var prop in wrappedMethod) {
- if (!Object.prototype.hasOwnProperty.call(method, prop)) {
- method[prop] = wrappedMethod[prop];
- }
- }
- }
-
- return method;
- }
-
- function stub(object, property, func, copyProperties) {
- if (!!func && typeof func != "function") {
- throw new TypeError("Custom stub should be function");
- }
-
- var wrapper;
-
- if (func) {
- wrapper = func;
- } else {
- wrapper = stub.create();
- }
-
- if (!object && typeof property === "undefined") {
- return stub.create();
- }
-
- if (typeof property === "undefined" && typeof object == "object") {
- for (var prop in object) {
- if (typeof object[prop] === "function") {
- stub(object, prop);
- }
- }
-
- return object;
- }
-
- return wrapMethod(object, property, wrapper, copyProperties);
- }
-
- $.extend(stub, (function () {
- var proto = {
- create: function create() {
- var functionStub = function () {
- functionStub.callCount = functionStub.callCount ? functionStub.callCount + 1 : 1;
- functionStub.lastCallArgs = arguments;
- functionStub.callArgsStack.push(arguments);
- if (functionStub.returnCallback && $.type(functionStub.returnCallback) === 'function') {
- return functionStub.returnCallback.apply(functionStub.returnCallback, arguments);
- } else if (functionStub.returnValue) {
- return functionStub.returnValue;
- }
- };
- $.extend(functionStub, stub);
- functionStub.reset();
- functionStub.displayName = "stub";
- return functionStub;
- },
-
- reset: function() {
- this.callCount = null;
- this.lastCallArgs = [];
- this.callArgsStack = [];
- this.returnValue = null;
- this.returnCallback = null;
- }
- };
-
- return proto;
- }()));
-
- window.jsunit = window.jsunit || {};
- $.extend(window.jsunit, {
- stub: stub
- });
-})(jQuery, window);
diff --git a/dev/tests/js/JsTestDriver/jsTestDriver.php.dist b/dev/tests/js/JsTestDriver/jsTestDriver.php.dist
deleted file mode 100644
index 089e5220f2d8f..0000000000000
--- a/dev/tests/js/JsTestDriver/jsTestDriver.php.dist
+++ /dev/null
@@ -1,35 +0,0 @@
- 'http://localhost:9876',
- 'load' => array(
- '/dev/tests/js/JsTestDriver/framework',
- '/lib/web/mage/webapi.js',
- '/lib/web/mage/validation/validation.js',
- '/lib/web/jquery/jstree/jquery.jstree.js',
- '/lib/web/jquery/jquery-ui-timepicker-addon.js',
- '/lib/web/mage/cookies.js',
- '/lib/web/mage/calendar.js',
- '/lib/web/mage/loader_old.js',
- '/lib/web/mage/edit-trigger.js',
- '/lib/web/mage/translate-inline.js',
- '/lib/web/mage/translate-inline-vde.js',
- '/lib/web/mage/backend/form.js',
- '/lib/web/mage/backend/button.js',
- '/lib/web/mage/backend/tabs.js',
- '/lib/web/mage/backend/menu.js',
- '/lib/web/mage/backend/suggest.js',
- '/lib/web/mage/backend/tree-suggest.js',
- '/lib/web/mage/zoom.js',
- ),
- 'test' => array('/dev/tests/js/JsTestDriver/testsuite'),
- 'JsTestDriver' => '{{path_to_jstestdriver_jar}}'
-);
diff --git a/dev/tests/js/JsTestDriver/jsTestDriverOrder.php b/dev/tests/js/JsTestDriver/jsTestDriverOrder.php
deleted file mode 100644
index 8ee790a281655..0000000000000
--- a/dev/tests/js/JsTestDriver/jsTestDriverOrder.php
+++ /dev/null
@@ -1,25 +0,0 @@
- 0) {
- fwrite($fh, "proxy:" . PHP_EOL);
- foreach ($proxies as $proxy) {
- $proxyServer = sprintf($proxy['server'], $server, normalize(RELATIVE_APP_ROOT));
- fwrite($fh, ' - {matcher: "' . $proxy['matcher'] . '", server: "' . $proxyServer . '"}' . PHP_EOL);
- }
-}
-
-fwrite($fh, "load:" . PHP_EOL);
-foreach ($sortedFiles as $file) {
- if (!in_array($file, $serveFiles)) {
- fwrite($fh, " - " . $file . PHP_EOL);
- }
-}
-
-fwrite($fh, "test:" . PHP_EOL);
-foreach ($testFiles as $file) {
- fwrite($fh, " - " . $file . PHP_EOL);
-}
-
-if (count($serveFiles) > 0) {
- fwrite($fh, "serve:" . PHP_EOL);
- foreach ($serveFiles as $file) {
- fwrite($fh, " - " . $file . PHP_EOL);
- }
-}
-
-fclose($fh);
-
-$testOutput = __DIR__ . '/test-output';
-
-$filesystemAdapter = new \Magento\Framework\Filesystem\Driver\File();
-if ($filesystemAdapter->isExists($testOutput)) {
- $filesystemAdapter->deleteDirectory($testOutput);
-}
-mkdir($testOutput);
-
-$command
- = 'java -jar "' . $jsTestDriver . '" --config "' . $jsTestDriverConf . '" --reset --port ' . $port .
- ' --browser "' . $browser . '" --raiseOnFailure true --tests all --testOutput "' . $testOutput . '"';
-
-echo $command . PHP_EOL;
-
-if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
- system($command);
-} else {
- $commandFile = __DIR__ . '/run_js_tests.sh';
- $fh = fopen($commandFile, 'w');
-
- $shellCommand
- = 'LSOF=`/usr/sbin/lsof -i :' . $port . ' -t`
- if [ "$LSOF" != "" ];
- then
- kill -9 $LSOF
- fi
-
- # Skip Xvfb setup for OS X since there browsers do not support headless display that way
- if [ "$(uname)" != "Darwin" ]; then
- DISPLAY_NUM=99
- ps -ef | egrep "[X]vfb.*:$DISPLAY_NUM"
- if [ $? -eq 0 ] ; then
- pkill Xvfb
- fi
-
- XVFB=`which Xvfb`
- if [ "$?" -eq 1 ];
- then
- echo "Xvfb not found."
- exit 1
- fi
-
- $XVFB :$DISPLAY_NUM -nolisten inet6 -ac &
- PID_XVFB="$!" # take the process ID
- export DISPLAY=:$DISPLAY_NUM # set display to use that of the Xvfb
- fi
-
- USER=`whoami`
- SUDO=`which sudo`
-
- # run the tests
- $SUDO -u $USER ' . $command . '
-
- if [ "$(uname)" != "Darwin" ]; then
- kill -9 $PID_XVFB # shut down Xvfb (firefox will shut down cleanly by JsTestDriver)
- fi
- echo "Done."';
-
- fwrite($fh, $shellCommand . PHP_EOL);
- fclose($fh);
- chmod($commandFile, 0750);
-
- exec($commandFile);
-}
-
-/**
- * Show a message that displays how to use (invoke) this PHP script and exit.
- */
-function showUsage()
-{
- reportError('Usage: php run_js_tests.php');
-}
-
-/**
- * Reports an error given an error message and exits, effectively halting the PHP script's execution.
- *
- * @param string $message - Error message to be displayed to the user.
- *
- * @SuppressWarnings(PHPMD.ExitExpression)
- */
-function reportError($message)
-{
- echo $message . PHP_EOL;
- exit(1);
-}
-
-/**
- * Takes a file or directory path in any form and normalizes it to fully absolute canonical form
- * relative to this PHP script's location.
- *
- * @param string $filePath - File or directory path to be fully normalized to canonical form.
- *
- * @return string - The fully resolved path converted to absolute form.
- */
-function normalize($filePath)
-{
- return str_replace('\\', '/', realpath(__DIR__ . '/' . $filePath));
-}
-
-/**
- * Accepts an array of directories and generates a list of Javascript files (.js) in those directories and
- * all subdirectories recursively.
- *
- * @param array $dirs - An array of directories as specified in the configuration file (i.e. $configFile).
- *
- * @return array - An array of directory paths to all Javascript files found by recursively searching the
- * specified array of directories.
- */
-function listFiles($dirs)
-{
- $baseDir = normalize(RELATIVE_APP_ROOT);
- $result = [];
- foreach ($dirs as $dir) {
- $path = $baseDir . $dir;
- if (is_file($path)) {
- $path = substr_replace($path, RELATIVE_APP_ROOT, 0, strlen($baseDir));
- array_push($result, $path);
- } else {
- $paths = glob($path . '/*', GLOB_ONLYDIR | GLOB_NOSORT);
- $paths = substr_replace($paths, '', 0, strlen($baseDir));
- $result = array_merge($result, listFiles($paths));
-
- $files = glob($path . '/*.js', GLOB_NOSORT);
- $files = substr_replace($files, RELATIVE_APP_ROOT, 0, strlen($baseDir));
- $result = array_merge($result, $files);
- }
- }
- return $result;
-}
diff --git a/dev/tests/js/JsTestDriver/testsuite/lib/ko/datepicker/datepicker.js b/dev/tests/js/JsTestDriver/testsuite/lib/ko/datepicker/datepicker.js
deleted file mode 100644
index 267c5d3df9a91..0000000000000
--- a/dev/tests/js/JsTestDriver/testsuite/lib/ko/datepicker/datepicker.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-test('DatepickerBinding', function () {
- expect(1);
-
- var element = $('#datepicker'),
- observable = ko.observable(),
- openBtn,
- todayBtn,
- todayDate,
- dateFormat,
- result;
-
- ko.applyBindingsToNode(element, {
- datepicker: observable
- });
-
- dateFormat = $(element).datepicker('option', 'dateFormat');
- todayDate = moment().format(dateFormat);
-
- btn = $('img.ui-datepicker-trigger');
- todayBtn = $('[data-handler="today"]');
-
- btn.click();
- todayBtn.click();
-
- result = moment(observable()).format(dateFormat);
-
- equal(todayDate, result);
-});
diff --git a/dev/tests/js/JsTestDriver/testsuite/lib/ko/datepicker/index.html b/dev/tests/js/JsTestDriver/testsuite/lib/ko/datepicker/index.html
deleted file mode 100644
index e66e34da43945..0000000000000
--- a/dev/tests/js/JsTestDriver/testsuite/lib/ko/datepicker/index.html
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
- */
- var list = $('#list');
- list.decorate('list');
- assertTrue($(list.find('li')[0]).hasClass('odd'));
- assertFalse($(list.find('li')[0]).hasClass('even'));
- assertTrue($(list.find('li')[1]).hasClass('even'));
- assertFalse($(list.find('li')[1]).hasClass('odd'));
- assertTrue($(list.find('li')[2]).hasClass('odd'));
- assertFalse($(list.find('li')[2]).hasClass('even'));
- assertTrue($(list.find('li')[3]).hasClass('even'));
- assertFalse($(list.find('li')[3]).hasClass('odd'));
- assertTrue($(list.find('li')[3]).hasClass('last'));
-};
-
-DecoratorTest.prototype.testDecoratorGeneral = function () {
- /*:DOC +=
-
-
- */
- var tableId = '#foo';
- $(tableId).decorate('table');
- assertTrue($(tableId).find('thead tr').hasClass('first'));
- assertTrue($(tableId).find('thead tr').hasClass('last'));
- assertFalse($(tableId).find('thead tr').hasClass('odd'));
- assertFalse($(tableId).find('thead tr').hasClass('even'));
-
- assertTrue($(tableId).find('tfoot tr').hasClass('first'));
- assertTrue($(tableId).find('tfoot tr').hasClass('last'));
- assertFalse($(tableId).find('tfoot tr').hasClass('odd'));
- assertFalse($(tableId).find('tfoot tr').hasClass('even'));
-
- assertFalse($(tableId).find('tfoot tr td').last().hasClass('first'));
- assertTrue($(tableId).find('tfoot tr td').last().hasClass('last'));
- assertFalse($(tableId).find('tfoot tr td').last().hasClass('odd'));
- assertFalse($(tableId).find('tfoot tr td').last().hasClass('even'));
-
- assertTrue($(tableId).find('tbody tr').first().hasClass('first'));
- assertTrue($(tableId).find('tbody tr').first().hasClass('odd'));
- assertFalse($(tableId).find('tbody tr').first().hasClass('last'));
- assertFalse($(tableId).find('tbody tr').first().hasClass('even'));
- assertFalse($(tableId).find('tbody tr').last().hasClass('first'));
- assertFalse($(tableId).find('tbody tr').last().hasClass('odd'));
- assertTrue($(tableId).find('tbody tr').last().hasClass('last'));
- assertTrue($(tableId).find('tbody tr').last().hasClass('even'));
-
- assertFalse($(tableId).find('tbody tr td').last().hasClass('first'));
- assertFalse($(tableId).find('tbody tr td').last().hasClass('odd'));
- assertTrue($(tableId).find('tbody tr td').last().hasClass('last'));
- assertFalse($(tableId).find('tbody tr td').last().hasClass('even'));
-};
-
-DecoratorTest.prototype.testDecoratorDataList = function () {
- /*:DOC +=
-
-
-
- Month
- Savings
-
-
-
-
- Sum
- $180
-
-
- January
- $100
-
-
-
- February
- $80
-
-
- */
- var listId = '#data-list';
- $(listId).decorate('dataList');
- assertTrue($(listId).find('dt').first().hasClass('odd'));
- assertFalse($(listId).find('dt').first().hasClass('even'));
- assertFalse($(listId).find('dt').first().hasClass('last'));
-
- assertTrue($(listId).find('dt').last().hasClass('even'));
- assertFalse($(listId).find('dt').last().hasClass('odd'));
- assertTrue($(listId).find('dt').last().hasClass('last'));
-
- assertTrue($(listId).find('dd').first().hasClass('odd'));
- assertFalse($(listId).find('dd').first().hasClass('even'));
- assertFalse($(listId).find('dd').first().hasClass('last'));
-
- assertTrue($(listId).find('dd').last().hasClass('even'));
- assertFalse($(listId).find('dd').last().hasClass('odd'));
- assertTrue($(listId).find('dd').last().hasClass('last'));
-};
diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html
deleted file mode 100644
index 3d6ed5a7c1d28..0000000000000
--- a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
- */
- var options = {
- translateForm: {
- data:{
- id: 'translate-form-id',
- newTemplateVariable: ''
- }
- }
- },
- translateInline = jQuery('[data-role="translate-dialog"]').translateInline(options),
- editTrigger = jQuery('#edit-trigger-id').editTrigger(),
- editTriggerCreated = editTrigger.size() && jQuery('#edit-trigger-id').is(':mage-editTrigger'),
- editTriggerEventIsBound = false;
-
- assertTrue(translateInline.is(':mage-translateInline'));
- assertTrue(editTriggerCreated);
- translateInline.on('edit.editTrigger', function(){editTriggerEventIsBound = true;});
- translateInline.translateInline('destroy');
- translateInline.trigger('edit.editTrigger');
- assertFalse(translateInline.is(':mage-translateInline'));
- assertFalse(editTriggerEventIsBound);
-};
diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline_vde/translate-inline-vde-dialog-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline_vde/translate-inline-vde-dialog-test.js
deleted file mode 100644
index 358235eb13bf8..0000000000000
--- a/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline_vde/translate-inline-vde-dialog-test.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
-TranslateInlineDialogVdeTest = TestCase('TranslateInlineDialogVdeTest');
-
-TranslateInlineDialogVdeTest.prototype.testInit = function() {
- /*:DOC +=
-
-
- */
- var translateInlineDialogVde = jQuery('#translate-dialog').translateInlineDialogVde();
- assertTrue(translateInlineDialogVde.is(':mage-translateInlineDialogVde'));
- translateInlineDialogVde.translateInlineDialogVde('destroy');
-};
-TranslateInlineDialogVdeTest.prototype.testWithTemplate = function() {
- /*:DOC +=
-
-
- */
- var translateInlineDialogVde = jQuery('#translate-dialog').translateInlineDialogVde();
- assertEquals(true, translateInlineDialogVde.is(':mage-translateInlineDialogVde'));
- translateInlineDialogVde.translateInlineDialogVde('destroy');
-};
-TranslateInlineDialogVdeTest.prototype.testOpenAndClose = function() {
- /*:DOC +=
-
-
-
- */
- var options = {
- textTranslations: jQuery('[data-translate-mode="text"]'),
- imageTranslations: jQuery('[data-translate-mode="alt"]'),
- scriptTranslations: jQuery('[data-translate-mode="script"]')
- };
-
- var translateInlineDialogVde = jQuery('#translate-dialog').translateInlineDialogVde(options);
-
- var widget = {
- element : jQuery('#randomElement')
- };
-
- jQuery('#translate-dialog').translateInlineDialogVde('openWithWidget', null, widget, function() { });
- assertTrue(jQuery('#translate-dialog').translateInlineDialogVde('isOpen'));
-
- jQuery('#translate-dialog').translateInlineDialogVde('close');
- assertFalse(jQuery('#translate-dialog').translateInlineDialogVde('isOpen'));
-
- jQuery('#translate-dialog').translateInlineDialogVde('destroy');
-};
diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline_vde/translate-inline-vde-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline_vde/translate-inline-vde-test.js
deleted file mode 100644
index 3822310460132..0000000000000
--- a/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline_vde/translate-inline-vde-test.js
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
-TranslateInlineVdeTest = TestCase('TranslateInlineVdeTest');
-TranslateInlineVdeTest.prototype.testInit = function() {
- /*:DOC +=
-
');
- zoomInstance.largeImageSrc = 'large.image.jpg';
-
- zoomInstance._refreshLargeImage();
- assertNotUndefined(zoomInstance.largeImage.prop('src'));
- assertEquals(zoomInstance.largeImage.css('top'), css.top + 'px');
- assertEquals(zoomInstance.largeImage.css('left'), css.left + 'px');
-};
-ZoomTest.prototype.testRenderLargeImage = function() {
- var zoomInstance = this.zoomCreate();
-
- zoomInstance.element.append(jQuery(''));
- zoomInstance.options.selectors.image = '[data-role=test-image]';
-
- var image = zoomInstance._renderLargeImage();
- assertTrue(image.is('img'));
- assertTrue(image.is(zoomInstance.largeImage));
-};
-ZoomTest.prototype.testGetZoomRatio = function() {
- var zoomInstance = this.zoomCreate(),
- imageSize = {width: 100, height: 100},
- largeImageSize = {width: 200, height: 200};
-
- zoomInstance.ratio = null;
- zoomInstance.image = jQuery('
', imageSize);
- zoomInstance.largeImageSize = largeImageSize;
- var zoomRatio = zoomInstance.getZoomRatio();
-
- assertEquals(zoomRatio, (largeImageSize.width / imageSize.width));
- zoomInstance.ratio = 100;
- zoomRatio = zoomInstance.getZoomRatio();
- assertEquals(zoomRatio, zoomInstance.ratio);
-};
-ZoomTest.prototype.testGetAspectRatio = function() {
- var zoomInstance = this.zoomCreate(),
- aspectRatio = zoomInstance._getAspectRatio(),
- size = {width: 200, height: 100};
- assertNull(aspectRatio);
- aspectRatio = zoomInstance._getAspectRatio(jQuery('', size));
- assertEquals((Math.round((size.width / size.height) * 100) / 100), aspectRatio);
-};
diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/menu/index.html b/dev/tests/js/jasmine/assets/lib/web/mage/menu.html
similarity index 50%
rename from dev/tests/js/JsTestDriver/testsuite/mage/menu/index.html
rename to dev/tests/js/jasmine/assets/lib/web/mage/menu.html
index d0a3b9b873801..03c673a7dac5f 100644
--- a/dev/tests/js/JsTestDriver/testsuite/mage/menu/index.html
+++ b/dev/tests/js/jasmine/assets/lib/web/mage/menu.html
@@ -1,36 +1,10 @@
-
-
-
-
-
-
');
+
+ $('body').append(list);
+ });
+
+ afterEach(function () {
+ $('#' + listId).remove();
+ });
+
+ it('Check correct class decoration', function () {
+ var $list = $('#' + listId);
+
+ $list.decorate('list');
+ expect($list.find('li:first').hasClass('first')).toBe(false);
+ expect($list.find('li:first').hasClass('odd')).toBe(true);
+ expect($list.find('li:last').hasClass('last')).toBe(true);
+ expect($list.find('li:odd').hasClass('even')).toBe(true);
+ expect($list.find('li:even').hasClass('odd')).toBe(true);
+ });
+ });
+
+ describe('"generic" method', function () {
+ var listId = 'testList';
+
+ beforeEach(function () {
+ var list = $('
');
+
+ $('body').append(list);
+ });
+
+ afterEach(function () {
+ $('#' + listId).remove();
+ });
+
+ it('Check correct class decoration with default params', function () {
+ var $list = $('#' + listId);
+
+ $list.find('li').decorate('generic');
+ expect($list.find('li:first').hasClass('first')).toBe(true);
+ expect($list.find('li:first').hasClass('odd')).toBe(true);
+ expect($list.find('li:last').hasClass('last')).toBe(true);
+ expect($list.find('li:odd').hasClass('even')).toBe(true);
+ expect($list.find('li:even').hasClass('odd')).toBe(true);
+ });
+
+ it('Check correct class decoration with custom params', function () {
+ var $list = $('#' + listId);
+
+ $list.find('li').decorate('generic', ['last', 'first']);
+ expect($list.find('li:first').hasClass('first')).toBe(true);
+ expect($list.find('li:first').hasClass('odd')).toBe(false);
+ expect($list.find('li:last').hasClass('last')).toBe(true);
+ expect($list.find('li:odd').hasClass('even')).toBe(false);
+ expect($list.find('li:even').hasClass('odd')).toBe(false);
+ });
+
+ it('Check correct class decoration with empty items', function () {
+ var $list = $('#' + listId);
+
+ $list.find('span').decorate('generic', ['last', 'first']);
+ expect($list.find('li:first').hasClass('first')).toBe(false);
+ expect($list.find('li:first').hasClass('odd')).toBe(false);
+ expect($list.find('li:last').hasClass('last')).toBe(false);
+ expect($list.find('li:odd').hasClass('even')).toBe(false);
+ expect($list.find('li:even').hasClass('odd')).toBe(false);
+ });
+ });
+
+ describe('"table" method', function () {
+ var tableId = 'testTable';
+
+ beforeEach(function () {
+ var table = $('
' +
+ '
');
+
+ $('body').append(table);
+ });
+
+ afterEach(function () {
+ $('#' + tableId).remove();
+ });
+
+ it('Check correct class decoration with default params', function () {
+ var $table = $('#' + tableId);
+
+ $table.decorate('table');
+ expect($table.find('tbody tr:first').hasClass('first')).toBe(true);
+ expect($table.find('tbody tr:first').hasClass('odd')).toBe(true);
+ expect($table.find('tbody tr:odd').hasClass('even')).toBe(true);
+ expect($table.find('tbody tr:even').hasClass('odd')).toBe(true);
+ expect($table.find('tbody tr:last').hasClass('last')).toBe(true);
+ expect($table.find('thead tr:first').hasClass('first')).toBe(true);
+ expect($table.find('thead tr:last').hasClass('last')).toBe(true);
+ expect($table.find('tfoot tr:first').hasClass('first')).toBe(true);
+ expect($table.find('tfoot tr:last').hasClass('last')).toBe(true);
+ expect($table.find('tr td:last').hasClass('last')).toBe(true);
+ expect($table.find('tr td:first').hasClass('first')).toBe(false);
+ });
+
+ it('Check correct class decoration with custom params', function () {
+ var $table = $('#' + tableId);
+
+ $table.decorate('table', {
+ 'tbody': ['first'],
+ 'tbody tr': ['first'],
+ 'thead tr': ['first'],
+ 'tfoot tr': ['last'],
+ 'tr td': ['first']
+ });
+ expect($table.find('tbody:first').hasClass('first')).toBe(true);
+ expect($table.find('tbody tr:first').hasClass('first')).toBe(true);
+ expect($table.find('tbody tr:first').hasClass('odd')).toBe(false);
+ expect($table.find('tbody tr:odd').hasClass('even')).toBe(false);
+ expect($table.find('tbody tr:even').hasClass('odd')).toBe(false);
+ expect($table.find('tbody tr:last').hasClass('last')).toBe(false);
+ expect($table.find('thead tr:first').hasClass('first')).toBe(true);
+ expect($table.find('thead tr:last').hasClass('last')).toBe(false);
+ expect($table.find('tfoot tr:first').hasClass('first')).toBe(false);
+ expect($table.find('tfoot tr:last').hasClass('last')).toBe(true);
+ expect($table.find('tr td:last').hasClass('last')).toBe(false);
+ expect($table.find('tr td:first').hasClass('first')).toBe(true);
+ });
+ });
+
+ describe('"dataList" method', function () {
+ var listId = 'testDataList';
+
+ beforeEach(function () {
+ var list = $(' ' +
+ '' +
+ ' ' +
+ ' ' +
+ ' ' +
+ '>' +
+ ' ' +
+ '');
+
+ $('body').append(list);
+ });
+
+ afterEach(function () {
+ $('#' + listId).remove();
+ });
+
+ it('Check correct class decoration', function () {
+ var $list = $('#' + listId);
+
+ $list.decorate('dataList');
+ expect($list.find('dt:first').hasClass('first')).toBe(false);
+ expect($list.find('dt:first').hasClass('odd')).toBe(true);
+ expect($list.find('dt:odd').hasClass('even')).toBe(true);
+ expect($list.find('dt:even').hasClass('odd')).toBe(true);
+ expect($list.find('dt:last').hasClass('last')).toBe(true);
+ expect($list.find('dd:first').hasClass('first')).toBe(false);
+ expect($list.find('dd:first').hasClass('odd')).toBe(true);
+ expect($list.find('dd:odd').hasClass('even')).toBe(true);
+ expect($list.find('dd:even').hasClass('odd')).toBe(true);
+ expect($list.find('dd:last').hasClass('last')).toBe(true);
+ });
+ });
+
+ describe('Call decorate with fake method', function () {
+ var listId = 'testDataList';
+
+ beforeEach(function () {
+ var list = $('
');
+
+ $('body').append(list);
+ });
+
+ afterEach(function () {
+ $('#' + listId).remove();
+ });
+
+ it('Check error message', function () {
+ var $list = $('#' + listId);
+
+ spyOn($, 'error');
+ $list.decorate('customMethod');
+ expect($.error).toHaveBeenCalledWith('Method customMethod does not exist on jQuery.decorate');
+ });
+ });
+ });
+});
diff --git a/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js b/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js
new file mode 100644
index 0000000000000..1d149efe040e0
--- /dev/null
+++ b/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js
@@ -0,0 +1,357 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+/* eslint-disable max-nested-callbacks */
+
+define([
+ 'jquery',
+ 'mage/dropdown'
+], function ($) {
+ 'use strict';
+
+ describe('Test for mage/dropdown jQuery plugin', function () {
+ it('check if dialog opens when the triggerEvent is triggered', function () {
+ var opener = $(''),
+ dialog = $('');
+
+ dialog.dropdownDialog({
+ 'triggerEvent': 'click',
+ 'triggerTarget': opener
+ });
+
+ opener.trigger('click');
+ expect(dialog.dropdownDialog('isOpen')).toBeTruthy();
+
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({
+ 'triggerEvent': null,
+ 'triggerTarget': opener
+ });
+
+ opener.trigger('click');
+ expect(dialog.dropdownDialog('isOpen')).toBeFalsy();
+ dialog.dropdownDialog('destroy');
+ });
+
+ it('check if a specified class is added to the trigger', function () {
+ var opener = $(''),
+ dialog = $('');
+
+ dialog.dropdownDialog({
+ 'triggerClass': 'active',
+ 'triggerTarget': opener
+ });
+
+ dialog.dropdownDialog('open');
+ expect(opener.hasClass('active')).toBeTruthy();
+
+ dialog.dropdownDialog('close');
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({
+ 'triggerClass': null,
+ 'triggerTarget': opener
+ });
+
+ dialog.dropdownDialog('open');
+ expect(opener.hasClass('active')).toBeFalsy();
+
+ dialog.dropdownDialog('close');
+ dialog.dropdownDialog('destroy');
+ });
+
+ it('check if a specified class is added to the element which the dialog appends to', function () {
+ var parent = $(''),
+ dialog = $('');
+
+ dialog.dropdownDialog({
+ 'parentClass': 'active',
+ 'appendTo': parent
+ });
+
+ dialog.dropdownDialog('open');
+ expect(parent.hasClass('active')).toBeTruthy();
+
+ dialog.dropdownDialog('close');
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({
+ 'parentClass': null,
+ 'appendTo': parent
+ });
+
+ dialog.dropdownDialog('open');
+ expect(parent.hasClass('active')).toBeFalsy();
+
+ dialog.dropdownDialog('close');
+ dialog.dropdownDialog('destroy');
+ });
+
+ it('check if a specified class is added to the element that becomes dialog', function () {
+ var dialog = $(''),
+ content;
+
+ dialog.dropdownDialog({
+ 'dialogContentClass': 'active'
+ });
+
+ content = $('.ui-dialog-content');
+ dialog.dropdownDialog('open');
+ expect(content.hasClass('active')).toBeTruthy();
+
+ dialog.dropdownDialog('close');
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({
+ 'dialogContentClass': null
+ });
+
+ dialog.dropdownDialog('open');
+ expect(content.hasClass('active')).toBeFalsy();
+
+ dialog.dropdownDialog('close');
+ dialog.dropdownDialog('destroy');
+ });
+
+ it('check if a specified class is added to dialog', function () {
+ var dialog = $(''),
+ uiClass = '.ui-dialog',
+ ui;
+
+ dialog.dropdownDialog({
+ 'defaultDialogClass': 'custom'
+ });
+
+ ui = $(uiClass);
+ expect(ui.hasClass('custom')).toBeTruthy();
+ expect(ui.hasClass('mage-dropdown-dialog')).toBeFalsy();
+
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({});
+ ui = $(uiClass);
+ expect(ui.hasClass('mage-dropdown-dialog')).toBeTruthy();
+
+ dialog.dropdownDialog('destroy');
+ });
+
+ it('check if the specified trigger actually opens the dialog', function () {
+ var opener = $(''),
+ dialog = $('');
+
+ dialog.dropdownDialog({
+ 'triggerTarget': opener
+ });
+
+ opener.trigger('click');
+ expect(dialog.dropdownDialog('isOpen')).toBeTruthy();
+
+ dialog.dropdownDialog('close');
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({
+ 'triggerTarget': null
+ });
+
+ opener.trigger('click');
+ expect(dialog.dropdownDialog('isOpen')).toBeFalsy();
+
+ dialog.dropdownDialog('destroy');
+ });
+
+ it('check if the dialog gets closed when clicking outside of it', function () {
+ var container = $(''),
+ outside = $('').attr('id', 'outside').appendTo(container),
+ dialog = $('').attr('id', 'dialog').appendTo(container);
+
+ container.appendTo('body');
+
+ dialog.dropdownDialog({
+ 'closeOnClickOutside': true
+ });
+
+ dialog.dropdownDialog('open');
+ outside.trigger('click');
+ expect(dialog.dropdownDialog('isOpen')).toBeFalsy();
+
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({
+ 'closeOnClickOutside': false
+ });
+
+ dialog.dropdownDialog('open');
+ outside.trigger('click');
+ expect(dialog.dropdownDialog('isOpen')).toBeTruthy();
+
+ dialog.dropdownDialog('destroy');
+ });
+
+ it('check if the dialog gets closed when mouse leaves the dialog area', function () {
+ var container = $(''),
+ dialog = $('').attr('id', 'dialog').appendTo(container);
+
+ $('').attr('id', 'outside').appendTo(container);
+ $('').attr('id', 'opener').appendTo(container);
+
+ container.appendTo('body');
+
+ jasmine.clock().install();
+
+ dialog.dropdownDialog({
+ 'closeOnMouseLeave': true
+ });
+
+ dialog.dropdownDialog('open');
+ dialog.trigger('mouseenter');
+ expect(dialog.dropdownDialog('isOpen')).toBeTruthy();
+
+ dialog.trigger('mouseleave');
+
+ jasmine.clock().tick(10);
+
+ expect(dialog.dropdownDialog('isOpen')).toBeFalsy();
+ dialog.dropdownDialog('destroy');
+
+ jasmine.clock().uninstall();
+ });
+
+ it('check if the dialog does not close when mouse leaves the dialog area', function () {
+ var container = $(''),
+ dialog = $('').attr('id', 'dialog').appendTo(container);
+
+ $('').attr('id', 'outside').appendTo(container);
+ $('').attr('id', 'opener').appendTo(container);
+
+ container.appendTo('body');
+
+ jasmine.clock().install();
+
+ dialog.dropdownDialog({
+ 'closeOnMouseLeave': false
+ });
+
+ dialog.dropdownDialog('open');
+ dialog.trigger('mouseenter');
+ dialog.trigger('mouseleave');
+ jasmine.clock().tick(10);
+ expect(dialog.dropdownDialog('isOpen')).toBeTruthy();
+ dialog.dropdownDialog('destroy');
+
+ jasmine.clock().uninstall();
+ });
+
+ it('check if the dialog gets closed with the specified delay', function (done) {
+ var container = $(''),
+ dialog = $('').attr('id', 'dialog').appendTo(container);
+
+ $('').attr('id', 'outside').appendTo(container);
+ $('').attr('id', 'opener').appendTo(container);
+
+ container.appendTo('body');
+
+ dialog.dropdownDialog({
+ 'timeout': 5
+ });
+
+ dialog.dropdownDialog('open');
+ dialog.trigger('mouseenter');
+ dialog.trigger('mouseleave');
+ expect(dialog.dropdownDialog('isOpen')).toBeTruthy();
+
+ setTimeout(function () {
+ expect(dialog.dropdownDialog('isOpen')).toBeFalsy();
+ dialog.dropdownDialog('destroy');
+ done();
+ }, 6);
+ });
+
+ /*
+ * jQuery ui version 1.9.2 belongs to the adminhtml.
+ *
+ * This test will fail on backend since backend's jquery.ui will
+ * add ui-dialog-titlebar class anyway on create.
+ */
+ if ($.ui.version !== '1.9.2') {
+ it('check if the title bar is prevented from being created', function () {
+ var dialog = $(''),
+ uiClass = '.ui-dialog',
+ ui;
+
+ dialog.dropdownDialog({
+ 'createTitleBar': true
+ });
+
+ ui = $(uiClass);
+ expect(ui.find('.ui-dialog-titlebar').length > 0).toBeTruthy();
+
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({
+ 'createTitleBar': false
+ });
+
+ ui = $(uiClass);
+ expect(ui.find('.ui-dialog-titlebar').length <= 0).toBeTruthy();
+
+ dialog.dropdownDialog('destroy');
+ });
+ }
+
+ it('check if the position function gets disabled', function () {
+ var dialog = $(''),
+ uiClass = '.ui-dialog',
+ ui;
+
+ dialog.dropdownDialog({
+ 'autoPosition': false
+ });
+
+ ui = $(uiClass);
+ dialog.dropdownDialog('open');
+ expect(ui.css('top') === 'auto').toBeTruthy();
+
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({
+ 'autoPosition': true
+ });
+
+ ui = $(uiClass);
+ dialog.dropdownDialog('open');
+ expect(ui.css('top') !== '0px').toBeTruthy();
+
+ dialog.dropdownDialog('destroy');
+ });
+
+ it('check if the size function gets disabled', function () {
+ var dialog = $(''),
+ uiClass = '.ui-dialog',
+ ui;
+
+ dialog.dropdownDialog({
+ 'autoSize': true,
+ 'width': '300'
+ });
+
+ ui = $(uiClass);
+ dialog.dropdownDialog('open');
+ expect(ui.css('width') === '300px').toBeTruthy();
+
+ dialog.dropdownDialog('destroy');
+
+ dialog.dropdownDialog({
+ 'autoSize': false,
+ 'width': '300'
+ });
+
+ ui = $(uiClass);
+ dialog.dropdownDialog('open');
+ expect(ui.css('width') === '300px').toBeFalsy();
+
+ dialog.dropdownDialog('destroy');
+ });
+ });
+});
diff --git a/dev/tests/js/jasmine/tests/lib/mage/form.test.js b/dev/tests/js/jasmine/tests/lib/mage/form.test.js
new file mode 100644
index 0000000000000..6202f93da999a
--- /dev/null
+++ b/dev/tests/js/jasmine/tests/lib/mage/form.test.js
@@ -0,0 +1,262 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+/* eslint-disable max-nested-callbacks */
+/* jscs:disable jsDoc */
+
+define([
+ 'jquery',
+ 'mage/backend/form'
+], function ($) {
+ 'use strict';
+
+ /*
+ * jQuery ui version 1.9.2 belongs to the adminhtml.
+ *
+ * This test will fail on frontend since mage/backend/form only belongs to backend.
+ */
+ if ($.ui.version === '1.9.2') {
+ describe('Test for mage/form jQuery plugin', function () {
+ var id = 'edit_form',
+ elementId = '#' + id;
+
+ beforeEach(function () {
+ var element = $('');
+
+ element.appendTo('body');
+ });
+
+ afterEach(function () {
+ $(elementId).remove();
+ });
+
+ it('check if form can be initialized', function () {
+ var form = $(elementId).form();
+
+ expect(form.is(':mage-form')).toBeTruthy();
+ });
+
+ it('check get handlers', function () {
+ var form = $(elementId).form(),
+ handlersData = form.form('option', 'handlersData'),
+ handlers = [];
+
+ $.each(handlersData, function (key) {
+ handlers.push(key);
+ });
+ expect(handlers.join(' ')).toBe(form.data('form')._getHandlers().join(' '));
+ });
+
+ it('check store attribute', function () {
+ var form = $(elementId).form(),
+ initialFormAttrs = {
+ action: form.attr('action'),
+ target: form.attr('target'),
+ method: form.attr('method')
+ };
+
+ form.data('form')._storeAttribute('action');
+ form.data('form')._storeAttribute('target');
+ form.data('form')._storeAttribute('method');
+
+ expect(form.data('form').oldAttributes.action).toBe(initialFormAttrs.action);
+ expect(form.data('form').oldAttributes.target).toBe(initialFormAttrs.target);
+ expect(form.data('form').oldAttributes.method).toBe(initialFormAttrs.method);
+ });
+
+ it('check bind', function () {
+ var form = $(elementId).form(),
+ submitted = false,
+ handlersData = form.form('option', 'handlersData');
+
+ form.on('submit', function (e) {
+ submitted = true;
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ });
+
+ $.each(handlersData, function (key) {
+ form.trigger(key);
+ expect(submitted).toBeTruthy();
+ submitted = false;
+ });
+
+ form.off('submit');
+ });
+
+ it('check get action URL', function () {
+ var form = $(elementId).form(),
+ action = form.attr('action'),
+ testUrl = 'new/action/url',
+ testArgs = {
+ args: {
+ arg: 'value'
+ }
+ };
+
+ form.data('form')._storeAttribute('action');
+ expect(form.data('form')._getActionUrl(testArgs)).toBe(action + '/arg/value/');
+ expect(form.data('form')._getActionUrl(testUrl)).toBe(testUrl);
+ expect(form.data('form')._getActionUrl()).toBe(action);
+ });
+
+ it('check process data', function () {
+ var form = $(elementId).form(),
+ initialFormAttrs = {
+ action: form.attr('action'),
+ target: form.attr('target'),
+ method: form.attr('method')
+ },
+ testSimpleData = {
+ action: 'new/action/url',
+ target: '_blank',
+ method: 'POST'
+ },
+ testActionArgsData = {
+ action: {
+ args: {
+ arg: 'value'
+ }
+ }
+ },
+ processedData = form.data('form')._processData(testSimpleData);
+
+ expect(form.data('form').oldAttributes.action).toBe(initialFormAttrs.action);
+ expect(form.data('form').oldAttributes.target).toBe(initialFormAttrs.target);
+ expect(form.data('form').oldAttributes.method).toBe(initialFormAttrs.method);
+ expect(processedData.action).toBe(testSimpleData.action);
+ expect(processedData.target).toBe(testSimpleData.target);
+ expect(processedData.method).toBe(testSimpleData.method);
+
+ form.data('form')._rollback();
+ processedData = form.data('form')._processData(testActionArgsData);
+ form.data('form')._storeAttribute('action');
+ expect(processedData.action).toBe(form.data('form')._getActionUrl(testActionArgsData.action));
+ });
+
+ it('check before submit', function () {
+ var testForm = $('').appendTo('body'),
+ testHandler = {
+ action: {
+ args: {
+ arg1: 'value1'
+ }
+ }
+ },
+ form = $(elementId).form({
+ handlersData: {
+ testHandler: testHandler
+ }
+ }),
+ beforeSubmitData = {
+ action: {
+ args: {
+ arg2: 'value2'
+ }
+ },
+ target: '_blank'
+ },
+ eventData = {
+ method: 'POST'
+ },
+ resultData = $.extend(true, {}, testHandler, beforeSubmitData, eventData);
+
+ form.data('form')._storeAttribute('action');
+ resultData = form.data('form')._processData(resultData);
+ testForm.prop(resultData);
+
+ form.on('beforeSubmit', function (e, data) {
+ $.extend(data, beforeSubmitData);
+ });
+
+ form.on('submit', function (e) {
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ });
+
+ form.data('form')._beforeSubmit('testHandler', eventData);
+ expect(testForm.prop('action')).toBe(form.prop('action'));
+ expect(testForm.prop('target')).toBe(form.prop('target'));
+ expect(testForm.prop('method')).toBe(form.prop('method'));
+ });
+
+ it('check submit', function () {
+ var formSubmitted = false,
+ form = $(elementId).form({
+ handlersData: {
+ save: {}
+ }
+ });
+
+ form.data('form')._storeAttribute('action');
+ form.data('form')._storeAttribute('target');
+ form.data('form')._storeAttribute('method');
+
+ form.on('submit', function (e) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ formSubmitted = true;
+ }).prop({
+ action: 'new/action/url',
+ target: '_blank',
+ method: 'POST'
+ });
+
+ form.data('form')._submit({
+ type: 'save'
+ });
+
+ expect(form.attr('action')).toBe(form.data('form').oldAttributes.action);
+ expect(form.attr('target')).toBe(form.data('form').oldAttributes.target);
+ expect(form.attr('method')).toBe(form.data('form').oldAttributes.method);
+ expect(formSubmitted).toBeTruthy();
+
+ form.off('submit');
+ });
+
+ it('check build URL', function () {
+ var dataProvider = [
+ {
+ params: ['http://domain.com//', {
+ 'key[one]': 'value 1',
+ 'key2': '# value'
+ }],
+ expected: 'http://domain.com/key[one]/value%201/key2/%23%20value/'
+ },
+ {
+ params: ['http://domain.com', {
+ 'key[one]': 'value 1',
+ 'key2': '# value'
+ }],
+ expected: 'http://domain.com/key[one]/value%201/key2/%23%20value/'
+ },
+ {
+ params: ['http://domain.com?some=param', {
+ 'key[one]': 'value 1',
+ 'key2': '# value'
+ }],
+ expected: 'http://domain.com?some=param&key[one]=value%201&key2=%23%20value'
+ },
+ {
+ params: ['http://domain.com?some=param&', {
+ 'key[one]': 'value 1',
+ 'key2': '# value'
+ }],
+ expected: 'http://domain.com?some=param&key[one]=value%201&key2=%23%20value'
+ }
+ ],
+ method = $.mage.form._proto._buildURL,
+ quantity = dataProvider.length,
+ i = 0;
+
+ expect(quantity).toBeTruthy();
+
+ for (i; i < quantity; i++) {
+ expect(dataProvider[i].expected).toBe(method.apply(null, dataProvider[i].params));
+ }
+ });
+ });
+ }
+});
diff --git a/dev/tests/js/jasmine/tests/lib/mage/loader.test.js b/dev/tests/js/jasmine/tests/lib/mage/loader.test.js
new file mode 100644
index 0000000000000..93dd2ee91902c
--- /dev/null
+++ b/dev/tests/js/jasmine/tests/lib/mage/loader.test.js
@@ -0,0 +1,79 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/* eslint-disable max-nested-callbacks */
+define([
+ 'jquery',
+ 'mage/loader'
+], function ($) {
+ 'use strict';
+
+ describe('mage/loader', function () {
+ describe('Check loader', function () {
+ var loaderSelector = '#loader';
+
+ beforeEach(function () {
+ var $loader = $('');
+
+ $('body').append($loader);
+ });
+
+ afterEach(function () {
+ $(loaderSelector).remove();
+ $(loaderSelector).loader('destroy');
+ });
+
+ it('Check that loader inited', function () {
+ var $loader = $(loaderSelector).loader({
+ icon: 'icon.gif'
+ });
+
+ $loader.loader('show');
+
+ expect($loader.is(':mage-loader')).toBe(true);
+ expect($loader.find('p').text()).toBe('Please wait...');
+ expect($loader.find('img').prop('src').split('/').pop()).toBe('icon.gif');
+ expect($loader.find('img').prop('alt')).toBe('Loading...');
+ });
+
+ it('Body init', function () {
+ var $loader = $('body').loader();
+
+ $loader.loader('show');
+
+ expect($loader.is(':mage-loader')).toBe(true);
+ $loader.loader('destroy');
+ });
+
+ it('Check show/hide', function () {
+ var $loader = $(loaderSelector).loader(),
+ $loadingMask;
+
+ $loader.loader('show');
+ $loadingMask = $('.loading-mask');
+ expect($loadingMask.is(':visible')).toBe(true);
+
+ $loader.loader('hide');
+ expect($loadingMask.is(':hidden')).toBe(true);
+
+ $loader.loader('show');
+ $loader.trigger('processStop');
+ expect($loadingMask.is(':hidden')).toBe(true);
+ });
+
+ it('Check destroy', function () {
+ var $loader = $(loaderSelector).loader(),
+ $loadingMask;
+
+ $loader.loader('show');
+ $loadingMask = $('.loading-mask');
+ expect($loadingMask.is(':visible')).toBe(true);
+
+ $loader.loader('destroy');
+ expect($loadingMask.is(':visible')).toBe(false);
+ });
+ });
+ });
+});
diff --git a/dev/tests/js/jasmine/tests/lib/mage/menu.test.js b/dev/tests/js/jasmine/tests/lib/mage/menu.test.js
new file mode 100644
index 0000000000000..69d8af4ff3dba
--- /dev/null
+++ b/dev/tests/js/jasmine/tests/lib/mage/menu.test.js
@@ -0,0 +1,110 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/* eslint-disable max-nested-callbacks */
+define([
+ 'jquery',
+ 'mage/menu',
+ 'text!tests/assets/lib/web/mage/menu.html'
+], function ($, menu, menuTmpl) {
+ 'use strict';
+
+ describe('mage/menu', function () {
+ describe('Menu expanded', function () {
+ var menuSelector = '#menu';
+
+ beforeEach(function () {
+ var $menu = $(menuTmpl);
+
+ $('body').append($menu);
+ });
+
+ afterEach(function () {
+ $(menuSelector).remove();
+ });
+
+ it('Check that menu expanded', function () {
+ var $menu = $(menuSelector),
+ $menuItems = $menu.find('li'),
+ $submenu = $menuItems.find('ul');
+
+ menu.menu({
+ expanded: true
+ }, $menu);
+ expect($submenu.hasClass('expanded')).toBe(true);
+ });
+ });
+
+ describe('Menu hover event', function () {
+ var menuSelector = '#menu',
+ $menu;
+
+ beforeEach(function () {
+ var $menuObject = $(menuTmpl);
+
+ $('body').append($menuObject);
+ $menu = $(menuSelector).menu({
+ delay: 0,
+ showDelay: 0,
+ hideDelay: 0
+ });
+ });
+
+ afterEach(function () {
+ $(menuSelector).remove();
+ });
+
+ it('Check that menu expanded', function (done) {
+ var $menuItem = $menu.find('li.test-menu-item'),
+ $submenu = $menuItem.find('ul');
+
+ $menuItem.trigger('mouseover');
+ setTimeout(function () {
+ expect($submenu.attr('aria-expanded')).toBe('true');
+ $menuItem.trigger('mouseout');
+ setTimeout(function () {
+ expect($submenu.attr('aria-expanded')).toBe('false');
+ done();
+ }, 300);
+ }, 300);
+ });
+ });
+
+ describe('Menu navigation', function () {
+ var menuSelector = '#menu',
+ $menu;
+
+ beforeEach(function () {
+ var $menuObject = $(menuTmpl);
+
+ $('body').append($menuObject);
+ $menu = $(menuSelector).menu();
+ });
+
+ afterEach(function () {
+ $(menuSelector).remove();
+ });
+
+ it('Check max item limit', function () {
+ var $menuItems;
+
+ $menu.navigation({
+ maxItems: 3
+ });
+ $menuItems = $menu.find('li:visible');
+
+ expect($menuItems.length).toBe(4);
+ });
+
+ it('Check that More Menu item will be added', function () {
+ $menu.navigation({
+ responsive: 'onResize'
+ });
+
+ expect($('body').find('.ui-menu-more').length).toBeGreaterThan(0);
+ });
+ });
+ });
+});
diff --git a/dev/tests/js/jasmine/tests/lib/mage/tabs.test.js b/dev/tests/js/jasmine/tests/lib/mage/tabs.test.js
new file mode 100644
index 0000000000000..a6138df073434
--- /dev/null
+++ b/dev/tests/js/jasmine/tests/lib/mage/tabs.test.js
@@ -0,0 +1,93 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/* eslint-disable max-nested-callbacks */
+define([
+ 'jquery',
+ 'jquery/ui',
+ 'mage/tabs',
+ 'text!tests/assets/lib/web/mage/tabs.html'
+], function ($, ui, tabs, tabsTmpl) {
+ 'use strict';
+
+ describe('mage/tabs', function () {
+ var tabsSelector = '#tabs';
+
+ beforeEach(function () {
+ var $tabs = $(tabsTmpl);
+
+ $('body').append($tabs);
+ });
+
+ afterEach(function () {
+ $(tabsSelector).remove();
+ $(tabsSelector).tabs('destroy');
+ });
+
+ it('Check tabs inited', function () {
+ var $tabs = $(tabsSelector).tabs();
+
+ expect($tabs.is(':mage-tabs')).toBe(true);
+ });
+
+ it('Check tabs collapsible inited', function () {
+ var $title1 = $('#title1'),
+ $title2 = $('#title2');
+
+ $(tabsSelector).tabs();
+
+ expect($title1.is(':mage-collapsible')).toBe(true);
+ expect($title2.is(':mage-collapsible')).toBe(true);
+ });
+
+ it('Check tabs active', function () {
+ var $content1 = $('#content1'),
+ $content2 = $('#content2');
+
+ $(tabsSelector).tabs({
+ active: 1
+ });
+
+ expect($content1.is(':hidden')).toBe(true);
+ expect($content2.is(':visible')).toBe(true);
+ });
+
+ it('Check tabs closing others tabs when one gets activated', function () {
+ var $title2 = $('#title2'),
+ $content1 = $('#content1'),
+ $content2 = $('#content2');
+
+ $(tabsSelector).tabs();
+
+ expect($content1.is(':visible')).toBe(true);
+ expect($content2.is(':hidden')).toBe(true);
+
+ $title2.trigger('click');
+
+ expect($content1.is(':hidden')).toBe(true);
+ expect($content2.is(':visible')).toBe(true);
+ });
+
+ it('Check tabs enable,disable,activate,deactivate options', function () {
+ var $title1 = $('#title1'),
+ $content1 = $('#content1'),
+ $tabs = $(tabsSelector).tabs();
+
+ expect($content1.is(':visible')).toBe(true);
+ $tabs.tabs('deactivate', 0);
+ expect($content1.is(':hidden')).toBe(true);
+ $tabs.tabs('activate', 0);
+ expect($content1.is(':visible')).toBe(true);
+ $tabs.tabs('disable', 0);
+ expect($content1.is(':hidden')).toBe(true);
+ $title1.trigger('click');
+ expect($content1.is(':hidden')).toBe(true);
+ $tabs.tabs('enable', 0);
+ expect($content1.is(':visible')).toBe(true);
+ $title1.trigger('click');
+ expect($content1.is(':visible')).toBe(true);
+ });
+ });
+});
diff --git a/dev/tests/js/jasmine/tests/lib/mage/translate-inline.test.js b/dev/tests/js/jasmine/tests/lib/mage/translate-inline.test.js
new file mode 100644
index 0000000000000..bcdfc4cc59705
--- /dev/null
+++ b/dev/tests/js/jasmine/tests/lib/mage/translate-inline.test.js
@@ -0,0 +1,111 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/* eslint-disable max-nested-callbacks */
+define([
+ 'jquery',
+ 'mage/translate-inline',
+ 'text!tests/assets/lib/web/mage/translate-inline.html'
+], function ($, TranslateInline, translateTmpl) {
+ 'use strict';
+
+ describe('mage/translate-inline', function () {
+ describe('Check translate', function () {
+ var translateSelector = '[data-role="translate-dialog"]',
+ translateTemplateSelector = '#translate-form-template';
+
+ beforeEach(function () {
+ var translateBlock = $(translateTmpl);
+
+ $('body').append(translateBlock);
+ });
+
+ afterEach(function () {
+ $(translateSelector).remove();
+ $(translateSelector).translateInline('destroy');
+ $(translateTemplateSelector).remove();
+ });
+
+ it('Check that translate inited', function () {
+ var translateInline = $(translateSelector).translateInline();
+
+ expect(translateInline.is(':mage-translateInline')).toBe(true);
+ });
+
+ it('Check that translate hidden on init and visible on trigger', function () {
+ var translateInline = $(translateSelector).translateInline({
+ id: 'dialog-id'
+ }),
+ isDialogHiddenOnInit = translateInline.is(':hidden'),
+ dialogVisibleAfterTriggerEdit;
+
+ translateInline.trigger('edit.editTrigger');
+ dialogVisibleAfterTriggerEdit = translateInline.is(':visible');
+ expect(isDialogHiddenOnInit).toBe(true);
+ expect(dialogVisibleAfterTriggerEdit).toBe(true);
+ });
+
+ it('Check translation form template', function () {
+ var translateFormId = 'translate-form-id',
+ translateFormContent = 'New Template Variable',
+ translateInline = $(translateSelector).translateInline({
+ translateForm: {
+ data: {
+ id: translateFormId,
+ newTemplateVariable: translateFormContent
+ }
+ }
+ }),
+ $translateForm;
+
+ translateInline.trigger('edit.editTrigger');
+ $translateForm = $('#' + translateFormId);
+
+ expect($translateForm.length).toBeGreaterThan(0);
+ expect($translateForm.text()).toBe(translateFormContent);
+ });
+
+ it('Check translation submit', function () {
+ var options = {
+ ajaxUrl: 'www.test.com',
+ area: 'test',
+ translateForm: {
+ template: '',
+ data: {
+ id: 'translate-form-id'
+ }
+ }
+ },
+ expectedEequestData = 'area=test&test=test',
+ translateInline = $(translateSelector).translateInline(options),
+ $submitButton = $('body').find('.action-primary'),
+ originalAjax = $.ajax;
+
+ $.ajax = jasmine.createSpy().and.callFake(function (request) {
+ expect(request.url).toBe(options.ajaxUrl);
+ expect(request.type).toBe('POST');
+ expect(request.data).toBe(expectedEequestData);
+
+ return {
+ complete: jasmine.createSpy()
+ };
+ });
+
+ translateInline.trigger('edit.editTrigger');
+ $submitButton.trigger('click');
+ $.ajax = originalAjax;
+ });
+
+ it('Check translation destroy', function () {
+ var translateInline = $(translateSelector).translateInline();
+
+ translateInline.trigger('edit.editTrigger');
+ expect(translateInline.is(':mage-translateInline')).toBe(true);
+ translateInline.translateInline('destroy');
+ expect(translateInline.is(':mage-translateInline')).toBe(false);
+ });
+ });
+ });
+});
diff --git a/dev/tests/js/jasmine/tests/lib/mage/translate.test.js b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js
new file mode 100644
index 0000000000000..c87cfa227c1aa
--- /dev/null
+++ b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js
@@ -0,0 +1,49 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+/* eslint-disable max-nested-callbacks */
+define([
+ 'jquery',
+ 'mage/translate'
+], function ($) {
+ 'use strict';
+
+ describe('Test for mage/translate jQuery plugin', function () {
+ it('works with one string as parameter', function () {
+ $.mage.translate.add('Hello World!');
+ expect('Hello World!').toEqual($.mage.translate.translate('Hello World!'));
+ });
+ it('works with one array as parameter', function () {
+ $.mage.translate.add(['Hello World!', 'Bonjour tout le monde!']);
+ expect('Hello World!').toEqual($.mage.translate.translate('Hello World!'));
+ });
+ it('works with one object as parameter', function () {
+ var translation = {
+ 'Hello World!': 'Bonjour tout le monde!'
+ };
+
+ $.mage.translate.add(translation);
+ expect(translation['Hello World!']).toEqual($.mage.translate.translate('Hello World!'));
+
+ translation = {
+ 'Hello World!': 'Hallo Welt!',
+ 'Some text with symbols!-+"%#*': 'Ein Text mit Symbolen!-+"%#*'
+ };
+
+ $.mage.translate.add(translation);
+ $.each(translation, function (key) {
+ expect(translation[key]).toEqual($.mage.translate.translate(key));
+ });
+ });
+ it('works with two string as parameter', function () {
+ $.mage.translate.add('Hello World!', 'Bonjour tout le monde!');
+ expect('Bonjour tout le monde!').toEqual($.mage.translate.translate('Hello World!'));
+ });
+ it('works with translation alias __', function () {
+ $.mage.translate.add('Hello World!');
+ expect('Hello World!').toEqual($.mage.__('Hello World!'));
+ });
+ });
+
+});
diff --git a/dev/tests/js/jasmine/tests/lib/mage/validation.test.js b/dev/tests/js/jasmine/tests/lib/mage/validation.test.js
index 50931f940c689..1e1203d22a1e3 100644
--- a/dev/tests/js/jasmine/tests/lib/mage/validation.test.js
+++ b/dev/tests/js/jasmine/tests/lib/mage/validation.test.js
@@ -183,4 +183,963 @@ define([
)).toEqual(true);
});
});
+
+ describe('Testing validate-no-html-tags', function () {
+ it('validate-no-html-tags', function () {
+ expect($.validator.methods['validate-no-html-tags']
+ .call($.validator.prototype, '')).toEqual(true);
+ expect($.validator.methods['validate-no-html-tags']
+ .call($.validator.prototype, null)).toEqual(true);
+ expect($.validator.methods['validate-no-html-tags']
+ .call($.validator.prototype, 'abc')).toEqual(true);
+ expect($.validator.methods['validate-no-html-tags']
+ .call($.validator.prototype, '
';
-
- if (attributes['type_name']) {
- imageHtml += attributes['type_name'];
- }
+ return isSelected;
+ },
- imageHtml += '';
+ /**
+ * Convert {{widget}} style syntax to image placeholder HTML
+ * @param {String} content
+ * @return {*}
+ */
+ encodeWidgets: function (content) {
+ return content.gsub(/\{\{widget(.*?)\}\}/i, function (match) {
+ var attributes = wysiwyg.parseAttributesString(match[1]),
+ imageSrc,
+ imageHtml = '';
+
+ if (attributes.type) {
+ attributes.type = attributes.type.replace(/\\\\/g, '\\');
+ imageSrc = config.placeholders[attributes.type];
+
+ if (config.types.indexOf(attributes['type_name']) > -1) {
+ imageHtml += '';
+ } else {
+ imageSrc = config['error_image_url'];
+ imageHtml += '';
+ }
+
+ imageHtml += '
';
+
+ if (attributes['type_name']) {
+ imageHtml += attributes['type_name'];
+ }
+
+ imageHtml += '';
+
+ return imageHtml;
+ }
+ });
+ },
- return imageHtml;
- }
- }.bind(this));
- },
-
- /**
- * Convert image placeholder HTML to {{widget}} style syntax
- * @param {String} content
- * @return {*}
- */
- decodeWidgets: function (content) {
- return content.gsub(
- /(]*>)?
]+id="[^>]+)>(([^>]*)<\/span>)?/i,
- function (match) {
- var attributes = this.constructor.adapter.parseAttributesString(match[2]),
- widgetCode;
-
- if (attributes.id) {
- widgetCode = Base64.idDecode(attributes.id);
-
- if (widgetCode.indexOf('{{widget') !== -1) {
- return widgetCode;
+ /**
+ * Convert image placeholder HTML to {{widget}} style syntax
+ * @param {String} content
+ * @return {*}
+ */
+ decodeWidgets: function (content) {
+ return content.gsub(
+ /(]*>)?
]+id="[^>]+)>(([^>]*)<\/span>)?/i,
+ function (match) {
+ var attributes = wysiwyg.parseAttributesString(match[2]),
+ widgetCode;
+
+ if (attributes.id) {
+ widgetCode = Base64.idDecode(attributes.id);
+
+ if (widgetCode.indexOf('{{widget') !== -1) {
+ return widgetCode;
+ }
+ }
+
+ return match[0];
}
- }
+ );
+ },
- return match[0];
- }.bind(this)
- );
- },
+ /**
+ * Tinymce has strange behavior with html and this removes one of its side-effects
+ * @param {String} content
+ * @return {String}
+ */
+ removeDuplicateAncestorWidgetSpanElement: function (content) {
+ var parser, doc;
- /**
- * Tinymce has strange behavior with html and this removes one of its side-effects
- * @param {String} content
- * @return {String}
- */
- removeDuplicateAncestorWidgetSpanElement: function (content) {
- var parser, doc;
+ if (!window.DOMParser) {
+ return content;
+ }
- if (!window.DOMParser) {
- return content;
- }
+ parser = new DOMParser();
+ doc = parser.parseFromString(content.replace(/"/g, '"'), 'text/html');
- parser = new DOMParser();
- doc = parser.parseFromString(content, 'text/html');
+ [].forEach.call(doc.querySelectorAll('.magento-widget'), function (widgetEl) {
+ var widgetChildEl = widgetEl.querySelector('.magento-widget');
- [].forEach.call(doc.querySelectorAll('.magento-widget'), function (widgetEl) {
- var widgetChildEl = widgetEl.querySelector('.magento-widget');
+ if (!widgetChildEl) {
+ return;
+ }
- if (!widgetChildEl) {
- return;
- }
+ [].forEach.call(widgetEl.childNodes, function (el) {
+ widgetEl.parentNode.insertBefore(el, widgetEl);
+ });
- [].forEach.call(widgetEl.childNodes, function (el) {
- widgetEl.parentNode.insertBefore(el, widgetEl);
- });
+ widgetEl.parentNode.removeChild(widgetEl);
+ });
- widgetEl.parentNode.removeChild(widgetEl);
+ return doc.body ? doc.body.innerHTML.replace(/"/g, '"') : content;
+ },
+
+ /**
+ * @return {Object}
+ */
+ getInfo: function () {
+ return {
+ longname: 'Magento Widget Manager Plugin',
+ author: 'Magento Core Team',
+ authorurl: 'http://magentocommerce.com',
+ infourl: 'http://magentocommerce.com',
+ version: '1.0'
+ };
+ }
});
- return doc.body.innerHTML;
- },
-
- /**
- * @return {Object}
- */
- getInfo: function () {
- return {
- longname: 'Magento Widget Manager Plugin',
- author: 'Magento Core Team',
- authorurl: 'http://magentocommerce.com',
- infourl: 'http://magentocommerce.com',
- version: '1.0'
- };
- }
+ // Register plugin
+ tinymce.PluginManager.add('magentowidget', tinymce.plugins.magentowidget);
+ };
});
-
-// Register plugin
-tinymce.PluginManager.add('magentowidget', tinymce.plugins.magentowidget);
diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/tinymce4Adapter.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/tinymce4Adapter.js
index 4139b58a20aec..ef2e56b2ef66c 100644
--- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/tinymce4Adapter.js
+++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/tinymce4Adapter.js
@@ -3,18 +3,17 @@
* See COPYING.txt for license details.
*/
-/* global varienGlobalEvents, popups, tinyMceEditors, MediabrowserUtility, Base64 */
+/* global popups, tinyMceEditors, MediabrowserUtility, Base64 */
/* eslint-disable strict */
define([
'jquery',
'underscore',
'tinymce4',
+ 'mage/adminhtml/events',
'mage/translate',
'prototype',
- 'mage/adminhtml/events',
- 'jquery/ui',
- 'mage/translate'
-], function (jQuery, _, tinyMCE4, $t) {
+ 'jquery/ui'
+], function (jQuery, _, tinyMCE4, varienGlobalEvents) {
'use strict';
var tinyMce4Wysiwyg = Class.create();
@@ -67,7 +66,8 @@ define([
* Setup TinyMCE4 editor
*/
setup: function (mode) {
- var settings,
+ var deferreds = [],
+ settings,
self = this;
this.turnOff();
@@ -78,23 +78,26 @@ define([
if (this.config.plugins) {
this.config.plugins.forEach(function (plugin) {
+ var deferred;
+
self.addPluginToToolbar(plugin.name, '|');
- if (plugin.src) {
- tinyMCE4.PluginManager.load(plugin.name, plugin.src, function () {
- var pluginConstructor = tinyMCE4.plugins[plugin.name];
+ if (!plugin.src) {
+ return;
+ }
- if (!pluginConstructor) {
- throw new Error($t('Could not find plugin with name %1').replace('%1', plugin.name));
- }
+ deferred = jQuery.Deferred();
+ deferreds.push(deferred);
- pluginConstructor.config = plugin.options;
- pluginConstructor.adapter = self;
- });
- }
+ require([plugin.src], function (factoryFn) {
+ if (typeof factoryFn === 'function') {
+ factoryFn(plugin.options);
+ }
+ tinyMCE4.PluginManager.load(plugin.name, plugin.src);
+ deferred.resolve();
+ });
});
-
}
if (jQuery.isReady) {
@@ -103,8 +106,11 @@ define([
settings = this.getSettings();
settings.mode = mode;
- tinyMCE4.init(settings);
- this.getPluginButtons().hide();
+
+ jQuery.when.apply(jQuery, deferreds).done(function () {
+ tinyMCE4.init(settings);
+ this.getPluginButtons().hide();
+ }.bind(this));
},
/**
@@ -129,6 +135,32 @@ define([
this.config.tinymce4.toolbar = toolbar.join(' ');
},
+ /**
+ * Set the status of the toolbar to disabled or enabled (true for enabled, false for disabled)
+ * @param {Boolean} enabled
+ */
+ setToolbarStatus: function (enabled) {
+ var controlIds = this.get(this.getId()).theme.panel.rootControl.controlIdLookup;
+
+ _.each(controlIds, function (controlId) {
+ controlId.disabled(!enabled);
+ controlId.canFocus = enabled;
+
+ if (controlId.tooltip) {
+ controlId.tooltip().state.set('rendered', enabled);
+
+ if (enabled) {
+ jQuery(controlId.getEl()).children('button').andSelf().removeAttr('style');
+ } else {
+ jQuery(controlId.getEl()).children('button').andSelf().attr('style', 'color: inherit;' +
+ 'background-color: inherit;' +
+ 'border-color: transparent;'
+ );
+ }
+ }
+ });
+ },
+
/**
* @return {Object}
*/
@@ -136,7 +168,7 @@ define([
var settings;
settings = {
- selector: 'textarea#' + this.id,
+ selector: 'textarea#' + this.getId(),
theme: 'modern',
'entity_encoding': 'raw',
'convert_urls': false,
@@ -186,6 +218,10 @@ define([
editor.on('ExecCommand', function (cmd) {
varienGlobalEvents.fireEvent('tinymceExecCommand', cmd);
});
+
+ editor.on('init', function (args) {
+ varienGlobalEvents.fireEvent('wysiwygEditorInitialized', args.target);
+ });
}
};
@@ -243,6 +279,13 @@ define([
return tinyMCE4.get(id);
},
+ /**
+ * @return {String|null}
+ */
+ getId: function () {
+ return this.id || (this.activeEditor() ? this.activeEditor().id : null) || tinyMceEditors.values()[0].id;
+ },
+
/**
* @return {Object}
*/
@@ -278,7 +321,7 @@ define([
storeId = this.config['store_id'] !== null ? this.config['store_id'] : 0,
frameDialog = jQuery('div.mce-container[role="dialog"]'),
wUrl = this.config['files_browser_window_url'] +
- 'target_element_id/' + this.id + '/' +
+ 'target_element_id/' + this.getId() + '/' +
'store/' + storeId + '/';
this.mediaBrowserOpener = o.win;
@@ -330,14 +373,14 @@ define([
* @return {jQuery|*|HTMLElement}
*/
getToggleButton: function () {
- return $('toggle' + this.id);
+ return $('toggle' + this.getId());
},
/**
* Get plugins button.
*/
getPluginButtons: function () {
- return jQuery('#buttons' + this.id + ' > button.plugin');
+ return jQuery('#buttons' + this.getId() + ' > button.plugin');
},
/**
@@ -351,7 +394,7 @@ define([
this.getPluginButtons().hide();
- tinyMCE4.execCommand('mceAddControl', false, this.id);
+ tinyMCE4.execCommand('mceAddControl', false, this.getId());
return this;
},
@@ -373,7 +416,7 @@ define([
this.getPluginButtons().show();
- tinyMCE4.execCommand('mceRemoveEditor', false, this.id);
+ tinyMCE4.execCommand('mceRemoveEditor', false, this.getId());
return this;
},
@@ -384,14 +427,14 @@ define([
closePopups: function () {
// close all popups to avoid problems with updating parent content area
varienGlobalEvents.fireEvent('wysiwygClosePopups');
- this.closeEditorPopup('browser_window' + this.id);
+ this.closeEditorPopup('browser_window' + this.getId());
},
/**
* @return {Boolean}
*/
toggle: function () {
- if (!tinyMCE4.get(this.id)) {
+ if (!tinyMCE4.get(this.getId())) {
this.turnOn();
return true;
@@ -405,8 +448,8 @@ define([
* On form validation.
*/
onFormValidation: function () {
- if (tinyMCE4.get(this.id)) {
- $(this.id).value = tinyMCE4.get(this.id).getContent();
+ if (tinyMCE4.get(this.getId())) {
+ $(this.getId()).value = tinyMCE4.get(this.getId()).getContent();
}
},
@@ -484,7 +527,7 @@ define([
* Update text area.
*/
updateTextArea: function () {
- var editor = tinyMCE4.get(this.id),
+ var editor = tinyMCE4.get(this.getId()),
content;
if (!editor) {
@@ -497,7 +540,33 @@ define([
content = editor.getContent();
content = this.decodeContent(content);
- jQuery('#' + this.id).val(content).trigger('change');
+ this.getTextArea().val(content).trigger('change');
+ },
+
+ /**
+ * @return {Object} jQuery textarea element
+ */
+ getTextArea: function () {
+ return jQuery('#' + this.getId());
+ },
+
+ /**
+ * Set the status of the editor and toolbar
+ *
+ * @param {Boolean} enabled
+ */
+ setEnabledStatus: function (enabled) {
+ if (this.activeEditor()) {
+ this.activeEditor().getBody().setAttribute('contenteditable', enabled);
+ this.activeEditor().readonly = !enabled;
+ this.setToolbarStatus(enabled);
+ }
+
+ if (enabled) {
+ this.getTextArea().removeProp('disabled');
+ } else {
+ this.getTextArea().prop('disabled', 'disabled');
+ }
},
/**
@@ -506,39 +575,43 @@ define([
* @param {String} directive
*/
makeDirectiveUrl: function (directive) {
- return this.config['directives_url'].replace('directive', 'directive/___directive/' + directive);
+ return this.config['directives_url'].replace(/directive.*/, 'directive/___directive/' + directive);
},
/**
+ * Convert {{directive}} style attributes syntax to absolute URLs
* @param {Object} content
* @return {*}
*/
encodeDirectives: function (content) {
// collect all HTML tags with attributes that contain directives
return content.gsub(/<([a-z0-9\-\_]+[^>]+?)([a-z0-9\-\_]+=".*?\{\{.+?\}\}.*?".*?)>/i, function (match) {
- var attributesString = match[2];
+ var attributesString = match[2],
+ decodedDirectiveString;
// process tag attributes string
attributesString = attributesString.gsub(/([a-z0-9\-\_]+)="(.*?)(\{\{.+?\}\})(.*?)"/i, function (m) {
- return m[1] + '="' + m[2] + this.makeDirectiveUrl(Base64.mageEncode(m[3])) + m[4] + '"';
+ decodedDirectiveString = encodeURIComponent(Base64.mageEncode(m[3].replace(/"/g, '"')));
+
+ return m[1] + '="' + m[2] + this.makeDirectiveUrl(decodedDirectiveString) + m[4] + '"';
}.bind(this));
return '<' + match[1] + attributesString + '>';
-
}.bind(this));
},
/**
+ * Convert absolute URLs to {{directive}} style attributes syntax
* @param {Object} content
* @return {*}
*/
decodeDirectives: function (content) {
// escape special chars in directives url to use it in regular expression
var url = this.makeDirectiveUrl('%directive%').replace(/([$^.?*!+:=()\[\]{}|\\])/g, '\\$1'),
- reg = new RegExp(url.replace('%directive%', '([a-zA-Z0-9,_-]+)'));
+ reg = new RegExp(url.replace('%directive%', '([a-zA-Z0-9%,_-]+)\/?'));
return content.gsub(reg, function (match) { //eslint-disable-line no-extra-bind
- return Base64.mageDecode(match[1]);
+ return Base64.mageDecode(decodeURIComponent(match[1])).replace(/"/g, '"');
});
},
diff --git a/lib/web/mage/backend/suggest.js b/lib/web/mage/backend/suggest.js
index 81bde35f9e12a..412a80804ae0f 100644
--- a/lib/web/mage/backend/suggest.js
+++ b/lib/web/mage/backend/suggest.js
@@ -245,6 +245,7 @@
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
+ this._toggleEnter(event);
if (this.isDropdownShown() && this._focused) {
this._proxyEvents(event);
@@ -314,6 +315,30 @@
this._bindDropdown();
},
+ /**
+ * @param {Object} event - event object
+ * @private
+ */
+ _toggleEnter: function (event) {
+ var suggestList,
+ activeItems,
+ selectedItem;
+
+ suggestList = $(event.currentTarget.parentNode).find('ul').first();
+ activeItems = suggestList.find('._active');
+
+ if (activeItems.length >= 0) {
+ selectedItem = activeItems.first();
+
+ if (selectedItem.find('a') && selectedItem.find('a').attr('href') !== undefined) {
+ window.location = selectedItem.find('a').attr('href');
+ event.preventDefault();
+
+ return false;
+ }
+ }
+ },
+
/**
* @param {Object} e - event object
* @private
diff --git a/lib/web/mage/collapsible.js b/lib/web/mage/collapsible.js
index 0d8cf836c198e..267734605f141 100644
--- a/lib/web/mage/collapsible.js
+++ b/lib/web/mage/collapsible.js
@@ -243,7 +243,7 @@ define([
});
// For collapsible widget only (not tabs or accordion)
- if (this.header.parent().attr('role') != 'presentation') { //eslint-disable-line eqeqeq
+ if (this.header.parent().attr('role') !== 'presentation') {
this.header
.parent()
.attr('role', 'tablist');
@@ -316,9 +316,9 @@ define([
* Disable.
*/
disable: function () {
+ this.options.disabled = true;
this._off(this.trigger);
this.forceDeactivate();
- this.options.disabled = true;
if (this.options.disabledState) {
this.element.addClass(this.options.disabledState);
@@ -330,12 +330,14 @@ define([
* Enable.
*/
enable: function () {
- this._on(this.trigger, this.events);
this.options.disabled = false;
+ this._on(this.trigger, this.events);
+ this.forceActivate();
if (this.options.disabledState) {
this.element.removeClass(this.options.disabledState);
}
+ this.trigger.attr('tabIndex', 0);
},
/**
@@ -517,7 +519,7 @@ define([
that = this;
if (url) {
- this.xhr = $.get({
+ that.xhr = $.get({
url: url,
dataType: 'html'
}, function () {
@@ -533,7 +535,8 @@ define([
setTimeout(function () {
that.content.html(response);
}, 1);
- }).complete(function (jqXHR, status) {
+ });
+ that.xhr.complete(function (jqXHR, status) {
setTimeout(function () {
if (status === 'abort') {
that.content.stop(false, true);
diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js
index a59ebbaf8badc..834981402f67f 100644
--- a/lib/web/mage/menu.js
+++ b/lib/web/mage/menu.js
@@ -21,6 +21,7 @@ define([
expanded: false,
showDelay: 42,
hideDelay: 300,
+ delay: 300,
mediaBreakpoint: '(max-width: 768px)'
},
@@ -30,6 +31,8 @@ define([
_create: function () {
var self = this;
+ this.delay = this.options.delay;
+
this._super();
$(window).on('resize', function () {
self.element.find('.submenu-reverse').removeClass('submenu-reverse');
@@ -586,7 +589,7 @@ define([
html.removeClass('nav-open');
setTimeout(function () {
html.removeClass('nav-before-open');
- }, 300);
+ }, this.options.hideDelay);
}
},
diff --git a/lib/web/mage/validation.js b/lib/web/mage/validation.js
index aaece677a485d..7dee441b2a078 100644
--- a/lib/web/mage/validation.js
+++ b/lib/web/mage/validation.js
@@ -395,6 +395,24 @@
$.mage.__('Please enter at least {0} characters')
],
+ /* detect chars that would require more than 3 bytes */
+ 'validate-no-utf8mb4-characters': [
+ function (value) {
+ var validator = this,
+ message = $.mage.__('Please remove invalid characters: {0}.'),
+ matches = value.match(/(?:[\uD800-\uDBFF][\uDC00-\uDFFF])/g),
+ result = matches === null;
+
+ if (!result) {
+ validator.charErrorMessage = message.replace('{0}', matches.join());
+ }
+
+ return result;
+ }, function () {
+ return this.charErrorMessage;
+ }
+ ],
+
/* eslint-disable max-len */
'email2': [
function (value, element) {
@@ -826,11 +844,13 @@
result = true;
range = param;
- if (typeof range === 'object') {
+ if (typeof range === 'string') {
m = dataAttrRange.exec(range);
if (m) {
result = result && $.mage.isBetween(numValue, m[1], m[2]);
+ } else {
+ result = false;
}
} else if (elm && elm.className) {
classes = elm.className.split(' ');
@@ -877,11 +897,13 @@
result = true;
range = param;
- if (typeof range === 'object') {
+ if (typeof range === 'string') {
m = dataAttrRange.exec(range);
if (m) {
result = result && $.mage.isBetween(numValue, m[1], m[2]);
+ } else {
+ result = false;
}
} else if (elm && elm.className) {
classes = elm.className.split(' ');
diff --git a/nginx.conf.sample b/nginx.conf.sample
index 58c059657c070..1e20a51a511d3 100644
--- a/nginx.conf.sample
+++ b/nginx.conf.sample
@@ -100,7 +100,7 @@ location /static/ {
# Remove signature of the static files that is used to overcome the browser cache
location ~ ^/static/version {
- rewrite ^/static/(version\d*/)?(.*)$ /static/$2 last;
+ rewrite ^/static/(version[^/]+/)?(.*)$ /static/$2 last;
}
location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ {
@@ -162,7 +162,7 @@ location /media/import/ {
}
# PHP entry point for main application
-location ~ (index|get|static|report|404|503)\.php$ {
+location ~ (index|get|static|report|404|503|health_check)\.php$ {
try_files $uri =404;
fastcgi_pass fastcgi_backend;
fastcgi_buffers 1024 4k;
diff --git a/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php b/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php
index 940bcbbd6d7f1..4ad8e7c229bfd 100644
--- a/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php
@@ -6,13 +6,14 @@
namespace Magento\Setup\Console\Command;
-use Magento\Setup\Model\AdminAccount;
use Magento\Framework\Setup\ConsoleLogger;
+use Magento\Setup\Model\AdminAccount;
use Magento\Setup\Model\InstallerFactory;
use Magento\User\Model\UserValidationRules;
-use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\Question;
class AdminUserCreateCommand extends AbstractSetupCommand
{
@@ -50,6 +51,98 @@ protected function configure()
parent::configure();
}
+ /**
+ * @param \Symfony\Component\Console\Input\InputInterface $input
+ * @param \Symfony\Component\Console\Output\OutputInterface $output
+ *
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ */
+ protected function interact(InputInterface $input, OutputInterface $output)
+ {
+ /** @var \Symfony\Component\Console\Helper\QuestionHelper $questionHelper */
+ $questionHelper = $this->getHelper('question');
+
+ if (!$input->getOption(AdminAccount::KEY_USER)) {
+ $question = new Question('
- Our PHP extension help can get you started.
+ Our PHP extension help can get you started.
- For help, see our File Permission Help or call your hosting provider.
+ For help, see our File Permission Help or call your hosting provider.